SVGでやることのまとめ。

SVGは、Webサイトの中では、アイコンロゴシンプルなイラストに使われている、拡大してもずっと綺麗な画像ファイルです。画像フォーマットでありながら、XMLに基づくマークアップ言語でもあるので、テキストエディタで編集できてしまえるのも魅力。しかもずっと綺麗なんです。
そんなSVGファイルを作るときに僕がよくやることをちょこちょこまとめてゆきます:)

書き出しはイラレから

XMLに基づくマークアップ言語とはいえ、複雑な図形やイラストは、人力では到底マークアップできません…X‹
図形やイラストはAdobe Illustrator(以下、イラレ)で制作して、そのままイラレから、SVGファイルとして書き出すことが常です。
ここでは、このサイトの左上にいるパンちゃんアイコンを書き出してみます:)

イラレのデータを用意

まずは何はなくともaiデータを用意しなくちゃいけません。
「新規...+N」で、「Web」のタブから適当なドキュメントプリセットを選んで、幅と高さを100 pxにして作成します。

イラレで作ったアートワーク(ここではパンちゃんアイコン)を、おもむろにコピペ。
アートボードツールで、アイコン部分をクリックすると、そのオブジェクトサイズぴったしのアートボードが作成されます:)
最初にあったアートボード(01 - アートボード 1)は削除して、パンちゃんアイコンのアートボードだけにしておきます。

アートボードを選択した状態でreturnキーを押下すると「アートボードオプション」パネルが開きます。
ここで、アートボードの名前の変更と、アートボードの幅と高さ整数になるように調整します。ここでは名前を「pan」にして、高さが「36.7073 px」だったのを「37 px」に整えました。

整列ツールで、アイコンをアートボードの中央に揃えたらば、aiファイルを一旦「保存+S」。ここでは「pan.ai」というファイル名で保存しました。

SVGファイルとして書き出す

アートボードが用意できたら、「スクリーン用に書き出し...+option+E」で、SVGファイルを書き出します。書き出す対象の「アートボード」を選択して、書き出し先の「フォルダー」と、書き出すファイルの「フォーマット」を指定します。JPG/PNG/SVG/PDFをいっぺんに書き出せたり、画像の拡大率とか、サフィックス(接尾辞)を指定できたり、いろんな機能がありますけれど、今回はSVG一択。

「スクリーン用に書き出し」パネル
  1. アートボードごとに書き出す方法と、アセットに登録したオブジェクトを書き出す方法がありますが、ここでは「アートボード」を選択。
  2. 書き出したいアートボードにチェック。(チェックすると右の「選択」の欄に範囲が反映される)
    「裁ち落としを含める※1」は、チェックしてもしなくてもどちらでも良いです。
  3. 書き出し先」に、SVGファイルを書き出す場所を指定します。デフォルトで、現在開いているaiファイルがあるディレクトリが選択されてるので、そのままで大丈夫。
    「書き出し後に場所を開く※2」は、すでに開いてるのでチェックしなくて大丈夫。
    「サブフォルダーを作成※3」も、今回はフォーマットがSVGのみなので、チェックを外しておきます。
  • 裁ち落としとは、印刷物のデータにある、アートボードの周りを囲う赤枠(塗り足し領域)のこと。「裁ち落としを含める」とは、塗り足し部分も含めて書き出すという意味。新規作成時に、「Web」のプリセットを選んでいる場合には、裁ち落としサイズが「0px」になっているので、気にしなくて大丈夫:)
    裁ち落としのサイズは、メニュー「ファイル > ドキュメント設定...」の「全般」の項目で設定できる。
  • チェックすると、書き出した後に「書き出し先の場所フォルダ」が開かれる。
  • いろんなフォーマット(形式・拡大・縮小率)で書き出す場合に、ここにチェックしておくと、フォーマットごとにフォルダーが作られて、その中に画像が書き出されるようになる。
「形式の設定」パネル
  1. 「フォーマット」の欄の右端にあるはぐるまアイコンをクリックして「形式の設定」パネルを開いたらば、「SVG」の書き出し設定を変更します。
    「スタイル」を「内部 CSS」、「フォント」を「アウトラインに変換」、「画像」を「埋め込む」、「オブジェクト ID」を「レイヤー名」、「小数点以下の桁数」を「3」に、それぞれ設定し「設定を保存」しておきます。詳しくは後述
  2. 「形式」はもちろん「SVG」を選択。したら「アートボードを書き出し」をクリックです;)

