【SVG】pathタグの使い方|d属性、M, L, H, V, Z, C, S, Q, T, Aコマンド、gタグとは何かを実例で解説

html-kv-prograshi(プロぐらし)-kv HTML
記事内に広告が含まれていることがあります。

SVGタグの中で使うpathタグは、ウェブサイトやアプリケーションで柔軟なグラフィックを描画するために欠かせない要素です。

pathタグは複雑な図形を自由度高く描ける反面、指定できるコマンドがたくさんあり、パッと見だととっつきにくく感じてしまいます。

ですが、一つ一つ分解してみるととてもわかりやすい規則性を持っています。

この記事では、SVGのpathタグを使いこなすために、d属性の基本的な考え方から、代表的なコマンドを1つ1つ分かりやすい実例とともに解説しています。


なお、SVGタグの基本的な使い方や、circle, rect, line, polygon, polyline, ellipseなどの他のタグについては下記をご参考ください。


pathタグとは何か?

冒頭でも書きましたが、pathタグはSVGタグの中で使い自由な描画をするためのタグです。

例えるなら「1本でなんでも描ける」万能ペンで、直線だけでなく、曲線や複雑な図形も、すべて表現できます。(SVGの中で最も強力)

d属性に書くコマンド(命令)で描きます。例えば、以下のコードで三角形が描けます。

<svg width="160" height="120" viewBox="0 0 160 120">
  <path d="M10 100 L80 20 L150 100 Z"
        fill="#ffd54f" stroke="#333" stroke-width="2"/>
</svg>

使い方は少し複雑ですが、慣れると非常に便利です。


なお、pathでメインとなるd属性以外の属性は、stroke, storoke-width, fill など他のタグと同様です。

d属性とは?

d属性の「d」は「data」の略で、描画用のコマンドと座標の組み合わせで、図形を定義します


d属性の主なコマンド

pathタグを理解する上で絶対に欠かせないのがd属性と、その中の記述方法(コマンド/命令)です。

d属性で使えるコマンドには以下のようなものがあります。

pathタグの主な属性
  • M: Move to(移動)
    ペンを上げて、指定した座標まで移動します。パスの開始点に必須です。
    【使い方:M x y】(※xとyはx座標とy座標)
  • L: Line to(直線)
    現在の位置から指定した座標まで直線を引きます。
    【使い方:L x y】
  • H: Horizontal line to(水平線)
    現在のy座標を維持したまま、指定したx座標まで水平線を引きます。
    【使い方:H x】
  • V: Vertical line to(垂直線)
    現在のx座標を維持したまま、指定したy座標まで垂直線を引きます。
    【使い方:V y】
  • Z: Close path(パスを閉じる)
    現在の位置からパスの開始点まで直線を引いて、パスを閉じます。
    ※Zがない場合、最後の線と最初の点を結びません。
  • C: Curve to (三次ベジェ曲線)
    現在の位置から指定した座標まで、2つの制御点を使って滑らかな曲線を引きます。複雑な曲線を表現するのに使います。
    【使い方:C x1 y1, x2 y2, x y】
    • x1 y1: 1つ目の制御点の座標
    • x2 y2: 2つ目の制御点の座標
    • x y: 曲線の終点の座標
  • S: Smooth curve to (滑らかな三次ベジェ曲線)
    Cコマンドのショートハンド版です。Cの曲線の2つ目の制御点を自動的に対称に配置することで、滑らかな曲線を連続して描きます。
    【使い方:S x2 y2, x y】
    • x2 y2: 2つ目の制御点の座標
    • x y: 曲線の終点の座標
  • Q: Quadratic Bézier curve (二次ベジェ曲線)
    現在の位置から指定した座標まで、1つの制御点を使って曲線を引きます。Cコマンドよりもシンプルで、制御点が1つだけなので扱いやすいのが特徴です。
    【使い方:Q x1 y1, x y
    • x1 y1: 制御点の座標
    • x y: 曲線の終点の座標
  • T: Smooth quadratic Bézier curve (滑らかな二次ベジェ曲線)
    Qコマンドのショートハンド版です。Sと同様、前回の制御点を自動的に対称に配置することで、滑らかな曲線が連続して描けるようにします。
    【使い方:T x y
  • A: Arc to (円弧)
    現在の位置から指定した座標まで、楕円の一部を切り取った円弧を描きます。楕円の半径や回転角度、円弧の向きなどを細かく指定できます。
    【使い方:A rx ry x-axis-rotation large-arc-flag sweep-flag x y
    • rx ry: 円弧を形成する楕円の半径
    • x-axis-rotation: 楕円のx軸の回転角度
    • large-arc-flag: 0または1。円弧が180度以上か、それ未満かを指定
    • sweep-flag: 0または1。円弧を時計回りか、反時計回りかを指定
    • x y: 円弧の終点の座標


