FlatIsleロゴ

Flat Isle 日誌

SVG画像の作成・使用方法

2024-03-04

記事内でアイコンや簡単な図を挿入したい時、画像ファイルでは数十KByteは必要になります。
こうした画像をSVGで実装すれば容量を数KByteに抑えられ、表示の高速化も期待できます。
ここでは、SVG画像の基本的な作成・使用方法を説明します。

SVGとは

概要

「Scalable Vector Graphics」を略してSVGと呼びます。
直訳すると「拡大縮小可能なベクター画像」となり、線や円のような単純な図形で構成される画像を表現できます。
利点は、ベクター画像なのでレスポンシブ対応によって拡大縮小されても画質が劣化しない事、テキストベースなのでデータサイズが比較的小さくできる事、現行の全てのブラウザで表示できる事が挙げられます。
欠点は、 ベクター画像なので複雑な画像には向かない事ぐらいです。

下記のページが参考になります。

SVG解説ページ(MDN)
ブラウザ対応状況(Can I use)

SVGのデータ構成

データ構成

HTML(XML)形式で構成されたデータで、<svg>で囲まれた、下記のような記述で作られます。

<svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
    <g>
        <rect x="10" y="5" width="20" height="30" />
    </g>
</svg>

要素

図形

<circle cx="60" cy="15" r="10" />
中心点の座標cx,cyと半径rを指定
楕円<ellipse cx="60" cy="35" rx="20" ry="5" />
中心点cx,cyとX軸方向の半径rx、Y軸方向の半径ryを指定
長方形<rect x="10" y="5" width="20" height="30" />
始点x,yと幅、高さを指定
多角形<polygon points="40 45, 70 50, 65 80" />
各頂点の座標x yを指定。終点と始点は自動的に直線で結ばれます

直線<line x1="10" x2="40" y1="50" y2="80" stroke="black" />
始点x1、終点x2、始点y1、終点y2を指定
折れ線<polyline points="10 100, 30 85, 40 100, 60 90" stroke="blue" fill="none" />
連結された複数の直線を描きます。各頂点の座標x yを指定
パス<path d="M 20,130 Q 40,105 50,130 T 90,130" stroke="red" fill="none" />
色々な図形を作れる汎用的な要素。 詳細は後述

文字

テキスト<text x="10" y="20">Sample text</text>
始点の座標x,yを指定し、表示したい文字をタグで囲みます

グループ

<g id="gr01" stroke="orange" fill="none">
    <path d="..." />
    <path d="..." />
</g>

要素をグループ化して扱えます。
グループを複数作り、上記のようにidで区別して使うことが多いです。
グループに対して下記のスタイルを記述すると、グループ内の要素に一括して適用できます。

図形の再利用

グループ<g>タグや<defs>タグ等に付けられたIDに対して、<use>タグを使うと、同じ図形を再利用することができます。

図形の再利用<use x="0" y="0" href="#LED" />
始点の座標x,yを指定し、再利用したい図形のIDをhrefに指定

下記の例では別ファイルにある図形(IDがLED_R)を参照しています。

<use x="13" y="10" href="./eComponents.svg#LED_R" />

この時、参照される側のsvgファイルには以下のように記述してあります。

<g id="LED">
	<path d="M0.3,0.25 v-0.5 M0.65,0 h-0.1l-0.2,-0.2h0.35v0.45z" style="stroke:#d0d0d0; stroke-width:0.05; stroke-opacity:0.5; fill:#d0d0d0; fill-opacity:0.5;"/>
	<circle cx="0.5" cy="0" r="0.6" style="stroke:#ffffff; stroke-width:0.3; stroke-opacity:0.2; fill:#ffffff; fill-opacity:0.3;"/>
</g>
<g id="LED_R">
	<circle cx="0.5" cy="0" r="0.6" fill="#ff0000"/>
	<use x="0" y="0" href="#LED"/>
</g>

再利用する図形を定義するために<g>、<defs>、<symbol>がよく使われます。
それぞれ違いがあるので、目的に応じて使い分けると良いでしょう。

gタグ内に書いた図形は描画される
defsタグ内に書いた図形は描画されない
useタグを使うことで描画される
symbolタグ内に書いた図形は描画されない
useタグを使って描画する際に、viewBoxを指定できる(
座標系が新たに作られる)

useタグで呼び出す図形に対して指定できるのは表示位置の始点座標だけです。
回転などをさせたい場合は、下記のようにgタグを書き、その中にuseタグを入れます。

