内部参照SVGスプライトをCSSでカスタマイズ(IE11対応)

SVG画像をHTMLへ<svg>タグとして設置すると
塗りのfillや、線のstrokeなどをCSSから変更することができ
オンマウスでの色変更にtransitionでアニメーションをつけるなど表現の幅が広がります。

しかし、地図などパスの形が複雑になると、SVGコードが座標の指定だけでエディタを埋め尽くす程度には長くなるため
どのようなケースでも気軽に導入しにくい一面もあります。

SVGスプライトならHTMLを簡略化できる

そこで、HTMLソースが冗長になるのを避ける有効な方法が
useによる参照を活用したSVGスプライトです。

このようなとても長いコードを

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="hoge" viewBox="0 0 4 4">
    <path d="M417.1,227.8c-0.5-0.4-1.2-0.7-1.5-0.6c0,0-0.1,0-0.1,0c-0.2,0.1-0.1,0.4,0.8,1.1c0.2,0.2,0.6,0.3,0.8,0.3 ..." />
  </symbol>
  <symbol id="fuga" viewBox="0 0 4 4">
    <path d="M447.5,218.7c-0.2-0.7-1.1-1-1.8-1.1h0c-1.1-0.2-1.8-0.5-2.4-0.7c-0.3-0.1-0.5-0.2-0.7-0.2 ..." />
  </symbol>
</svg>

短くHTMLへ設置できます。

<svg>
  <use xlink:href="map.svg#hoge" />
  <use xlink:href="map.svg#fuga" />
</svg>

ただ、このままだと
hogeとfugaそれぞれにCSSからスタイルを設定し、表示も崩れないよう担保できないため
いくつか属性が必要です。

IE11やEdgeにも対応した構成

結論からいくと、このようになります。

<svg xmlns="http://www.w3.org/2000/svg">
  <symbol id="hoge" viewBox="0 0 4 4">
    <path class="hoge-style" d="M417.1,227.8c-0.5-0.4-1.2-0.7-1.5-0.6c0,0-0.1,0-0.1,0c-0.2,0.1-0.1,0.4,0.8,1.1c0.2,0.2,0.6,0.3,0.8,0.3 ..."/>
  </symbol>
  <symbol id="fuga" viewBox="0 0 4 4">
    < path class="fuga-style" d="M447.5,218.7c-0.2-0.7-1.1-1-1.8-1.1h0c-1.1-0.2-1.8-0.5-2.4-0.7c-0.3-0.1-0.5-0.2-0.7-0.2 ..."/>
  </symbol>
</svg>
<svg viewBox="0 0 4 4" class="test">
  <use class="hoge-style" xlink:href="dot.svg#hoge" />
  <use class="fuga-style" xlink:href="dot.svg#fuga" />
</svg>
.test .hoge-style {
  fill: whitesmoke;
  transition: fill 250ms;
}
.test .fuga-style {
  fill: gray;
  transition: fill 250ms;
}
.test:hover .hoge-style {
  fill: white;
}
.test:hover .fuga-style {
  fill: cyan;
}

ポイント

  1. SVG内の、useで呼び出したい単位をsymbolで囲いidを指定。
  2. HTMLに記述するsvgタグにもviewBox属性を記述。
  3. SVG内のsymbolが持つpath(またはそれに準ずるgcirclepolygonなど)と、HTMLに記述するuseタグに同じclassを付与。

symbolの使用とviewBoxの指定は、IE11で表示を崩さないための対策です。

Chromeなどのモダンブラウザで、表示されたHTMLを開発者ツールを通して見てみると
svgタグ内へはuseclassつきの状態で表示されており、その内部にclassが付与されていないpathが呼び出された状態で解釈されていることがわかります。

しかし、IE11ではsvgタグ内にuseは存在せず、symbol内部のタグがSVGソース時のclassが付与されている状態で解釈されています。

したがって、useとSVG内のpash両方にclassを付与したところ
クロスブラウザでCSSによる制御に対応できることがわかりました。

関連記事