スキップしてメイン コンテンツに移動

インラインSVGのdefsとgかsymbolとuseによる呼び出しのマークアップ

サイトに画像を描画できるインラインSVGは小さくても乱れず、しかもサイト内にマークアップすればサーバーの呼び出しを行わず、迅速に表示できるからアイコンのデザインなどに良く使われる。

蜂の巣の中の六角形の小部屋の集まり

インラインSVGには同じ画像を繰り返して表示するためのマークアップがある。

一つのsvgタグの内側にdefsタグを入れてそこにid付きのgタグかsymbolタグで描画内容を纏めておく。そして内側か、または外側の場合は他のもう一つのsvgタグにuseタグを入れてhref属性でgタグかsymbolタグのidを指定してリンクのように呼び出す。

インラインSVGの二つの呼び出し方

一つのsvgタグの中で呼び出す場合

HTML

<svg viewBox="0 0 124 36" width="124" height="36">
  <defs class="hidden">
  <g id="rect_g">
    <rect x="2" y="2" width="32" height="32" stroke-width="4px" stroke="#8fbc8f" fill="#2e8b57" rx="2px" ry="2px"/>
    <rect x="46" y="2" width="32" height="32" stroke-width="4px" stroke="#2e8b57" fill="#3cb371" rx="2px" ry="2px"/>
    <rect x="90" y="2" width="32" height="32" stroke-width="4px" stroke="#3cb371" fill="#8fbc8f"  rx="2px" ry="2px"/>
  </g>
  </defs>
  <use href="#rect_g"/>
</svg>

CSS

.hidden {display:none}

※SVGの名前空間のxmlns属性やxmlns:xlink属性は付けなくてもHTML5のブラウザは付くものとして把握する。

複数の画像をsvgタグのviewBox/座標系に全て纏めて記載するのに向いてそうだ。

定義用と表示用のsvgタグを分ける場合

HTML

/* 呼び出し元のマークアップ */
<svg class="hidden" viewBox="0 0 36 36">
  <symbol id="rect_r1">
    <rect x="2" y="2" width="32" height="32" stroke-width="4px" stroke="#dfc0cb" fill="#8b0000" rx="2px" ry="2px"/>
  </symbol>
  <symbol id="rect_r2">
    <rect x="2" y="2" width="32" height="32" stroke-width="4px" stroke="#8b0000" fill="#ff0000" rx="2px" ry="2px"/>
  </symbol>
  <symbol id="rect_r3">
    <rect x="2" y="2" width="32" height="32" stroke-width="4px" stroke="#ff0000" fill="#dfc0cb" rx="2px" ry="2px"/>
  </symbol>
</svg>
/* 呼び出し先のマークアップ */
<svg width="36" height="36"><use href="#rect_r1"/></svg>
<svg width="36" height="36"><use href="#rect_r2"/></svg>
<svg width="36" height="36"><use href="#rect_r3"/></svg>

CSS

.hidden {display:none}

※SVGの名前空間のxmlns属性やxmlns:xlink属性は付けなくてもHTML5のブラウザは付くものとして把握する。

複数の画像を一ずつ扱って色んなところに配置するのに向いてそうだ。

どちらの場合でもdefsタグは使わなくても画像の表示に支障はないけれどもSVGのマークアップとしては使うことが推進されている。

SVGでは、後で再利用できるよう描画オブジェクトを定義します。参照される要素は、可能なかぎりdefs要素内で定義されることが推奨されています。defs要素内でこれらの要素を定義することは、SVGの要素の可読性を向上させ、ひいては操作性をも向上させます。defs要素の描画要素は、そのままでは描画されません。ビューポート上で描画したい場所へそれらの要素を描画するために、<use>要素を使用します。

defsタグはサイトのソースコードでそれ自体がインラインSVGの「参照される要素」を含むという「可読性」を示すと同時に囲んだ領域を表示しないので、インラインSVGの画像を部分的に使ったり、使わずに他のuseタグの呼び出しでのみ使ったりするという「操作性」を与える。

只、symbolタグについては最初から呼び出しのuseタグとセットで使うものと決まっているからそうした描画用のマークアップを収めるだけの用途ならばdefsタグで囲わなくても不都合は特にない。

インラインSVGの呼び出しのマークアップは画像を定義する呼び出し元を表示したくない場合はデザインのCSSで親要素のsvgタグなどに非表示の「display:none」をかける。

defsタグやsymbolタグを使うとその場で描画しなくなるけれどもマークアップした分の高さが残ってしまうから余計な隙間を縮めるためにもCSSの「display:none」で要素として取り除くか、せめて「height:0」で高さをなくす必要が出て来る。