大文字と小文字

d属性のコマンドには「大文字」と「小文字」があります。(例:「L 10 0」と「l 10 0」は違います )

d属性のコマンドの大文字と小文字による違い
  • 大文字コマンド: 絶対座標(Absolute)
    • SVGビューポートの左上隅((0, 0))を基準とした座標です。
    • どの位置からコマンドを実行しても、指定した絶対座標に移動・描画されます。
  • 小文字コマンド: 相対座標(Relative)
    • 現在の描画位置(直前のコマンドの終点)を基準とした座標です。
    • 指定した値は、現在の位置からの移動量として解釈されます。


詳細については下記記事をご参考ください。

なお、Mは大文字(絶対座標)のみです。また、大文字と小文字を混ぜてpathを描くことも可能です。


Mの後にアルファベットがなく座標が続く場合

pathタグでは、Mの後にアルファベットがなく座標が続く場合があります。

この場合2点目以降は暗黙的にLコマンドが指定された状態になるため、自動的に直線で結ばれます。

例えば、以下のように「M20 90」の後ろに「70 40」「120 90」を記述した場合、それぞれの絶対座標を直線で結んだ三角形ができます。

<svg width="260" height="100" viewBox="0 0 260 120">
  <path d="M20 90 70 40 120 90 Z"
        fill="lightpink" stroke="#222" stroke-width="2"/>
</svg>


これは、「Lコマンド」で記述した場合と同じです。

<svg width="260" height="100" viewBox="0 0 260 120">
  <path d="M20 90 L70 40 L120 90 Z"
        fill="lightpink" stroke="#222" stroke-width="2"/>
</svg>


Zのあり/なしによる違い

Zコマンドは、パスの最後の点から、最初のMコマンドで指定した点まで、直線を引いてパスを閉じます

Zのありなしによらず、fillによる塗りつぶしは行われます。

しかし、Zがない場合は最期の外線がなくなります


Zありの例

<svg width="150" height="150" style="border: 1px solid #ccc;">
  <path d="M 20 20 L 120 20 L 70 100 Z" 
        stroke="red" stroke-width="3" fill="lightblue" />
</svg>

Zなしの例

<svg width="150" height="150" style="border: 1px solid #ccc;">
  <path d="M 20 20 L 120 20 L 70 100" 
        stroke="red" stroke-width="3" fill="lightblue" />
</svg>

なお、Zなしでもfill属性は有効なため、図形の内側は最後の点(70, 100)と最初の点(20, 20)を結んだ仮想的な線で囲まれた領域が塗りつぶされます



Zは閉じた図形を明示するための記号でもある

なお、Zは見た目の違い(線の有無)だけでなく、パスが「閉じた図形」であることを明示する役割を持っています。

塗りつぶしたい図形を完璧に表現するには、Zコマンドでパスを閉じるのが基本です。




実例:直線を描く(L、V、H、Zコマンド)

pathタグのM、L、V、Hコマンドを使った例として、簡単な家の図形を描くことができます。

<svg width="260" height="140" viewBox="0 0 260 120">
  <path d="
    M20 90 L70 40 L120 90 Z
    M35 90 V120 H105 V90 Z
  " fill="#bbdefb" stroke="#0d47a1" stroke-width="2"/>
</svg>  

「M20 90 L70 40 L120 90 Z」の解説

d=M20 90 L70 40 L120 90 Zは、ビューポートの左上から(20 90)の座標を開始点Mとして、Lで(70, 40)の座標と直線を結びます。

3つめの点(120, 90)とも線をむずび、最後にZで3つ目の点と開始点を結んだ三角形を描きます。


「M35 90 V120 H105 V90 Z」の解説