<g id="CC_h" transform="rotate(90)"><use x="0" y="0" href="#CC_v" /></g>

要素のスタイル

描画する線の太さや色などを指定できます。SVGの中に直接書く他、CSSに書くことができます。
よく使うものを下記に挙げます。

線のスタイル

  • 線の色
    CSSでの色の指定方法と同様に、stroke=”red” や “#FF0000″、”rgba(255,0,0,1)” と書きます。
    線無しにするには “none” を指定します。
  • 線の太さ
    stroke-width=”3″ のように数値で指定します。
    ゼロやマイナス値にすると線が描画されません。
  • 線の終端
    stroke-linecap=”round”とすると、先端が丸められます。他には”butt”(先端が無い)と”square”(線の太さの半分飛び出す)が指定できます。
  • 線の曲がり、輪郭の形状
    stroke-linejoin=”round”とすると、直角線を描いた時に角が丸められます。他には”bevel”(面取り)と”miter”(尖がりから面取りが可変)が指定できます。

塗りつぶしのスタイル

  • 塗りつぶしの色
    strokeと同様に、fill=”blue” や “#0000FF”、”rgba(0,0,255,1)” と書きます。
    “none” で塗りつぶし無し、”transparent” で透明になります。

fill の none と transparent の違いは、イベント(クリックやマウスオーバー等)が発生するかどうかです。
none ではイベントが発生しません。

  • グラデーション
    グラデーションを使うには、defsタグでグラデーションの定義をしておきます。
    線形グラデーションは linearGradient、円形グラデーションは radialGradientタグを使います。
    定義したグラデーションにはidを忘れずに付けておきましょう。
    グラデーションの方向はx1,y1、x2,y2の座標で表される直線によって制御できます。0~1、または0~100%の範囲で指定します。
    stopタグのoffsetで色の適用範囲を設定し、stop-colorで色を指定します。
    fillでグラデーションのidを参照すれば、その色で塗られます。
<defs>
  <linearGradient id="gra_sample" x1="0" y1="0" x2="1" y2="1">
    <stop offset="0%"   stop-color="#11ccff"></stop>
    <stop offset="50%"  stop-color="#ffdddd"></stop>
    <stop offset="100%" stop-color="#ffff11"></stop>
  </linearGradient>
</defs>
<circle cx="15" cy="15" r="10" style="stroke:#none; fill:url(#gra_sample)" />

パスでの線の描画

svgで多用するパス(軌跡)について、概要を説明します。

<path d="M 9,8 35,32 C 35,32 35,19 52,18 68,17 53,45 53,45 L 82,34 90,5 Z" />

d=””の中で、下記のコマンドを使ってパスを描きます。
各コマンドは大文字で書くと絶対座標で、小文字で書くと相対座標での指定になります。

相対座標で書くと、同じ図形を複数作成する場合、開始点のみを変更するだけで作成できます。

点の移動

M x,y 絶対座標x,yで指定した点を現在位置とする
m dx,dy 現在の位置から横にdx,縦にdy移動した点を現在位置とする

直線

直線L x,y線の終端の絶対座標を指定
l dx,dy線の終端を現在の位置から相対座標で指定
水平線H x現在位置から絶対座標xまでの水平線を描く
h dx現在位置から値dx移動した点までの水平線を描く
垂直線V y現在位置から絶対座標yまでの垂直線を描く
v dy現在位置から値dy移動した点までの垂直線を描く

パスを閉じる

Z または z現在位置からパスの開始位置までを直線で結び、パスを閉じる

曲線

2次ベジエ曲線(Q, q, T, t)や、3次ベジエ曲線(C, c, S, s)や、円弧(A, a)があります。
指定する引数が複雑なので、図と併せて説明します。

2次ベジエ曲線

2次ベジエ曲線は、始点・制御点1・終点を使って曲線を描きます。

Q x1,y1 x,y現在位置から絶対座標x,yで指定した終点までの曲線を描く。
制御点はx1,y1で指定する
q dx1,dy1 dx,dy現在位置から相対座標dx,dyで指定した終点までの曲線を描く。
制御点はdx1,dy1で相対的に指定する
T x,y現在位置から絶対座標x,yで指定した終点までの曲線を描く。
制御点は直前の曲線の制御点を反転させたものになる
t dx,dy現在位置から相対座標dx,dyで指定した終点までの曲線を描く。
制御点は直前の曲線の制御点を反転させたものになる
5,25 25,25 15,10
<path d="M 5,25  Q 15,10 25,25" />
<path d="M 45,25 Q 60,2  65,25" />

