2014年8月16日土曜日

HTMLパーサーを使ったインラインSVGのフォールバック方法

表題の件って以前にも当ブログで紹介していたんだけれど,それには一点問題があったのだけれど,ようやっと解決策を思いついたのでご紹介.って二年越しだよコレ!



インラインSVGを使う上で問題となること


ようやくIE8環境の終焉が見えてきたところでSVG普及の目処が立ちつつある今日このごろですが,それでも要件上SVG非対応環境を無視できないことは未だにあるかと思います.

すると問題となるのがSVG画像のフォールバックによる対処です.大抵はPNG画像を用いて代替とするのでしょうが,HTMLのインラインSVG機構を使っていた場合結構実現が難しかったりします.

この問題への対処策は本ブログで紹介してきたとおりで,下記の記事で触れています.

要はforeignObject要素を使って次のようなコードを記述せよってことです.

<!DOCTYPE html>
<html>
 <body>
  <svg width="200px" height="200px">
   <rect x="50" y="50" width="100" height="100" fill="yellow"/>
   <foreignObject display="none">
    <img src="img.png"/>
   </foreignObject>
  </svg>
 </body>
</html>

こうすると,
  • SVGをサポートしているブラウザではimg要素が隠れる
  • SVGをサポートしているブラウザではimg要素が表示される
ようになります.よってこれでフォールバックは完璧!

…と思われましたが,
こちら(SVGをIE等のブラウザ対応を考慮して使う方法まとめ(SVGのフォールバック画像など))
で指摘されているように,これでは常にimg.pngの内容が読み込まれてしまうのです!

少数派となっているSVG非対応ブラウザのために,大半を占める環境にimg.pngをダウンロードさせるというのはいかにも無駄が多いと言わざるを得ません.

じゃあこの他にインラインSVGのフォールバックってどうやりゃいいのよ?というのが今回の課題です.

HTMLパーサーを使った対処


そこで今回紹介するのがHTMLパーサーの挙動を逆手に取ったものです.とりあえず次のコードを見てください.

<!DOCTYPE html>
<html>
 <head>
 <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
 <style type="text/css">
svg, #fallback{
 width:200px;
 height:200px;
}
#fallback{
 background-image:url(fallback.png);
 background-size:200px 200px;
}
svg+#fallback{
 display:none;
 background-image:none;
}
 </style>
 </head>
 <body>
  <svg>
   <rect x="10" y="10" width="180" height="180" fill="blue"/>
   <div id="fallback"></div>
  </svg>
 </body>
</html>

そこで質問です.これをfirefox等のSVGをサポートするwebブラウザで表示するとid="fallback"が付けられたdiv要素はどこに配置されるでしょうか

htmlコードの通り「svg要素配下にdiv要素が格納される」と考えた方はハズレです.実はSVG要素の直後に配置されます.すると,スタイルシートの「svg+#fallback」の記述が有効となります

一方SVGをサポートしないwebブラウザ(ie8,android2.x系)ではsvg要素を解釈できず,上記のような再配置が発生しません.つまり「#fallback」の記述が有効となります

よってcssによる画像の読み込み有無の振り分けが可能になるのです!
下は実際の動作例です.(android2.x系は@rikuo氏に確認していただきました.感謝!)




奇妙な動作に見えますか?ですが,これはれっきとしたHTML5の仕様なのです
http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html#creating-and-inserting-nodes
ですから今後動作しなくなることもありません.


NOTE:
http://css-tricks.com/svg-fallbacks/
にあるimageタグトリックは個人的には好かんのですが,こっちのほうが簡単かも知れません.
何れにせよ複数の選択肢があるってのは良いことです.

0 件のコメント:

コメントを投稿