やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

SVGスプライトの作成と利用

 SVGスプライトは複数の画像を一つのファイルにまとめたもの。表示時に画像をid指定するため複数ヶ所で参照する時に短く書けて画像やHTMLファイルのサイズが削減できる。

成果物

  • インライン版
  • 外部参照版

インライン版

 サーバ不要。

index.html

<svg>
<defs>
<symbol id="clipboard" viewBox="0 0 256 256"><path d="M64 0a8 8 0 0 0-8 8v16H32a8 8 0 0 0-8 8v216a8 8 0 0 0 8 8h192a8 8 0 0 0 8-8V32a8 8 0 0 0-8-8h-24V8a8 8 0 0 0-8-8zm8 16h112v48H72V32zM40 40h16v32a8 8 0 0 0 .041.799 8 8 0 0 0 .12.79 8 8 0 0 0 .472 1.526 8 8 0 0 0 .765 1.403 8 8 0 0 0 .485.636 8 8 0 0 0 1.144 1.114 8 8 0 0 0 1.346.863 8 8 0 0 0 .729.326 8 8 0 0 0 1.54.426A8 8 0 0 0 64 80h128a8 8 0 0 0 1.59-.16 8 8 0 0 0 1.525-.473 8 8 0 0 0 .72-.347 8 8 0 0 0 .682-.418 8 8 0 0 0 2.215-2.28 8 8 0 0 0 .977-2.183 8 8 0 0 0 .29-2.14V40h16v200H40z"/></symbol>
<symbol id="file" viewBox="0 0 256 256"><path d="M32 0a8 8 0 0 0-8 8v240a8 8 0 0 0 8 8h192a8 8 0 0 0 8-8V72a8 8 0 0 0-.006-.125 8 8 0 0 0-.021-.39 8 8 0 0 0-.032-.405 8 8 0 0 0-.056-.373 8 8 0 0 0-.076-.42 8 8 0 0 0-.09-.35 8 8 0 0 0-.121-.423 8 8 0 0 0-.131-.356 8 8 0 0 0-.153-.383 8 8 0 0 0-.171-.357 8 8 0 0 0-.182-.348 8 8 0 0 0-.219-.357 8 8 0 0 0-.213-.324 8 8 0 0 0-.242-.319 8 8 0 0 0-.25-.31 8 8 0 0 0-.38-.416l-.085-.082-63.916-63.918a8 8 0 0 0-.049-.045 8 8 0 0 0-.27-.244 8 8 0 0 0-.32-.284 8 8 0 0 0-.351-.257 8 8 0 0 0-.291-.207 8 8 0 0 0-.365-.22 8 8 0 0 0-.33-.187 8 8 0 0 0-.457-.213 8 8 0 0 0-.25-.11 8 8 0 0 0-.48-.169 8 8 0 0 0-.288-.096 8 8 0 0 0-.447-.105 8 8 0 0 0-.338-.076 8 8 0 0 0-.422-.059 8 8 0 0 0-.37-.045A8 8 0 0 0 160 0zm8 16h112v56a8 8 0 0 0 .041.799 8 8 0 0 0 .94 3.037 8 8 0 0 0 .417.682 8 8 0 0 0 2.28 2.214 8 8 0 0 0 2.965 1.15A8 8 0 0 0 160 80h56v160H40zm128 11.312L204.688 64H168z"/></symbol>
<defs>
</svg>

<svg><use href="#clipboard"></use></svg>
<svg><use href="#clipboard"></use></svg>
<svg><use href="#file"></use></svg>
<svg><use href="#file"></use></svg>

 画像データは以前作成したSVG画像をコピペして作った。

外部参照版

  • sprite.svg
  • index.html

sprite.svg