Mコマンドで開始点5,25が指定されています。
続くQコマンドで、制御点15,10が指定されます。
Qコマンドの2つ目の座標25,25は終点を表します。
点と制御点を結ぶ直線に引っ張られるようにして、曲線が描かれます。
制御点が点に近いと緩いカーブになり、点から離れていると、急カーブになります。

3次ベジエ曲線

3次ベジエ曲線は、始点・制御点1・制御点2・終点を使って曲線を描きます。

C x1,y1 x2,y2 x,y現在位置から絶対座標x,yで指定した終点までの曲線を描く。
x1,y1は始点側の制御点を絶対座標で指定する。x2,y2は終点側の制御点となる
c dx1,dy1 dx2,dy2 dx,dy現在位置から相対座標dx,dyで指定した終点までの曲線を描く。
dx1,dy1は始点側の制御点を相対座標で指定する。dx2,dy2は終点側の制御点となる
S x2,y2 x,y現在位置から絶対座標x,yで指定した終点までの曲線を描く。
x2,y2は終点側の制御点を絶対座標で指定する。
始点側の制御点は、直前の曲線の終点側制御点を反転させたものになる
s dx2,dy2 dx,dy現在位置から相対座標dx,dyで指定した終点までの曲線を描く。
dx2,dy2は終点側の制御点を相対座標で指定する。
始点側の制御点は、直前の曲線の終点側制御点を反転させたものになる
9,5 95,27 5,19 41,44
<path d="M 9,5 C 5,19 41,44 95,27" />

Mコマンドで開始点9,5が指定されています。
続くCコマンドで、開始点側の制御点5,19が指定されます。
開始点と制御点を結ぶ直線に引っ張られるようにして、曲線が描かれます。この直線が短いと、急カーブを描くようになります。
Cコマンドの2つ目の座標41,44は、終点側の制御点を表します。
Cコマンドの3つ目の座標95,27が終点になります。
上記の例では、終点側の制御点と終点を結ぶ直線が長いので、曲線は緩いカーブを描いています。

円弧

ベジエ曲線でも円弧は描けますが、Aコマンドのほうが正確な円弧を描けます。
また、始点と終点で描ける事もメリットです。

A rx ry 角度 大円弧フラグ 掃引フラグ x y現在位置から、絶対座標x,yで指定した終点へ円弧を描く。
x軸方向の半径rx、y軸方向の半径ry、
x軸に対する楕円の回転角度、
大円弧フラグ(0:短い方の円弧、1:長い方の円弧)、
掃引フラグ(0:反時計回り、1:時計回り)を指定する
a rx ry 角度 大円弧フラグ 掃引フラグ dx dy現在位置から、相対座標dx,dyで指定した終点へ円弧を描く。
x軸方向の半径rx、y軸方向の半径ry、
x軸に対する楕円の回転角度、
大円弧フラグ(0:短い方の円弧、1:長い方の円弧)、
掃引フラグ(0:反時計回り、1:時計回り)を指定する
5,5 15,0 30,5 40,5 60,5 70,5 回転角0度 回転角30度 回転角-30度
<g style="fill:none;stroke:#000000;stroke-width:0.5px">
	<path d="M5,5  A5,3 0   0 1 15,0" />
	<path d="M30,5 A5,3 30  0 1 40,5" />
	<path d="M60,5 A5,3 -30 0 1 70,5" />
</g>
<g style="fill:none; stroke:#999999; stroke-width:0.4px; stroke-dasharray:0.6">
	<path d="M5,5  A5,3 0   1 0 15,0" />
	<path d="M30,5 A5,3 30  1 0 40,5" />
	<path d="M60,5 A5,3 -30 1 0 70,5" />
</g>

上記の例では、
それぞれの楕円の x方向の半径は5、y方向の半径は3にしています。
左の図形は 回転角0度、中央の図形は 回転角30度、右の図形は 回転角-30度にしています。
黒い実線が 短い方の円弧(0)で、時計回り(1)を指定してあります。
灰色の点線は 長い方の円弧(1)で、反時計回り(0)を指定しています。
円弧の始点・終点の座標は同じです。

他のコマンドについては、随時追加していきます。