SVGファイルができましたー!
アートボード名がそのままファイル名となって書き出されます。

SVGコード

書き出したSVGファイルの中身のSVGコードはこちら。

<?xml version="1.0" encoding="UTF-8"?>
<svg id="_レイヤー_1" xmlns="http://www.w3.org/2000/svg" width="40" height="37" viewBox="0 0 40 37">
  <defs>
    <style>
      .cls-1 {
        stroke-width: .9px;
      }

      .cls-1, .cls-2, .cls-3 {
        fill: none;
        stroke: #000;
        stroke-linecap: round;
        stroke-linejoin: round;
      }

      .cls-2 {
        stroke-width: 1.2px;
      }

      .cls-3 {
        stroke-width: 1.6px;
      }
    </style>
  </defs>
  <g>
    <g>
      <path class="cls-1" d="M15.242,31.485c-.786,.73-1.58,1.244-1.58,1.244,0,0-.755-.656-1.385-1.468"/>
      <g>
        <path class="cls-1" d="M11.812,16.727c-2.323,.754-2.723,3.413-1.068,4.772"/>
        <path class="cls-1" d="M14.41,16.963c-2.364,1.069-2.461,3.882-.375,4.924"/>
        <path class="cls-1" d="M16.958,16.991c-2.002,1.09-2.002,3.903,.229,4.533"/>
      </g>
      <g>
        <path class="cls-3" d="M7.362,24.651c-.785,0-.821,1.296-.009,1.296,.731,0,.751-1.296,.009-1.296Z"/>
        <path class="cls-3" d="M19.759,24.781c-.857-.019-.867,1.375-.009,1.393,.88,.019,.89-1.374,.009-1.393Z"/>
      </g>
    </g>
    <g>
      <path class="cls-2" d="M9.018,14.374c.609-4.655-1.181-9.845-6.669-13.628C-.701,9.074,.207,14.869,5.313,19.025"/>
      <path class="cls-2" d="M23.6,18.577c-2.08,6.65-.916,13.019,5.504,15.614,2.318-6.822,1.137-13.058-4.087-18.288-6.749-6.759-19.716-3.626-20.386,6.967-.669,10.57,11.489,12.478,19.718,7.935"/>
      <path class="cls-2" d="M26.22,16.783c6.287-2.347,13.18,2.065,13.18,10.11,0,7.656-7.42,8.599-9.813,6.271"/>
      <path class="cls-2" d="M30.396,27.894c.743-1.015,2.054-1.76,3.745-1.791"/>
      <path class="cls-2" d="M7.883,31.148c-2.633,.951-2.54,4.448,1.195,4.848,2.33,.25,3.656-1.135,3.115-3.061"/>
      <path class="cls-2" d="M18.156,33.003c-.733,1.941,.548,3.573,3.346,3.196,2.829-.381,3.709-2.883,2.038-4.701"/>
    </g>
  </g>
</svg>

パッと見なにが何だかわからないですけれど、2行めのid="_レイヤー_1"というのは、きっとイラレのレイヤー名ですね。イラレでグループ化してあるところはg要素で括られてるのが分かります。
イラレのレイヤー構造と見比べてみると(下図)、なんとなくSVGの階層構造が見えてきますね…!

レイヤー構造とSVG構造の見比べ

試しにレイヤーに名前を付けてみると、SVG要素のid属性として反映されました。
「レイヤー名」が「オブジェクト ID」になってるってことですね!;)
そして、イラレはレイヤーが上に重なってゆくけれど、ソースコードは下の行に書かれた要素が上に重なってゆくから、上下の並びは逆になるわけです。