d=M35 90 V120 H105 V90 Zは、ビューポートの左上から(35 90)の座標を開始点Mとして、V120で垂直方向(x座標は固定)のy座標120の位置に点を打ちます。

H105は水平方向(y座標は固定)のx座標105の位置に点を打ちます。

V90で垂直方向(x座標は固定)のy座標90の位置に点を打ち、開始点と結ぶことで長方形を描きます。


実例:曲線を描く(3次ベジェ曲線 C,S)

CとSコマンドを使うと曲線を描くことができます。

<svg width="320" height="140" viewBox="0 0 320 140">
  <path d="
    M10 70
    C 50 10, 110 10, 150 70
    S 250 130, 310 70
  " fill="none" stroke="#009688" stroke-width="4"/>
</svg>


C: Curve to (三次ベジェ曲線)

Cコマンドは現在の位置から指定した座標まで、2つの制御点を使って滑らかな曲線を引きます。
【使い方:C x1 y1, x2 y2, x y】

  • x1 y1: 1つ目の制御点の座標
  • x2 y2: 2つ目の制御点の座標
  • x y: 曲線の終点の座標

なお、Cだけの場合は以下のようになります。

<svg width="320" height="140" viewBox="0 0 320 140">
  <path d="
    M10 70
    C 50 10, 110 10, 150 70
  " fill="none" stroke="#009688" stroke-width="4"/>
</svg>


S: Smooth curve to (滑らかな三次ベジェ曲線)

Cコマンドのショートハンド版です。Sは直前のCまたはSコマンドの終端接線を自動的に継承します。最初の制御点を省略でき、自然にスムーズにつなげることができます。
【使い方:S x2 y2, x y】

  • x2 y2: 2つ目の制御点の座標
  • x y: 曲線の終点の座標

なおSだけの場合は以下のようになります。

<svg width="320" height="140" viewBox="0 0 320 140">
  <path d="
    M10 70
    S 250 130, 310 70
  " fill="none" stroke="#009688" stroke-width="4"/>
</svg>


3次ベジェ曲線とは何か?

3次ベジェ曲線とは、2つの端点と2つの制御点を使って描かれる、滑らかな曲線です。

制御点は曲線自体の上にはありませんが、磁石のように曲線を引っ張り、その形状を決定します。端点から制御点への線の向きと長さが、曲線の開始と終了の「滑らかさ」を調整します。

これにより、複雑で自由な曲線デザインを少ない情報で効率的に表現することができます。



実例:曲線を描く(2次ベジェ曲線 Q,T)

QやTコマンドを使っても曲線を描くことができます。

<svg width="220" height="120" viewBox="0 0 220 120">
  <path d="
    M20 30
    Q 20 10, 60 10
    T 100 30
    T 140 50
    T 180 70
  " fill="none" stroke="#9c27b0" stroke-width="3"/>
</svg>

Q: Quadratic Bézier curve (二次ベジェ曲線)

現在の位置から指定した座標まで、1つの制御点を使って曲線を引きます。Cコマンドよりもシンプルで、制御点が1つだけなので扱いやすいのが特徴です。
【使い方:Q x1 y1, x y

  • x1 y1: 制御点の座標
  • x y: 曲線の終点の座標

Qだけの場合は以下のような曲線になります。

<svg width="220" height="120" viewBox="0 0 220 120">
  <path d="
    M20 30
    Q 20 10, 60 10
  " fill="none" stroke="#9c27b0" stroke-width="3"/>
</svg>


T: Smooth quadratic Bézier curve (二次ベジェ曲線)

Qコマンドのショートハンド版です。Sと同様、前回の制御点を自動的に対称に配置することで、滑らかな曲線が連続して描けるようにします。(Qの次にTを使うと、制御点が自動反転して連続曲線が簡単に作れます)
【使い方:T x y

Tだけの場合以下のようになります。

<svg width="220" height="120" viewBox="0 0 220 120">
  <path d="
    M20 30 
    T 100 30
    T 140 50
    T 180 70
  " fill="none" stroke="#9c27b0" stroke-width="3"/>
</svg>


2次ベジェ曲線とは?(3次ベジェ曲線との違い)

2次ベジェ曲線は、2つの端点と1つの制御点を使って描かれる曲線です。