<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="clipboard" viewBox="0 0 256 256"><path d="M64 0a8 8 0 0 0-8 8v16H32a8 8 0 0 0-8 8v216a8 8 0 0 0 8 8h192a8 8 0 0 0 8-8V32a8 8 0 0 0-8-8h-24V8a8 8 0 0 0-8-8zm8 16h112v48H72V32zM40 40h16v32a8 8 0 0 0 .041.799 8 8 0 0 0 .12.79 8 8 0 0 0 .472 1.526 8 8 0 0 0 .765 1.403 8 8 0 0 0 .485.636 8 8 0 0 0 1.144 1.114 8 8 0 0 0 1.346.863 8 8 0 0 0 .729.326 8 8 0 0 0 1.54.426A8 8 0 0 0 64 80h128a8 8 0 0 0 1.59-.16 8 8 0 0 0 1.525-.473 8 8 0 0 0 .72-.347 8 8 0 0 0 .682-.418 8 8 0 0 0 2.215-2.28 8 8 0 0 0 .977-2.183 8 8 0 0 0 .29-2.14V40h16v200H40z"/></symbol>
<symbol id="file" viewBox="0 0 256 256"><path d="M32 0a8 8 0 0 0-8 8v240a8 8 0 0 0 8 8h192a8 8 0 0 0 8-8V72a8 8 0 0 0-.006-.125 8 8 0 0 0-.021-.39 8 8 0 0 0-.032-.405 8 8 0 0 0-.056-.373 8 8 0 0 0-.076-.42 8 8 0 0 0-.09-.35 8 8 0 0 0-.121-.423 8 8 0 0 0-.131-.356 8 8 0 0 0-.153-.383 8 8 0 0 0-.171-.357 8 8 0 0 0-.182-.348 8 8 0 0 0-.219-.357 8 8 0 0 0-.213-.324 8 8 0 0 0-.242-.319 8 8 0 0 0-.25-.31 8 8 0 0 0-.38-.416l-.085-.082-63.916-63.918a8 8 0 0 0-.049-.045 8 8 0 0 0-.27-.244 8 8 0 0 0-.32-.284 8 8 0 0 0-.351-.257 8 8 0 0 0-.291-.207 8 8 0 0 0-.365-.22 8 8 0 0 0-.33-.187 8 8 0 0 0-.457-.213 8 8 0 0 0-.25-.11 8 8 0 0 0-.48-.169 8 8 0 0 0-.288-.096 8 8 0 0 0-.447-.105 8 8 0 0 0-.338-.076 8 8 0 0 0-.422-.059 8 8 0 0 0-.37-.045A8 8 0 0 0 160 0zm8 16h112v56a8 8 0 0 0 .041.799 8 8 0 0 0 .94 3.037 8 8 0 0 0 .417.682 8 8 0 0 0 2.28 2.214 8 8 0 0 0 2.965 1.15A8 8 0 0 0 160 80h56v160H40zm128 11.312L204.688 64H168z"/></symbol>
<defs>
</svg>

index.html

<svg><use href="./sprite.svg#clipboard"></use></svg>
<svg><use href="./sprite.svg#clipboard"></use></svg>
<svg><use href="./sprite.svg#file"></use></svg>
<svg><use href="./sprite.svg#file"></use></svg>

HTTPS server

 上記のように外部のSVGファイルを参照する場合はHTTPSサーバを立てる必要がある。

SVGスプライト作成

 以下のようなフォーマットになる。

<svg xmlns="http://www.w3.org/2000/svg">
<defs>
<symbol id="..." viewBox="0 0 256 256"><path d="..."/></symbol>
<defs>
</svg>
要素 概要
<svg> SVGルート要素
<defs> 定義要素を含める
<symbol> id属性値に識別名を記入する
<path> d属性値にパスデータを記入する
  1. 画像一つあたりの要素を<symbol>に入れる
  2. 1のid属性値に識別子をつける
  3. 画像の数だけ上記を繰り返す

 ポイントは以下。

  • <defs>により、その内容が<use>で参照すべきものであることを示す(表示内容でないことを示す)
  • <symbol>により、その内容を<use>するとき、<use>で属性指定することで変更可能になる(色やサイズ等)
  • <path>Inkscape等で作成した要素そのままコピペする

 尚、そのまま挿入されると空白領域が表示されてしまうため、以下のいずれかで非表示にする。

<svg style="display:none;">
<svg width="0" height="0">

SVGスプライト利用

<svg><use href="..."></use></svg>
  • hrefにはpath#idの形式で与える
    • pathはファイルパス
    • idSVGスプライトで定義した属性値

 注意点はidが必須であること。また、インラインの場合、他の要素とidが重複しやすくなる。

変更

  • サイズ

index.html

<svg>
  <use href="..." fill="#f00"/>
</svg>
  • fillstrokeで色をセットする

 CSSで調整してもいい。

