2.IDEA

JP only

SVGをIE等のブラウザ対応を考慮して使う方法まとめ(SVGのフォールバック画像など)

SVGは、2011年にIE9が標準対応したことをきっかけに、注目され始めました。スマホやタブレットで拡大して表示する機会が多くなったことや高解像度ディスプレイが多く使用されるようになったこともあり、拡大率や解像度に関係なく綺麗に表示してくれるSVGは、依然として盛り上がりを見せています。

その一方で、ウェブ制作者としては、IE7以下で使えないならまだしもIE8でも使えないとなると、実務で使うのは躊躇われます(Androidも2.3以下はサポート外です)。

そこで今回は、(だいぶ今更感はありますが)IE等を考慮したSVGの使用方法について書きたいと思います。

目次

  1. IE6までSVGで表示したい場合
    1. Raphaëlを使う
    2. svgwebを使う
  2. IE8までSVGで表示したい場合
    1. SIE.jsを使う
  3. SVGにサポートしていないブラウザは代替画像ですませる場合
    1. インラインSVGで使う場合
    2. objectで使う場合
    3. background-imageで使う場合
    4. imgで使う場合
  4. デモとパフォーマンス比較
  5. 参考

1. IE6までSVGで表示したい場合

IE6等のレガシーブラウザでも、(PNG等の代替画像ではなく)SVGを表示したいときはJavaScriptライブラリを使う必要があります。

しかし、それらのライブラリのほとんどは、アニメーションを簡単に実現するためのコードも含まれています。

SVGアニメーションを使うなら導入していいかもしれません。しかし、IEでSVGを表示させるためだけに使うのは、膨大なサイズのファイルを余計に読み込むことになるので、パフォーマンスに注意して使う必要があります。

追記:Androidでは3.0未満の標準ブラウザでは表示できないので、フォールバックが必要です。

1.1. Raphaëlを使う

Raphaëlは、割と昔からある有名なSVG用のJavaScriptライブラリです。

使う際には、SVGファイルをRaphaël用のコードに変換する必要があります。以下のどちらかを使うと良いでしょう。

変換した後、以下のように使います。

<script src="raphael.js"></script>
<script>
Raphael(function(){
  /* 上記のリンクで変換したRaphaël用のコード
   var paper = Raphael('canvas-id', '(width)', '(height)'); から始まる */
});
</script>

<div id="canvas-id"></div><!-- このdiv内にSVGが追加される -->

1.2. svgwebを使う

svgwebは、Google Codeで公開されているものです。

IEのバージョン分岐を使って以下のように実装します。
IE8以下で確認したところ、表示されていませんでした。

<!--[if lt IE 9]>
<script type="text/javascript" src="svg.js"></script>
<![endif]-->

<!--[if !IE]>-->
<object data="circle.svg" type="image/svg+xml"
        width="100" height="100" id="c1"> <!--<![endif]-->
<!--[if lt IE 9]>
<object src="circle.svg" classid="image/svg+xml"
        width="100" height="100" id="c1"> <![endif]-->
<!--[if gte IE 9]>
<object data="circle.svg" type="image/svg+xml"
        width="100" height="100" id="c1"> <![endif]-->
<p>ここにフォールバック時のコンテンツ</p>
</object>

2. IE8までSVGで表示したい場合

IE6,7は切り捨てていい場合は、こちらでいいかと思います。

追記:Androidでは3.0未満の標準ブラウザでは表示できないので、フォールバックが必要です。

2.1. SIEを使う

国産のライブラリのSIEです。以下、使い方です。

<head>
<script defer="defer" type="text/javascript" src="sie.js"></script>
</head>
<body>
<object data="circle.svg" type="image/svg+xml" width="100" height="100"></object>
</body>

3. SVGにサポートしていないブラウザは代替画像ですませる場合

SVGをサポートしていないブラウザにはPNG等のフォールバック画像を使うパターンです。パフォーマンスを考えるとこちらがスマートで良いと思います。

3.1. インラインSVGで使う場合

こちらの記事で紹介されているやり方です。SVG内で<foreignObject>を使って<img>を読み込ませ、display="none"で非表示にしています。レガシーブラウザでは<svg>などを無視して<img>のみ読み込むため、PNG画像が表示されます。

<svg width="100px" height="100px">
  <circle fill="black" cx="50" cy="50" r="50" />
  <foreignObject display="none">
    <img src="circle.png" />
  </foreignObject>
</svg>