<?xml version="1.0" encoding="UTF-8"?>
<svg id="logo" xmlns="http://www.w3.org/2000/svg" width="40" height="37" viewBox="0 0 40 37">
  <defs>
    ︙
  </defs>
  <g id="pan">
    <g id="face">
      <path class="cls-1" d="M15.242,31.485c-.786,.73-1.58,1.244-1.58,1.244,0,0-.755-.656-1.385-1.468"/>
      <g id="hair">
        <path class="cls-1" d="M11.812,16.727c-2.323,.754-2.723,3.413-1.068,4.772"/>
        <path class="cls-1" d="M14.41,16.963c-2.364,1.069-2.461,3.882-.375,4.924"/>
        <path class="cls-1" d="M16.958,16.991c-2.002,1.09-2.002,3.903,.229,4.533"/>
      </g>
      <g id="eye">
        <path class="cls-3" d="M7.362,24.651c-.785,0-.821,1.296-.009,1.296,.731,0,.751-1.296,.009-1.296Z"/>
        <path class="cls-3" d="M19.759,24.781c-.857-.019-.867,1.375-.009,1.393,.88,.019,.89-1.374,.009-1.393Z"/>
      </g>
    </g>
    <g id="body">
      <path class="cls-2" d="M9.018,14.374c.609-4.655-1.181-9.845-6.669-13.628C-.701,9.074,.207,14.869,5.313,19.025"/>
      <path class="cls-2" d="M23.6,18.577c-2.08,6.65-.916,13.019,5.504,15.614,2.318-6.822,1.137-13.058-4.087-18.288-6.749-6.759-19.716-3.626-20.386,6.967-.669,10.57,11.489,12.478,19.718,7.935"/>
      <path class="cls-2" d="M26.22,16.783c6.287-2.347,13.18,2.065,13.18,10.11,0,7.656-7.42,8.599-9.813,6.271"/>
      <path class="cls-2" d="M30.396,27.894c.743-1.015,2.054-1.76,3.745-1.791"/>
      <path class="cls-2" d="M7.883,31.148c-2.633,.951-2.54,4.448,1.195,4.848,2.33,.25,3.656-1.135,3.115-3.061"/>
      <path class="cls-2" d="M18.156,33.003c-.733,1.941,.548,3.573,3.346,3.196,2.829-.381,3.709-2.883,2.038-4.701"/>
    </g>
  </g>
</svg>

書き出し形式の詳細設定

形式の設定」パネルの設定項目について詳しく見てゆきます:D

「スタイル」

SVG要素のスタイルの書き出し方法を設定します。

内部 CSS
HTMLでやるみたいに、style要素にスタイルを定義して、SVG要素にclass属性でもって、スタイルを適用します。
スタイルを一箇所で管理できるので、読みやすさを優先するなら断然「内部 CSS」がおすすめ;D
インラインスタイル
SVG要素に、直接style属性でもって、スタイルを適用します。SVG要素に逐一style属性を書き込むので、ソースコードが溢れかえりがちX(
プレゼンテーション属性
SVG要素に用意されているプレゼンテーション属性を使って、スタイルを適用します。こちらもSVG要素ごとに属性を書き込むので、ソースコードが煩雑になりがち:(

インラインスタイルのサンプルと、プレゼンテーション属性のサンプルを見比べると、CSSプロパティがそのまま、属性になってるのがわかりますね。そうつまりプレゼンテーション属性=CSSプロパティなのです:)

<path d="M15.242,31.485c-.786,.73-1.58,1.244-1.58,1.244,0,0-.755-.656-1.385-1.468" style="fill: none; stroke: #000; stroke-linecap: round; stroke-linejoin: round; stroke-width: .9px;"/>
インラインスタイル(抜粋)
<path d="M15.242,31.485c-.786,.73-1.58,1.244-1.58,1.244,0,0-.755-.656-1.385-1.468" fill="none" stroke="#000" stroke-linecap="round" stroke-linejoin="round" stroke-width=".9"/>
プレゼンテーション属性(抜粋)

「フォント」と「画像」

今回はフォントも画像も含まないので特に意識しなくても良いですけれど、主にアイコンを書き出すのに特化した設定になります。

アウトラインに変換
テキストすべてアウトラインが取られ、パスオブジェクトとして書き出されます。
SVG
テキストはtext要素で括られて、ちゃんと文字として書き出されます。文字間のカーニングが設定されているテキストは、一文字ずつtspan要素で括られ、x/y属性を駆使してカーニングを再現します。
保持
リンクで配置された画像は「リンク」で、埋め込まれた画像「埋め込む」で書き出します(それぞれ後述参照)。つまりイラレで配置している状態を保持する、ということ;)
埋め込む
イラレ内に配置された画像はすべて、「base64」にエンコードされた状態で書き出されます。
リンク
イラレ内に配置された画像は、埋め込んだ画像もすべて、リンクされた状態で書き出されます。元画像が同じフォルダ内にない場合は、埋め込まれた画像も外部ファイルとして一緒に書き出します。

base64については以下の記事が詳しいです。

base64ってなんぞ??理解のために実装してみた - Qiita

「オブジェクト ID」

SVG要素に付与されるid属性class属性の値をどうするか設定します。

レイヤー名
イラレのレイヤー名がid属性の値として使われます。class名は、cls-1とかcls-2という風に指定されます。
最小
id属性は出力されず、オブジェクトのスタイルを指定するためのclass名には、aとかbとかごく短い文字が指定されます。
固有
id属性の値もclass名も、完全ユニークな(めちゃんこ長い)名前が指定されます。