<style>.icon{fill:#f00; stroke:#0f0;}</style>
<svg css="icon">
  <use href="..."/>
</svg>
属性 意味
fill 内側の塗りつぶし色
stroke 外側(輪郭)の色

 fill:noneにすると塗りつぶしが失くなり、マウスイベントまで失う。

サイズ

  • viewBox
  • width
  • height

 <symbol>viewBoxを定義し、dでそれに応じた図形を作る。それを<use>で参照し、その大きさは<use>をもつ<svg>width,heightで指定する。viewBoxはそれに合わせて拡縮する。

sprite.svg

...
<symbol id="..." viewBox="0 0 256 256"><path d="..."/></symbol>
...

index.html

<svg width="1em" height="1em">
  <use href="..."/>
</svg>

 CSSでセットしてもいい。

<style>.icon{width:1em; height:1em;}</style>
<svg class="icon">
  <use href="..."/>
</svg>
属性 意味
viewBox 図形パス座標はこの領域内に含めること
width, height 実際の表示サイズ。viewBoxはこの領域内に収まるよう拡縮する

SVGスプライトの使い所は?

 SVGスプライトを使うべき場面はいつ? SVG画像そのままでもいいのでは? わざわざスプライトにする必要ある?

 こうした疑問には、次の効果があると答える。

  • 通信量を減らす
  • ファイル容量を減らす
  • 製作コストを減らす

通信量を減らす

 以下によると複数のSVG画像を一つのSVGスプライトファイルにまとめることでHTTP通信の回数を減らし応答速度を改善してきたという。今となっては通信技術により、その必要がないという話のようだが。

HTTP通信数を減らす方法 概要
スプライティング 複数の画像を一つにまとめる
インライニング 画像をBase64化しCSSに埋め込む
コンカチネーション JSファイルを全て1つにまとめる
HTTP ver 概要
1.1 オーバーヘッドがあり通信やキャッシュの効率が悪い
2.0 通信の多重化(並列処理により通信回数が増えても良くなった)
3.0 QUICによりHead-of-Line-Block問題解決

 ただ、SVGスプライトが役目を終えたわけではない。上記の記事はあくまでHTTP通信頻度を下げる工夫としてのスプライティングという手法はHTTP2以降の通信技術により不要化する、と言っているだけだと思う。わざわざ一つのファイルにまとめずとも、複数のSVG画像でそれぞれHTTPリクエストしても、HTTP2以降なら通信回数がファイル数の分だけ増えても問題なくなった、という話に過ぎない。

 SVGの価値はファイルを一つにまとめてHTTPリクエスト回数を減らすだけではない。

制作コスト・ファイル容量を減らす

 SVGスプライトの価値は他にもある。制作コストとファイル容量を減らせる点だ。

 同じ図形を短縮参照し、それぞれに拡縮・変色・変形などの幅広い変化をつけて流用できる。これにより、ゼロから色やサイズ等が違うだけの図形を複数作成してそれぞれ異なるパスデータを持たせるよりもファイル容量が縮小できる。そういう使い方をするのがSVGスプライトの本領であり価値だろう。その価値は未だ衰えず、替えの効かないSVGスプライトの存在意義だと思う。

 以下のサイトでは単一の図形を複数参照して、角度などを変えて配置し一つの図形を作成している。

 応用はいくらでも思いつく。たとえば矢印を一つ作って、それを4つ参照し、それぞれ別の角度をつけてやれば、一つの基礎画像で四つの矢印が作れる。これは四つの画像ファイルを別の図形データとして作るよりも制作の手間やファイル容量が少なく済む。ファイル容量が減れば、そのままHTTP通信量の削減にもなる。

 もちろん矢印は他の図形とも組合せ可能なので、いくらでも流用できる。流用の回数が増えるほどファイル縮小効果があがる。

 というわけで、SVGスプライトはパフォーマンスの観点から見ても、制作工程を減らす観点から見ても、学ぶべき価値のある技術のはずだ。そうしたファイル作成を想定し実装することで劇的に容量削減できる可能性を持っている。学習コストも高めだが、その価値はあるだろう。流用する最低限の知識として、<defs>, <symbol>, <use>を知っておけば充分だ。

まとめ

  1. アイコンを作る
  2. それを<use>で組合せる or 複数ヶ所で参照する
  3. 繰り返す

 これにより以下が改善される。

  • アイコン作成の労力
  • ファイルサイズ
  • HTTP通信量

 SVGスプライト、すごい、えらい、つよい。