外部SVGファイルを非同期で読み込み、インラインのSVGスプライトとして利用する
SVGスプライトを外部ファイルとして読み込みたくて、色々と調べたり試してみたりしていたのですが、外部SVGをAjaxで非同期読み込みするという方法が一番しっくりきたので、その方法を紹介します。
SVGスプライトといっても、CSSで背景画像として表示させるものではなく、HTMLにインラインで表示させるためのSVGスプライトになります。
何もしなくてもuse
タグのxlink
属性で外部SVGファイルを参照できることは知っていたのですが、IE9+でサポートされてなく、またEdgeでも怪しいとのことだったので、その方法は利用してきませんでした。ポリフィルを使ったフォールバックもあるようですが、そのためだけのフォールバックも何だか気持ちが悪かったので。。
今までやっていた方法
これまではbody
の開始タグすぐ下にsvg
タグを置き、その中へ画像ごとにsymbol
タグで囲み直したsvg
をずらーっと並べuse
タグで呼び出す、という方法で表示していました。
HTML
<body>
<svg style="display:none;">
<symbol id="twitterIcon" viewBox="0 0 200 200">
<path d="M246.1,23.7c-9.1,4-18.8,6.7-29,8c10 〜省略〜 39.3,33.8,246.1,23.7z"/>
</symbol>
<symbol id="facebookIcon" viewBox="0 0 88 170">
<path d="M57,170V93h26.6l3.9-31H57V43.1c0-8.7 〜省略〜 H0v31h26v77H57z"/>
</symbol>
<symbol id="hatenaIcon" viewBox="0 0 200 200">
<path d="M85.9,91.8c2.2-1.3,3.3-3.6,3.3-6.8c0 〜省略〜 C79.6,94,83.7,93.1,85.9,91.8z"/>
<path d="M89.6,111.3c-2.1-1.5-6.1-2.3-11.9-2. 〜省略〜 C92.8,115.3,91.8,112.7,89.6,111.3z"/>
<path d="M170.4,0H99.8H29.2C13,0,0,13.5,0,29. 〜省略〜 151.3,139.2,146,144.5,139.5,144.5z"/>
</symbol>
</svg>
<div class="wrapper">
…
SVGタグの部分はdisplay:none
で非表示にします。表示させる時は、使いたい画像のsymbol
タグにつけたid
を、use
タグのxlink
属性にセットし表示させます。
HTML
<svg class="icon"><use xlink:href="#twitterIcon"/></svg>
この方法で表示に関しては全く問題ないのですが、画像をコードで羅列しているため視認性が悪く、一つ一つの画像を管理するのが煩わしいのと、複雑な画像だった場合にHTML内がとんでもないことになり、HTMLの管理も面倒になってしまうというデメリットがありました。
そのため、今までは複雑な画像は避け、簡単なアイコンでのみ使用するに留めていました。
xlinkで外部SVGの参照
冒頭で記載した通り、xlink
は外部ファイルを参照できるので、SVGを外部ファイル化し、ファイルパスも含めて属性値に記載しておけば、モダンブラウザでは問題なく表示できます。
HTML
<svg class="icon"><use xlink:href="./assets/images/svg/sprite.svg#twitterIcon"/></svg>
IE11がなくなり、Edgeでの問題が解消されれば、これが一番スマートな方法ですね(さすがにIE11は無視できない&IE9は既にないものとして考えています)。
非同期で読み込む方法
ここからが本題です。
外部SVGファイルの作成
まずは、SVGの外部ファイルを用意します。ファイル名を「sprite.svg」という名前にして、そこにSVGスプライトを作成します。
ここで重要なのは名前空間です。インラインSVGとは異なり通常の「SVGファイル」としなければいけないので、先頭のSVGタグにxmlns
属性として必ず名前空間宣言を記載します。最終的にインラインとして挿入するので名前空間は不要と思いがちですが必須です。念のため、version
属性も併記しています。
インラインのSVGスプライトが既にあれば、その部分を切り取ってそのまま新規に作成したファイルに貼り付け、名前空間を追加し保存すればOKです。
既存のものがない場合には、下記を参考に作成してみてください。ここではsymbol
タグを使用していますが、g
タグでも問題ないはずです。必要なのは、名前空間と固有のid
です。viewBox
は任意ですが、記載しない場合、呼び出す際に幅と高さを指定し、use
で座標を調整する必要があります。
sprite.svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" style="display:none;">
<symbol id="twitterIcon" viewBox="0 0 200 200">
<path d="M246.1,23.7c-9.1,4-18.8,6.7-29,8c10 〜省略〜 39.3,33.8,246.1,23.7z"/>
</symbol>
<symbol id="facebookIcon" viewBox="0 0 88 170">
<path d="M57,170V93h26.6l3.9-31H57V43.1c0-8.7 〜省略〜 H0v31h26v77H57z"/>
</symbol>
<symbol id="hatenaIcon" viewBox="0 0 200 200">
<path d="M85.9,91.8c2.2-1.3,3.3-3.6,3.3-6.8c0 〜省略〜 C79.6,94,83.7,93.1,85.9,91.8z"/>
<path d="M89.6,111.3c-2.1-1.5-6.1-2.3-11.9-2. 〜省略〜 C92.8,115.3,91.8,112.7,89.6,111.3z"/>
<path d="M170.4,0H99.8H29.2C13,0,0,13.5,0,29. 〜省略〜 151.3,139.2,146,144.5,139.5,144.5z"/>
</symbol>
</svg>
上記の部分は、svg
タグごとそのままHTMLへ挿入されることになるので、style
属性にdisplay:none
を指定して非表示にします。svg
タグにclass
を指定して、CSSでdisplay:none
しても問題無いです。
作成したSVGファイルは、任意の場所にアップロードしておきます。
AjaxでSVGファイルを読み込む
Ajaxは、jQueryのajax
を使っているので、先にjQueryの読み込みが必要になります。下記、url:'./assets/images/svg/sprite.svg'
のファイルパスを変更した上で、body
の終了タグ直前に設置します(外部JS、head内でもOK)。
index.html
<script src="jquery.js"></script>
<script>
$.ajax({
type: 'get',
url: './assets/images/svg/sprite.svg'//ここにパスを入れる(環境に合わせて変更)
}).done(function(data) {
var svg = $(data).find('svg');
$('body').prepend(svg);
});
</script>
</body>
svg
タグごとすべてをjQueryのprepend
でbody
要素の先頭に挿入しています。
画像を表示させる時は。同じようにuse
タグのxlink
属性にそれぞれのid
をセットして表示させます。
index.html
<svg class="icon"><use xlink:href="#twitterIcon"/></svg>
あとは、CSSで幅や高さ、色などを調整して完了です。インラインSVGと同じ扱いとなるので、CSSで色々と調整が可能になります。
各ブラウザでの表示確認
Chrome、Safari、Firefoxでは問題なく表示できていました。iOSのSafari、AndroidのChromeでも問題なく表示できていましたが、上記のデモはスマホ対応していませんので、表示自体は崩れます。ご了承ください。
IEに関して、IE9では問題なく表示できていました。ただ、IE11とEdgeで確認することができなかったため、もし確認された方がいらっしゃったら教えていただけると助かります。IE9で表示できているので多分大丈夫だとは思いますが。
[追記]IE11、Edgeでも表示はされているとのご連絡をいただきました。ありがとうございます。ただ、ホバー時のアニメーション等、IEやEdgeならではの不具合(バグ?)はあるようです…。
大きめのSVGを入れて表示してみたりもしましたが、もたつくこともなく表示できていたので、問題なく使える方法かと思います。
SVGスプライトの作成をgulpで自動化
SVGスプライトは手動で作成してもいいのですが、手間が掛かるのと管理が煩わしくなるので、Illustratorで作成したSVGをそのままフォルダに突っ込んで、gulp等で自動化するとより楽になります。
この辺りについて書くと長くなるので、今回はここまでにします。