「小数点以下の桁数」

パスやアンカーポイントの位置の、小数点以下の最大桁数(1桁〜15桁くらいまで)を指定します。桁数が多いほど、描画の精度が上がります。「3」が最適とされています。

「縮小」と「レスポンシブ」

縮小
チェックすると、書き出されるSVGファイルから、余計な記述が削減され圧縮された状態で書き出されます。
チェックしなければちゃんと改行とインデントがなされた読みやすいソースコードで書き出されます。
レスポンシブ
チェックすると、svg要素にwidth属性height属性が出力されなくなります。
個人的には、width/height属性もあった方が良いのになーと思っているので、書き出すことにしてます。

SVGファイルの取り扱い

SVG画像をHTMLで表示する方法を見てゆきます。
その前に、イラレのデータから書き出したソースコードを整理整頓して、使いやすくしておきます。

自分なりに整える

無駄な属性を削除したり、余分なスタイル指定をひとまとめにしたり、スペースのインデントをタブに変えたり、いつもの自分の書式ルールに直すことで、個人的に見やすくしておきます。
※あくまで自分なりなのであしからず。

  • path要素すべてに同じclass名がついてるのは、なんだか効率が悪いので、path要素のclass属性は消しちゃって、g要素のid属性をclass属性に変えて、そのclass属性でもってスタイルを指定することにします。
  • .cls-1, .cls-2, .cls-3への指定は、つまり全部のpath要素に適用するということなので、一番上のg要素.panにまとめちゃいます。
  • よく見ると、線の太さstroke-widthの違いは、.face.eye.bodyで綺麗に分けられるので、stroke-widthの指定を、g要素のclass名を利用して割り振ります。
  • SVGのstroke-widthの値は、単位がなくても大丈夫なので、端折ハショります。
  • 線の色を黒から、Lopanの紫に変えます。

てなもんで、こんな感じになりました!

<?xml version="1.0" encoding="UTF-8"?>
<svg id="logo" xmlns="http://www.w3.org/2000/svg" width="40" height="37" viewBox="0 0 40 37">
	<defs>
		<style>
			.pan {
				fill: none;
				stroke: #553968;
				stroke-width: .9;
				stroke-linecap: round;
				stroke-linejoin: round;
			}
			.body { stroke-width: 1.2; }
			.eye { stroke-width: 1.6; }
		</style>
	</defs>
	<g class="pan">
		<g class="face">
			<path d="M15.242,31.485c-.786,.73-1.58,1.244-1.58,1.244,0,0-.755-.656-1.385-1.468"/>
			<g class="hair">
				<path d="M11.812,16.727c-2.323,.754-2.723,3.413-1.068,4.772"/>
				<path d="M14.41,16.963c-2.364,1.069-2.461,3.882-.375,4.924"/>
				<path d="M16.958,16.991c-2.002,1.09-2.002,3.903,.229,4.533"/>
			</g>
			<g class="eye">
				<path d="M7.362,24.651c-.785,0-.821,1.296-.009,1.296,.731,0,.751-1.296,.009-1.296Z"/>
				<path d="M19.759,24.781c-.857-.019-.867,1.375-.009,1.393,.88,.019,.89-1.374,.009-1.393Z"/>
			</g>
		</g>
		<g class="body">
			<path d="M9.018,14.374c.609-4.655-1.181-9.845-6.669-13.628C-.701,9.074,.207,14.869,5.313,19.025"/>
			<path d="M23.6,18.577c-2.08,6.65-.916,13.019,5.504,15.614,2.318-6.822,1.137-13.058-4.087-18.288-6.749-6.759-19.716-3.626-20.386,6.967-.669,10.57,11.489,12.478,19.718,7.935"/>
			<path d="M26.22,16.783c6.287-2.347,13.18,2.065,13.18,10.11,0,7.656-7.42,8.599-9.813,6.271"/>
			<path d="M30.396,27.894c.743-1.015,2.054-1.76,3.745-1.791"/>
			<path d="M7.883,31.148c-2.633,.951-2.54,4.448,1.195,4.848,2.33,.25,3.656-1.135,3.115-3.061"/>
			<path d="M18.156,33.003c-.733,1.941,.548,3.573,3.346,3.196,2.829-.381,3.709-2.883,2.038-4.701"/>
		</g>
	</g>
</svg>

HTMLに表示する方法