JavaScriptを使わないのが良いところです。ただ、モダンブラウザでは、余計なリソース(<img>)を読み込んでしまうことが難点です。

3.2. objectで使う場合

こちらの記事で説明されています。<object>では、仕様レベルでフォールバック画像が指定可能になっています。

なお、SVGに<a>タグでリンクを貼った場合、リンクがクリッカブルにならなかったり、IE9でカーソルがポインターにならないという問題が発生したりするとのことです(紹介した記事内で解決策も教えてくれています)。

<object data="image.svg" type="image/svg+xml" width="100" height="100">
 <img src="image.png" width="100" height="100" />
</object>

こちらも、モダンブラウザでは、余計なリソース(<img>)を読み込んでしまうという難点はついてきます。

3.3. background-imageで使う場合

Modernizrを使って、SVGが使えないブラウザを判定する方法が一般的です。

.class {} /* 共通スタイル */
.svg .class{background:url(circle.svg)}/* SVGが使えるブラウザはSVGで表示 */
.no-svg .class{background:url(circle.png)}/* SVGが使えないブラウザではPNGで代替 */

パフォーマンスの関係でModernizrを使いたくないときは、「SVGは高解像度のディスプレイだけで良い」のであれば以下でも大丈夫です。

.class{background:url(circle.png)}/* 解像度が高くないディスプレイはPNGで表示 */
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
  only screen and (-o-min-device-pixel-ratio: 3/2),
  only screen and (min--moz-device-pixel-ratio: 1.5),
  only screen and (min-device-pixel-ratio: 1.5) {
  .class{background:url(circle.svg)}/* 解像度が高い(ピクセル率が1.5以上の)ディスプレイはSVGで表示 */
}

他にも、html内に、スタイルシートを読み込むメタデータを含んだSVGを書くことでも実現出来ます。詳しくは以下の記事に書いてあります。

追記:HTMLパーサの機構(SVGが利用可能なブラウザではSVG内のdiv等が外に追い出される仕様)を利用して、以下のようなCSSを使うことでも実現できるようです!詳しくはこちらの記事(HTMLパーサーを使ったインラインSVGのフォールバック方法)をご覧下さい。

#fallback{
 background-image:url(fallback.png);
}
svg+#fallback{
 display:none;
 background-image:none;
}

3.4. imgで使う場合

こちらも、Modernizrで振り分けます。SVGが使えないブラウザでは、JavaScriptを使ってリソースを.svgから.pngに書き換えます。

<img src="circle.svg" id="circle" width="100" height="100" />

<script>
if(!Modernizr.svg){
  var circle = document.getElementById("circle");
  circle.setAttribute("src", "circle.png");
}
</script>

複数のSVGを使う場合は、以下の記事で紹介しているようなdata-*属性を使うのが良いかと思います。

4. デモとパフォーマンス比較

最後に、あくまで参考程度ですが、MacBookProのRetinaモデル(メモリ8GB)、Chrome(Canary)のDevToolsでSVGが表示されるまで(というよりなんやかんやの処理が終わるまで)の時間を計測しました。

リンク先はデモになっています。

正直、読み込むたびに10msくらいの誤差があるので、Raphaël以外はほとんど変わらないと考えて良いです。

それよりも、単純にリソースのサイズやJavaScriptでどれだけゴリゴリやってるか等から一番軽そうなやつを選ぶと良いかと思います。

追記:こちらのスライド(SVG MANIAX Ver.2 - Mars vanilla)の51ページ目から、この記事には書いていないフォールバック手法が紹介されています。以下です。

  • objectを入れ子にして外側はSVG、内側をフォールバック画像にする
    <object data="sample.svg" type="image/svg+xml">
      <object data="fallback.png" type="image/png">
        <p>xxx</p>
      </object>
    </object>
  • インラインSVGの中でimage要素を使い、xlink:hrefにSVG、srcにフォールバック画像を指定する
    <svg viewBox="0 0 96 96">
      <image xlink:href="sample.svg" src="fallback.png" width="96" height="96" />
    </svg>
  • imgで普通に.svgを読み込み、onerrorイベントでsrcを.pngに書き換える
    <img src="sample.svg" onerror="this.src='fallback.png';">
  • background-imageで普通にフォールバック画像を指定した後、複数画像指定が使えるブラウザにはSVGを使う
    .element{
      background-image: url(fallback.png);
      background-image: url(sample.svg) none;
    }

5. 参考