画像の大きさは表示するsvgタグに横幅のwidth属性と縦幅のheight属性を付ける(pxか%の値で、単位なしはpx値となる)かCSSの縦幅のwidthと横幅のheightを指定する(単位ありの値)のが簡単だ。

定義用と表示用のsvgタグが同じか異なる場合の何れにしても画像を呼び出して実際に表示するuseタグを含む方で大きさを調節できる。

呼び出しのマークアップの長所と短所

僕はインラインSVGの呼び出しのマークアップに関して一つのページに同じ画像が幾つも必要でなければ意味がないと思ってブログのアイコンでも使わなかったけれども表示速度などのパフォーマンスへの好影響がないわけではないかも知れないから改めて使ってみたくなったんだ。

一方defs要素に定義されたグラフィックをuse要素から参照する場合,一旦defs要素内で解析済みの内容をuse要素部に描画するだけであり,その結果スクリーンの書き換え処理の回数を極小化できる.つまり,オフスクリーンレンダリングのような効果が得られる.

ブラウザのインラインSVGのパースとレンダリング(解析と表出)が分離されるとスクリーンの描画コストを下げることができるのかも知れない。

または描画内容の比較的に長めのマークアップを定義用としてインラインSVGの実際の表示位置から外して下の方にでも置けば後続のコンテンツへのブラウザの動作もなるべく止めずに済ませられるかも知れない。

defsとgかsymbolとuseによる呼び出しのマークアップは複数のインラインSVGを一つに纏めておけるから便利だけれどもそれらを一つずつしか使わない場合でもやる価値はパフォーマンスの向上のためにありそうだ。

ただし状況によって反対の結果を招くという可能性もあるから注意を要する。

私は<use>を深く入れ子にしないことを助言する。大半のブラウザで遅鈍を引き起こすと知られている、こちらとこちらで分かる。

原文

I would advise you to not nest elements deeply. That is known to cause slowdowns in most browsers, see here and here.

Does reusing symbols improve SVG performance?|stackoverflow(訳出)

gタグやsymbolタグの中にuseタグを記載すると階層が深くなるほどにインラインSVGのパフォーマンスの低下を招く。

その他、アニメーションを付けるとスクリーンの書き換えが増えて表示速度が下がり易くなる。

use要素とsymbol要素は、Flashで使われる「シンボル化」と違って、内部でかなり複雑な変換をしています。

動的な変更があるたびに、この複雑な変換をしますので、描画処理の性能が落ちてしまいます。

重たくなりますので、必ず、この二つの要素は避けましょう。

gタグを含めてアニメーションはデザインのCSSの更新などでもパフォーマンスを低下させるからなるべくインラインSVG自体を使わない方が望ましいようだ。

その他、大きな画像の場合はインラインSVGをサイト内よりも外部ファイルのマークアップから呼び出す方がブラウザが適切に読み込んだり、保存して使い回せたりして効率的かも知れない。

大量の5k以下の小さなSVG――SVGスプライトを作る

原文

Huge number of small SVG(s) < 5k - Make SVG sprite

例えばアイコンを大量に使うような場合はインラインSVGのマークアップを外部ファイルに「SVGスプライト」として全て纏めて一回で読み込む方がパフォーマンスが良いと考えられる。

useタグで外部ファイルを読み込む場合はリンクと全く同じにhref属性にインラインSVGの定義を置いたサイトのURLを入力することになる。

SVGのgタグとsymbolタグの違い

どちらもidを付けるとuseタグでマークアップされた描画内容をhref属性で呼び出すことができるけれども全く同じものでもない。

gタグの特徴
それ自体は表示される
座標系のviewBox属性が使えない
縦横比のpreserveAspectRatio属性が使えない
symbolタグの特徴
useタグなしに表示されない
座標系のviewBox属性が使える
縦横比のpreserveAspectRatio属性が使える

HTML要素としてgタグはSVGの描画内容を纏めるもの、symbolタグはuseタグで呼び出される描画内容を示すものなので、インラインSVGの呼び出しにはsymbolタグを使うのが普通だろう。

両方とも別々に使うだけではなく、gタグの中にsymbolタグ、反対にsymbolタグの中にgタグを入れ子にして一緒に使うこともできる。

useタグが呼び出せるのはgタグとsymbolタグだけではなく、svgタグやグラフィックス要素と呼ばれる一群の描画用のタグ: circle/ellipse/image/line/path/polygon/polyline/rect/text/useもidを付ければhref属性で表示できる。

コメント