3次ベジェ曲線が2つの制御点を使うのに対し、2次ベジェ曲線は制御点が1つなので、よりシンプルで直感的に曲線の形を調整できます。

3次ベジェ曲線の方がより複雑で自由なカーブを表現できますが、2次ベジェ曲線はシンプルさから、比較的緩やかな曲線を描くのに適しています。


実例:円弧を描く(A)

Aコマンドを使うと、円弧を描くことができます。

<svg width="260" height="160" viewBox="0 0 260 160">
  <path d="M40 90 A60 60 0 0 0 160 90"
        fill="none" stroke="#ff9800" stroke-width="10" stroke-linecap="round"/>
</svg>

A: Arc to (円弧)
現在の位置から指定した座標まで、楕円の一部を切り取った円弧を描きます。楕円の半径や回転角度、円弧の向きなどを細かく指定できます。
【使い方:A rx ry x-axis-rotation large-arc-flag sweep-flag x y

  • rx ry: 円弧を形成する楕円の半径
  • x-axis-rotation: 楕円のx軸の回転角度
  • large-arc-flag: 0または1。円弧が180度以上か、それ未満かを指定
  • sweep-flag: 0または1。円弧を時計回りか、反時計回りかを指定
  • x y: 円弧の終点の座標


gタグでグループ化する

gタグとは何か?

実際に、pathタグで描画を行う際は、gタグの中で使うことが多いです。

gタグは「グループ(gloup)」の略で、複数のSVG要素(path,circle, rectなど)をひとまとめにするためのタグです。

※pathだけでなく、他のタグにも使用しますが、複数のpathタグをまとめるときに使うことが多いです。


gタグを使うメリット

gタグを使うことで図形の操作が非常に簡単になります。

  1. 一括でスタイルを適用できる
    グループ内のすべての要素に、まとめて同じスタイル(色、線の太さなど)を適用できます。
  2. 一括で変形できる: グループ全体をまとめて移動(translate)、回転(rotate)、拡大縮小(scale)できます。
  3. 構造を分かりやすくする: 複数の図形が何を表しているのか、コード上で視覚的に分かりやすくなります。


実用としては、gタグにidやclass属性を付与することで、そのグループが何を表しているのかを明確にできます。


pathタグの実用的な使い方

SVGファイルのダウンロードとその中身

pathタグは実用面では、自分でコードを編集して図形を描くということはほぼないかと思います。

それよりも無料のSVG画像をダウンロードして編集したり、イラストレーターなどで図形を描画してSVG画像としてダウンロードすることが一般的です。

例えば、無料でアイコンがダウンロードできるICOON MONOで以下のようなカメラの画像をSVG形式でダウンロードすることができます。


ダウンロードしたファイルをメモ帳などのテキストエディタで開くと以下のようになっています。

<!--?xml version="1.0" encoding="utf-8"?-->
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->