画像編集ソフトでSVGを作る

  1. 画像編集ソフトを用意する
    フリーソフト「Inkscape」を使います。公式ページからダウンロードできます。
    Inkscape公式ページ
  • InkscapeのY軸はHTMLと同じく、下向きが+方向になるので、おすすめです
  • デフォルトの単位がmmですが、pxに変更する必要はありません(プレーンSVG出力の際、mmに変換されます)
  • 座標は「環境設定」-「入出力」-「SVG出力」で、パスデータを「絶対座標」、「相対座標」、「最適化(混在)」に変更できます
  1. 画像データの作成
    Inkscape上で新規に画像を作成するか、下記の手順でビットマップ画像をベクター画像に変換します。
    1. 「ファイル」-「開く」 で変換したい画像を開きます。
    2. 画像をクリックして選択した状態で「パス」-「ビットマップをトレース」をクリック。
    3. 設定はお好みで変更して「適用」をクリック。
  1. SVGの保存
    「ファイル」-「名前を付けて保存」 で、種類を「プレーンSVG」にして保存します。

HTML内でSVGを表示する

タグを挿入する

HTML内でSVGを表示するには、<body>タグ内に<svg>タグを入れます。

viewBoxとwidth,heightの関係

出力したSVGファイルには、width、height、viewBox の大きさが書かれています。

<svg width="300" height="200" viewBox="0 0 300 200" ....

width、height はSVGの描画領域の幅、高さになります。
viewBoxはSVGの表示領域になります。

レスポンシブ対応する

レスポンシブ対応させるには、svgタグから width=”…” と height=”…” を削除します(viewBox=”…” は残す)。

<svg viewBox="0 0 300 200" ....

CSSで背景にSVGデータを埋め込む

CSSにSVGファイルを直接記述しても表示はできますが、SVGデータを埋め込む事もできます。
この方法はSVGで作ったアイコンや背景の表示に適しています。

当サイトでは記事の見出し(H2~H5)に、アイコンとして小さなSVG画像を表示しています。
以前はSVGファイルとして保存したものを、CSSで指定して読み込んでいたのですが、これらを今回説明する方法に置き換えてみました。

  • メリット
    個別にSVGファイルを読み込む必要がなくなるため、表示速度の改善が期待できます。
    base64の場合、さらにデータ量の削減も見込めます。
  • デメリット
    SVGデータをエンコード(base64またはパーセント)するため、可読性が下がり、SVGの修正がしづらくなります。
    base64ならデコードしないと何が書いてあるのか全く分からなくなります。
    パーセントエンコードでは記号以外はそのまま読めますが、色コード(#が%23に変換されるので見つけやすい)を変更するぐらいしかできないでしょう。
    なお、これらのデメリットは、手直しする必要がないSVG画像を利用する場合は全く問題になりません。

SVGを整形する

改行やインデント、コメントや余分な空白を消して、1行につなげた状態にします。
さらに、画像サイズを明確にするため、widthとheightを指定します。

整形前の例:

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
	<path style="fill:#784421" d="M 31,31 C 18,20 2,30 4,44 14,53 33,48 31,31 Z" />
	<path style="fill:none;stroke:#541717" d="M 29,31 C 15,28 10,37 8,40" />
	<path style="fill:#00dd00" d="M 29,33 C 32,23 31,12 31,12 V 12 C 28,10 26,9 26,2 29,4 33,7 32,12 L 32,17 C 34,13 35,12 43,12 38,16 36,15 32,18 32,23 32,29 31,32 31,33 30,33 29,33 Z" />
</svg>

整形後の例:

<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 50 50"><path style="fill:#784421" d="M31,31C18,20 2,30 4,44 14,53 33,48 31,31Z"/><path style="fill:none;stroke:#541717" d="M29,31C15,28 10,37 8,40"/><path style="fill:#00dd00" d="M29,33C32,23 31,12 31,12V12C28,10 26,9 26,2 29,4 33,7 32,12 L32,17C34,13 35,12 43,12 38,16 36,15 32,18 32,23 32,29 31,32 31,33 30,33 29,33Z"/></svg>

base64にエンコードする

base64の方が、パーセントエンコードに比べて変換後の文字列が短くなります。
下記に、簡単に変換できるツールを用意しましたので、ご活用下さい。
整形したSVGをコピーして、入力ボックスに貼り付け、「Encode」ボタンをクリックして下さい。
「Copy」ボタンで変換結果をコピーできます。



下記のページを参考にさせていただきました。
JavaScriptの文字コード・バイト配列絡みの忘却録

CSSに記述する

エンコードしたSVGデータをコピーし、CSSに貼り付けます。

アイコン表示例:

.my-icon {
	background: url(data:image/svg+xml;base64,この部分にbase64エンコード結果を貼り付け) no-repeat;
}

SVGのアニメーション(次回)

長くなるので後日、別記事にまとめます。