SVGファイルをHTMLに表示する方法は以下の4種類。
最初のふたつは、SVGファイルを画像ファイルとして、他のフォーマットの画像(jpgとかpngとか)と同じように配置する方法。もうふたつは、XMLに基づくマークアップ言語ならではの方法で、HTMLに直接SVGコードを記述する方法です。

img/object要素で設置する

img要素なら<img src="pan.svg">、object要素なら<object data="pan.svg"></object>と記述するだけ、いちばん簡単な表示方法です:)
ただ、ダークモード用に白いパンちゃんアイコンも欲しいなって時には、別途、白いパンちゃんのSVGファイルも用意しないといけません。

<img src="img/pan.svg" alt="パンちゃん" width="40" height="37">
<img src="img/pan_white.svg" alt="白いパンちゃん" width="40" height="37">

data属性があればtype属性は記述する必要はありませんが、記述する場合type="image/svg+xml"と記述します。

背景画像として表示する

画像なので、もちろんCSSの背景画像としても表示できます。下サンプルは、ひとつめがdiv要素に背景画像を表示するタイプ、ふたつめがp要素擬似要素に対して背景画像を指定するタイプ。
ここでも、白いパンちゃんには「pan_white.svg」を用意しています。

svg要素を直接書き込む

HTML内に直接、svg要素まるごと書き込みます。まるごとと言っても、HTMLの中にsvg要素を書く時には、名前空間宣言xmlns="http://www.w3.org/2000/svg"の記述は要らないし、style要素は別途HTML側へ移動します。
下のサンプルでは、svg要素内のstyle要素をそっくりそのまま、HTMLのhead要素へ移動しています。
この方法ならば、画像ファイルはひとつも要らないし、CSSでstrokeプロパティの値を変えるだけでどんな色のパンちゃんも表示できちゃいます:D。ただ、ソースコードが長ーくなってしまうのが玉にきずX‹

use要素で設置する

use要素を使って、外部SVGファイルのソースコードを読み込む方法です。
svg要素の中にuse要素を置いて、href属性SVGファイルまでの場所パスと、SVGファイル内の使いたい要素のidを続けて指定します。ここでは、「pan.svg」のsvg要素に付けているid属性の#logoを使って、下記のように指定します。

<svg width="68" height="63" viewBox="0 0 40 37"><use href="pan.svg#logo" stroke="#553968"/></svg>

これで、svg要素の中に「pan.svg」のソースコードが読み込まれる手筈なのですけれど、パンちゃん真っ黒ですね…Xᗡ

実は、use要素で読み込むのは描画可能要素だけで、<style>の中身は読み込まれないから、スタイルが反映されないんです。なので「svg要素を直接書き込む」のと同じ要領で、別途スタイルを定義しないといけません。

描画可能要素についてはこちらを参照のこと。
SVG 要素リファレンス - SVG: スケーラブルベクターグラフィック | MDN

とはいえ、use要素を通して、SVGファイル内のパーツ要素に細かくスタイルを指定することはできないですもんね…。

<svg width="68" height="63" viewBox="0 0 40 37"><use href="pan.svg#logo" style="fill:none;stroke:#553968;stroke-width:.9;stroke-linecap:round;stroke-linejoin:round;"></use></svg>

上記のようにuse要素にstyle属性でスタイルを指定しても、線の太さがぜんぶ同じになっちゃいます…。

なので、SVGファイル内の描画可能要素に直接スタイルを指定しておくことにします。表示する時に変えたいのは線の色だけなので、stroke以外のスタイルを指定します。

<g class="pan" style="fill:none;stroke-width:.9;stroke-linecap:round;stroke-linejoin:round">
  ︙
</g>
こんな感じ(詳しくは下サンプルの「SVG」ソースコードを参照のこと)

HTML側では、以下のようにstrokeの色だけ指定すれば良いことになりますね!

<svg width="68" height="63" viewBox="0 0 40 37"><use href="pan.svg#logo" stroke="#553968"></use></svg>

はたまた、CSSで定義しておいても良いかもしれません。(下のサンプルではCSSで定義しています。)
できました!

あとがき

SVGファイルは画像ファイルでありながら、ソースコードを編集して、あとから色だけ変えたり、線の太さを調整できるのが良いところ。しかも綺麗ですし。
そうして、自分の使いやすいようにカスタムされたSVGファイルは、Webサイト内で便利に使い回せるようになるってわけです;)

てなもんで、以上、SVGファイルを作るときにやることでした。
最後まで読んでいただきありがとうございました!

使いまわせるSVG