<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="width: 256px; height: 256px; opacity: 1;" xml:space="preserve">
<style type="text/css">

	.st0{fill:#4B4B4B;}

</style>
<g>
	<path class="st0" d="M256,233.109c-28.5,0-51.594,23.297-51.594,52.047c0,28.766,23.094,52.047,51.594,52.047
		s51.594-23.281,51.594-52.047C307.594,256.406,284.5,233.109,256,233.109z" style="fill: rgb(75, 75, 75);"></path>
	<path class="st0" d="M497.375,140.297c-8.984-9.094-21.641-14.813-35.453-14.813h-54.203c-4.359,0.016-8.438-2.594-10.313-6.813
		l-16.234-36.344c-8.031-18.016-25.891-29.734-45.703-29.734H176.531c-19.813,0-37.672,11.719-45.719,29.719v0.016l-16.219,36.344
		c-1.875,4.219-5.953,6.828-10.313,6.813H50.078c-13.813,0-26.484,5.719-35.484,14.813C5.594,149.359,0,162.031,0,175.828v233.25
		c0,13.797,5.594,26.469,14.594,35.531c9,9.094,21.672,14.813,35.484,14.797h225.781h186.063
		c13.813,0.016,26.469-5.703,35.453-14.797c9.031-9.063,14.625-21.734,14.625-35.531v-233.25
		C512,162.031,506.406,149.344,497.375,140.297z M473.281,409.078c0,3.313-1.281,6.125-3.375,8.281
		c-2.156,2.109-4.844,3.328-7.984,3.344H275.859H50.078c-3.156-0.016-5.859-1.234-7.984-3.344c-2.094-2.156-3.375-4.969-3.375-8.281
		v-233.25c0-3.313,1.281-6.125,3.375-8.281c2.125-2.125,4.828-3.328,7.984-3.344h54.203c19.781,0,37.656-11.734,45.688-29.766
		l16.188-36.328c1.906-4.203,5.969-6.813,10.375-6.813h158.938c4.406,0,8.469,2.609,10.359,6.797l16.219,36.359
		c8.016,18.016,25.891,29.75,45.672,29.75h54.203c3.141,0.016,5.828,1.219,7.984,3.344c2.094,2.156,3.375,4.984,3.375,8.281V409.078
		z" style="fill: rgb(75, 75, 75);"></path>
	<path class="st0" d="M256,170.938c-31.313-0.016-59.75,12.844-80.203,33.5c-20.484,20.656-33.172,49.266-33.156,80.719
		c-0.016,31.453,12.672,60.094,33.156,80.719c20.453,20.672,48.891,33.516,80.203,33.516c31.297,0,59.75-12.844,80.203-33.516
		c20.484-20.625,33.172-49.266,33.156-80.719c0.016-31.453-12.672-60.063-33.156-80.719C315.75,183.781,287.297,170.922,256,170.938
		z M315.031,344.891c-15.172,15.297-35.953,24.688-59.031,24.688c-23.094,0-43.859-9.391-59.047-24.688
		c-15.141-15.297-24.5-36.328-24.516-59.734c0.016-23.391,9.375-44.422,24.516-59.734c15.188-15.297,35.953-24.672,59.047-24.688
		c23.078,0.016,43.859,9.391,59.031,24.688c15.156,15.313,24.516,36.344,24.531,59.734
		C339.547,308.563,330.188,329.594,315.031,344.891z" style="fill: rgb(75, 75, 75);"></path>
	<rect x="392.188" y="197.656" class="st0" width="34.406" height="34.406" style="fill: rgb(75, 75, 75);"></rect>
</g>
</svg>


svgタグの中にgタグがあり、その中に3つのpathタグとrectタグがあることがわかります。


色の変更

例えば、上記のファイルではpathやrectの各タグにカラーコードが指定されています。

各要素の色はstyle="fill: rgb(75, 75, 75);"となっています。これを変更すると、パーツごとに色を変更することができます。

<!--?xml version="1.0" encoding="utf-8"?-->
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->

<svg version="1.1" id="_x32_" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="512px" height="512px" viewBox="0 0 512 512" style="width: 256px; height: 256px; opacity: 1;" xml:space="preserve">
<style type="text/css">

	.st0{fill:#4B4B4B;}

</style>
<g>
	<path class="st0" d="M256,233.109c-28.5,0-51.594,23.297-51.594,52.047c0,28.766,23.094,52.047,51.594,52.047
		s51.594-23.281,51.594-52.047C307.594,256.406,284.5,233.109,256,233.109z" style="fill: blue;"></path>
	<path class="st0" d="M497.375,140.297c-8.984-9.094-21.641-14.813-35.453-14.813h-54.203c-4.359,0.016-8.438-2.594-10.313-6.813
		l-16.234-36.344c-8.031-18.016-25.891-29.734-45.703-29.734H176.531c-19.813,0-37.672,11.719-45.719,29.719v0.016l-16.219,36.344
		c-1.875,4.219-5.953,6.828-10.313,6.813H50.078c-13.813,0-26.484,5.719-35.484,14.813C5.594,149.359,0,162.031,0,175.828v233.25
		c0,13.797,5.594,26.469,14.594,35.531c9,9.094,21.672,14.813,35.484,14.797h225.781h186.063
		c13.813,0.016,26.469-5.703,35.453-14.797c9.031-9.063,14.625-21.734,14.625-35.531v-233.25
		C512,162.031,506.406,149.344,497.375,140.297z M473.281,409.078c0,3.313-1.281,6.125-3.375,8.281
		c-2.156,2.109-4.844,3.328-7.984,3.344H275.859H50.078c-3.156-0.016-5.859-1.234-7.984-3.344c-2.094-2.156-3.375-4.969-3.375-8.281
		v-233.25c0-3.313,1.281-6.125,3.375-8.281c2.125-2.125,4.828-3.328,7.984-3.344h54.203c19.781,0,37.656-11.734,45.688-29.766
		l16.188-36.328c1.906-4.203,5.969-6.813,10.375-6.813h158.938c4.406,0,8.469,2.609,10.359,6.797l16.219,36.359
		c8.016,18.016,25.891,29.75,45.672,29.75h54.203c3.141,0.016,5.828,1.219,7.984,3.344c2.094,2.156,3.375,4.984,3.375,8.281V409.078
		z" style="fill: pink"></path>
	<path class="st0" d="M256,170.938c-31.313-0.016-59.75,12.844-80.203,33.5c-20.484,20.656-33.172,49.266-33.156,80.719
		c-0.016,31.453,12.672,60.094,33.156,80.719c20.453,20.672,48.891,33.516,80.203,33.516c31.297,0,59.75-12.844,80.203-33.516
		c20.484-20.625,33.172-49.266,33.156-80.719c0.016-31.453-12.672-60.063-33.156-80.719C315.75,183.781,287.297,170.922,256,170.938
		z M315.031,344.891c-15.172,15.297-35.953,24.688-59.031,24.688c-23.094,0-43.859-9.391-59.047-24.688
		c-15.141-15.297-24.5-36.328-24.516-59.734c0.016-23.391,9.375-44.422,24.516-59.734c15.188-15.297,35.953-24.672,59.047-24.688
		c23.078,0.016,43.859,9.391,59.031,24.688c15.156,15.313,24.516,36.344,24.531,59.734
		C339.547,308.563,330.188,329.594,315.031,344.891z" style="fill: slyblue;"></path>
	<rect x="392.188" y="197.656" class="st0" width="34.406" height="34.406" style="fill: green;"></rect>
</g>
</svg>



アニメーションで動きをつける

上記のカメラのアイコンをベースにanimationやJavaScriptを使って動きをつけることもできます。(グレーの枠をホバーするとアニメーションが開始します)

<style>
  #camera {
    background: #f0f0f0;
    padding: 30px;
    width: 256px;
    height: 256px;
    display: block;
    margin: 50px auto;
    transform-origin: center;
  }

  /* 初期状態 */
  .draw {
    fill: none;
    stroke: currentColor;
    stroke-width: 3;
    stroke-dasharray: var(--length);
    stroke-dashoffset: var(--length);
  }
  .fill-in {
    opacity: 0;
  }
  #circle {
    fill: blue;
    opacity: 0;
  }

  /* hover時アニメーション適用 */
  #camera:hover #part1 {
    animation: draw 2.5s cubic-bezier(.77,0,.18,1) forwards;
    animation-delay: 0.5s;
    color: pink;
  }
  #camera:hover #fill1 {
    animation: fillIn 0.6s ease forwards;
    animation-delay: 1s;
  }

  #camera:hover #part2 {
    animation: draw 2.5s cubic-bezier(.77,0,.18,1) forwards;
    animation-delay: 1.2s;
    color: skyblue;
  }
  #camera:hover #fill2 {
    animation: fillIn 0.6s ease forwards;
    animation-delay: 1.7s;
  }

  #camera:hover #part3 {
    animation: draw 2.5s cubic-bezier(.77,0,.18,1) forwards;
    animation-delay: 1.9s;
    color: green;
  }
  #camera:hover #fill3 {
    animation: fillIn 0.6s ease forwards;
    animation-delay: 1.4s;
  }

  #camera:hover #circle {
    animation: lensAppear 0.4s ease forwards;
    animation-delay: 2.6s;
  }

  /* レンズ登場後にカメラ拡大 */
  #camera:hover {
    animation: snap 0.5s ease;
    animation-delay: 4s;
    animation-fill-mode: forwards;
  }

  /* keyframes */
  @keyframes draw {
    to { stroke-dashoffset: 0; }
  }
  @keyframes fillIn {
    to { opacity: 1; }
  }
  @keyframes lensAppear {
    to { opacity: 1; }
  }
  @keyframes snap {
    0%   { transform: scale(1); }
    20%  { transform: scale(1.15); }
    60%  { transform: scale(0.95); }
    100% { transform: scale(1); }
  }
</style>

<svg id="camera" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
  <!-- 外枠 -->
  <path id="part1" d="M497.375,140.297c-8.984-9.094-21.641-14.813-35.453-14.813h-54.203c-4.359,0.016-8.438-2.594-10.313-6.813
    l-16.234-36.344c-8.031-18.016-25.891-29.734-45.703-29.734H176.531c-19.813,0-37.672,11.719-45.719,29.719v0.016l-16.219,36.344
    c-1.875,4.219-5.953,6.828-10.313,6.813H50.078c-13.813,0-26.484,5.719-35.484,14.813C5.594,149.359,0,162.031,0,175.828v233.25
    c0,13.797,5.594,26.469,14.594,35.531c9,9.094,21.672,14.813,35.484,14.797h225.781h186.063
    c13.813,0.016,26.469-5.703,35.453-14.797c9.031-9.063,14.625-21.734,14.625-35.531v-233.25
    C512,162.031,506.406,149.344,497.375,140.297z M473.281,409.078c0,3.313-1.281,6.125-3.375,8.281
    c-2.156,2.109-4.844,3.328-7.984,3.344H275.859H50.078c-3.156-0.016-5.859-1.234-7.984-3.344c-2.094-2.156-3.375-4.969-3.375-8.281
    v-233.25c0-3.313,1.281-6.125,3.375-8.281c2.125-2.125,4.828-3.328,7.984-3.344h54.203c19.781,0,37.656-11.734,45.688-29.766
    l16.188-36.328c1.906-4.203,5.969-6.813,10.375-6.813h158.938c4.406,0,8.469,2.609,10.359,6.797l16.219,36.359
    c8.016,18.016,25.891,29.75,45.672,29.75h54.203c3.141,0.016,5.828,1.219,7.984,3.344c2.094,2.156,3.375,4.984,3.375,8.281V409.078
    z" class="draw"></path>
  <path id="fill1" d="M497.375,140.297 ...省略なし..." fill="pink" class="fill-in"></path>

  <!-- レンズ外周 -->
  <path id="part2" d="M256,170.938c-31.313-0.016-59.75,12.844-80.203,33.5c-20.484,20.656-33.172,49.266-33.156,80.719
    c-0.016,31.453,12.672,60.094,33.156,80.719c20.453,20.672,48.891,33.516,80.203,33.516c31.297,0,59.75-12.844,80.203-33.516
    c20.484-20.625,33.172-49.266,33.156-80.719c0.016-31.453-12.672-60.063-33.156-80.719C315.75,183.781,287.297,170.922,256,170.938
    z M315.031,344.891c-15.172,15.297-35.953,24.688-59.031,24.688c-23.094,0-43.859-9.391-59.047-24.688
    c-15.141-15.297-24.5-36.328-24.516-59.734c0.016-23.391,9.375-44.422,24.516-59.734c15.188-15.297,35.953-24.672,59.047-24.688
    c23.078,0.016,43.859,9.391,59.031,24.688c15.156,15.313,24.516,36.344,24.531,59.734
    C339.547,308.563,330.188,329.594,315.031,344.891z" class="draw"></path>
  <path id="fill2" d="M256,170.938 ...省略なし..." fill="skyblue" class="fill-in"></path>

  <!-- ファインダー窓 -->
  <rect id="part3" x="392.188" y="197.656" width="34.406" height="34.406" class="draw"></rect>
  <rect id="fill3" x="392.188" y="197.656" width="34.406" height="34.406" fill="green" class="fill-in"></rect>

  <!-- 中央レンズ -->
  <path id="circle" d="M256,233.109c-28.5,0-51.594,23.297-51.594,52.047c0,28.766,23.094,52.047,51.594,52.047
    s51.594-23.281,51.594-52.047C307.594,256.406,284.5,233.109,256,233.109z"></path>
</svg>

<script>
  // 各drawパーツの長さを計算
  document.querySelectorAll('.draw').forEach(el => {
    const len = el.getTotalLength();
    el.style.setProperty('--length', len);
  });
</script>
タイトルとURLをコピーしました