Hatena::ブログ(Diary)

聴く耳を持たない(片方しか)

2015-10-17 Acceptヘッダで判別するサーバーサイドのSVGフォールバック

前回の記事ではSVGに未対応な環境が現在どの程度残っているのか調査しました。

2015年10月に調査したSVG対応状況の円グラフ、未対応の環境は13.99%

SVG未対応ブラウザのシェアって今どれくらいか?2015年10月版

ブラウザシェアの調査は難しく、Webサイトの利用者層によっても傾向は異なるのでしょうが、NetMarketShareによれば未対応な環境は2割以下ほどになってきています。

しかし少数だからと言って全く無視をしてSVGだけを使うというわけにはいきません、なぜなら未対応の環境では表示されませんから、必要な情報を得られず困りますから、なんらかの形でフォールバックが必要になります。


簡易目次



フォールバックとは

フォールバックとは、ある機能が利用できないときでも別の手段で代替とすることです。

例えば、回線状況の悪化で画像が見れない場合、または視覚障害者向けのスクリーンリーダーなどで利用できるようにalt属性を使いますね、これも一つのフォールバックです。

<img src="paint.jpg" alt="代替テキスト">

jpeg画像が見れないときにはalt属性が代わりに表示されますし、スクリーンリーダーであれば画像が見れない視覚障害者向けに音声として読み上げます。


SVGもimg要素で使えますが、このままでは未対応の古いブラウザでは表示できません。

<img src="paint.svg" alt="代替テキスト">

代わりのalt属性を設定するのは当然として、できれば

  • SVG対応のブラウザならそのままSVGを表示する
  • 未対応のブラウザにはPNG画像などを代替として表示する

とさせたいわけです。


SVG未対応の環境とは

主要なモダンブラウザでは概ねSVGへの対応はされていますが、現在まで残っているSVG未対応の代表的な環境をピックアップすると、これらが挙げられます。

Inline SVG in HTML5 - Can I use...

IE 8以下Android 2.3.x以下フィーチャーフォンゲーム機

IEは8以下、Android3は未満の標準ブラウザが未対応。さらにフィーチャーフォン、いわゆるガラパゴスケータイですね。

そしてゲーム機の対応状況はこのような感じ

名前SVGレンダリングエンジンブラウザ仕様発売/配信時期
Wii インターネットチャンネル×PrestoOpera 9.xURL2006年12月
WiiU ブラウザーWebKitNetFront Browser NX v3.0URL2012年11月
DSブラウザー×PrestoOpera 8.5URL2006年7月
DSiブラウザー×PrestoOpera 9.5URL2008年11月
3DSブラウザー×WebKitNetFront(R)BrowserURL2011年6月
New 3DSブラウザーWebKitNetFront Browser NX v3.0URL2014年10月
PS3×Mozilla?URL2006年11月
PS4Webkit2013年11月
PSP×Mozilla?NetFrontURL2005年7月
PS VitaWebkitNetFront NXURL2011年12月

任天堂のハードは、WiiUとNew 3DSからSVG対応されています。

PS4とPS Vitaは実機を所有していないため確かめられていないのですが、こちらのサイトによるとSVGに対応とのこと(PS4PS Vita)。

なおXbox系はIEなので省略します。


こうした環境に対して上手く切り分けて、SVGと代替となるPNG画像を適切に表示させたいわけです。


それには様々な手段がありますが、まず最初にダメな例を紹介します

ダメなフォールバックの例

日本経済新聞はダメな例として分かりやすいです。


日本経済新聞ではトップのロゴにSVGを使っています。

<div class="l-header_title">
  <a href="/" id="JSID_TITLE">
    <!--[if lte IE 8]>
      <img src="http://partsa.nikkei.jp/parts/ds/images/common/logo_nikkei_header.png" title="日本経済新聞" alt="日本経済新聞" />
    <![endif]-->
    <!--[if gte IE 9]><!-->
      <img src="http://partsa.nikkei.jp/parts/ds/images/common/logo_nikkei_header.svg" title="日本経済新聞" alt="日本経済新聞">
    <!--<![endif]-->
  </a>
</div>

SVG未対応ブラウザへのフォールバックは条件付きコメントで行っています。

これは古いIE向けであれば有効に機能しますが、IE以外のレガシーな環境に対しては意味がありません。具体的に言えば、Android3未満の環境や3DSなどでアクセスすると代替であるはずのPNG画像も表示されません。

試しに3DSでアクセスした場合

このようにロゴが全くの空欄になってしまいます*1。古いIEのみを対象としたこうしたフォールバックは避けるべきです。



一方、ニューヨークタイムズで行われているフォールバックはこのようになっています。

インラインSVGのimage要素を使ったフォールバック

ニューヨークタイムズもロゴにSVGを使っています。ただしこちらで利用しているのはこうした手法です。

SVGの仕様に無いはずのsrc属性をimage要素に記述しているのが注目ポイントです。

<h2 class="branding">
  <a href="http://www.nytimes.com/">
    <svg class="nyt-logo" width="379" height="64" role="img" aria-label="The New York Times">
      <image width="379" height="64" 
        xlink:href="http://a1.nyt.com/assets/homepage/20151012-175041/images/foundation/logos/nyt-logo-379x64.svg" 
        src="http://a1.nyt.com/assets/homepage/20151012-175041/images/foundation/logos/nyt-logo-379x64.png" 
        alt="The New York Times" border="0">
      </image>
    </svg>
  </a>
</h2>

これはインラインSVGに対応したブラウザはimage要素として表示するの対し、SVG未対応の環境の場合ではimage要素をHTMLのimg要素として扱いsrc属性のPNG画像を表示する仕組みを利用したフォールバックです。

この手法は2013年8月に公開されて以降、その斬新さと適用範囲の広さでSVG界隈では話題になりました。ブラウザ環境を選ばす幅広く使えるのが大きな特徴で、条件付きコメントとは異なりSVG/PNG画像どちらも表示されないという最悪の事態が起きるブラウザは私の知る限りありません。

ただネックなのが、IE9〜IE11ではSVG/PNG画像どちらに対してもリクエストが行われる点です。(参考記事

デモページ

(クリックで拡大)

つまりSVGに対応したIE9〜IE11では必要もないPNG画像が無駄にリクエストされるわけです、これがなければベストな方法なのですが……。*2



これとは逆にレガシーな環境で無駄なリクエストが生じるフォールバックもあります。

SVG未対応の環境で余計なリクエストがあるフォールバック

メジャーリーグのWebサイトでは各球団のロゴがSVGで作られています。

The Boston Red Soxの公式サイトより)

そしてフォールバックはこのように行われています。

<a class="logobar__logo" href="http://boston.redsox.mlb.com/index.jsp?c_id=bos" data-phone-href="http://m.redsox.mlb.com/">
  <img src="/documents/9/6/2/111260962/BOS_header_logo_htojzayw.svg" alt="BOS Wired Logo" 
    onerror="this.onerror=null;this.src='/assets/images/8/1/0/111260810/cuts/BOS_1x_omwx1j3o_7o1v91an.png';">
</a>

SVGに対応していればそのまま表示されますが、SVG未対応のブラウザだとSVGが表示できませんから、エラーがでます。

それをerrorイベントで発火させてPNG画像に書き換える、という手法です。シンプルな構成で記述できるためメジャーリーグの全球団の他、ジャクソンビル市観光局やアメコミ出版社のDark Horse Comicsなど採用例は多いです。

ただこの手法の欠点はJavaScript無効では使えないこと、なによりSVG未対応の環境では

SVGファイル → エラー → PNG画像ファイル

と必ず不要なリクエストが発生する点がネックです。

しかしロゴに一つだけ使うのであれば記述も簡潔で済む点は魅力的な手法ではあります。



ただ複数のSVG画像を配置するケースにはパフォーマンスも低下しますから、JavaScriptライブラリを利用した方が良いでしょう。

JavaScriptを使ったフォールバック

JavaScriptを使ったフォールバックはSVGeezyといったSVGに特化したライブラリもありますが、Modernizrを使うケースが多いですね。

以前にこの記事を書いた際に調査したところ

SVGを使用してる企業・団体のサイトを22ヶ国、160件以上調べてみた

57件でModernizrを利用していました。


Modernizrの使い方はこちらの記事が参考になります。

SVG のフォールバックは結局 Modernizr に落ち着いた件 | WWW WATCH

ここではModernizrでSVG対応状況を判別し、jQueryでimg要素を書き換えてPNG画像を表示させるサンプルが掲載されています。


またModernizrは background-imageで利用する手もあります。

具体的な利用例としては、元国務長官のヒラリー・クリントン氏の公式サイトが分かりやすい使い方で参考になるでしょう。

ヒラリー氏の公式サイトではロゴにSVGを使っていますが、

Modernizrを使っていながらも、JavaScript無効の環境ならばPNG画像が表示されるように構成されています。



このようにJavaScript無効の環境であっても工夫次第で適切なフォールバックは構築できますが、可能ならJavaScriptには依存せずにいたいなー、と個人的に思うわけです。

またbackground-imageでも良いのですが、img要素でも使いたいですし。



srcset属性を使ったSVGフォールバック・ハック

そんなことを考えていたら、先日投稿された、Hail2u.netさんのこの記事が興味深い内容でした

srcset属性を使ったSVGフォールバック・ハック - Weblog - Hail2u.net

srcset属性を使ったSVGのフォールバック(ハック)でシンプルな構成ながら利点の大きい手法です。

<img src="foo.png" srcset="foo.svg">

この方法の利点は3点

  • img要素で使える
  • JavaScriptを使わない
  • 画像のリクエストが1回で済む

レガシーな環境にはsrc属性で示した代替画像が表示され、モダンブラウザではsrcset属性のSVGが表示される仕組みです。

特に他の手法ではおざなりがちだった、不要なリクエストの問題が解決されるのが素晴らしいですね。

ただ欠点は、SVGが表示される対象が狭いこと。

Srcset attribute - Can I use

主だったところでは、SVGに対応しているにもかかわらず

  • IE9〜11
  • Android3〜4
  • WiiU, New 3DS, PS4, PS Vita

これらの環境で代替のPNG画像が表示されてしまいます。

全く何も表示されないよりは良いものの、せっかくSVGが表示できるブラウザなのに、PNG画像になってしまうのは残念ですね。特にIE9〜11、Android4はまだまだ利用者も多いですし。


そこでようやく今回の表題である「Acceptヘッダで判別するサーバーサイドのSVGフォールバック」の話になります。srcset属性を使ったフォールバック(ハック)の利点を活かしつつ、それを補う形でさらにもう一つ別のフォールバックを組み合わせると適用範囲を広げれるのではないか?という実験的な内容です。


すげー長くなりましたが、ここまでが前置きで今からやっと本題です。

Acceptヘッダとはなにか?

それにはHTTPとはなにか?といった説明も必要になってくるのですが、そこまですると余計に長くなってしまうので、すごくざっくりと図で説明するとこんな感じです。

Webサイトを閲覧する際にはブラウザを利用してサーバー側に「貴方のサイトを見たいです」と要求(リクエスト)をします、それに対してサーバー側が返答(レスポンス)を返すことで実際に情報……HTMLや画像が見れるわけです。


もう少し具体的に言えば例えば、img要素の画像に対して

<img src="http://f.st-hatena.com/images/fotolife/r/rikuo/20151014/20151014230634.png" width="590" height="374" alt="">

Firefoxであればこうしたリクエストが送信されます。

Host: f.st-hatena.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:41.0) Gecko/20100101 Firefox/41.0
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: ja,en-US;q=0.7,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://d.hatena.ne.jp/rikuo/20151014
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache

それに対してレスポンスはこのようになります。

Cache-Control:public, max-age=86400, s-maxage=1292
Connection:Keep-Alive
Content-Length:32502
Content-Type:image/png
Date:Fri, 16 Oct 2015 01:59:46 GMT
ETag:"1103437556"
Keep-Alive:timeout=7, max=5
Last-Modified:Wed, 14 Oct 2015 14:07:25 GMT
Server:nginx/1.2.2
Via:1.0 squid.hatena.ne.jp:8080 (squid/2.7.STABLE6)
X-Cache:MISS from squid.hatena.ne.jp
X-Cache-Lookup:HIT from squid.hatena.ne.jp:8080


こうした情報はFirefoxなら

「開発ツール」から


「ネットワーク」を選択して


各項目を選ぶと確認できます。他のブラウザでも開発ツールで確認できます。


そしてリクエストにAcceptという項目がありますね。

Accept: image/png,image/*;q=0.8,*/*;q=0.5

Acceptヘッダはコンテントネゴシエーションという機能の一つで、利用可能なファイルの種類を示すヘッダフィールドです。

これに記載されているimage/pngはPNG画像を示すContent-Typeで、かつて古いブラウザではPNG画像に対応していないことがありました。そのためAcceptヘッダに明記することで、このブラウザはPNGに対応していますよ、とサーバー側に伝えられます。


ちなみにChromeの場合、img要素で送信されるAcceptヘッダはこうなります。

Accept:image/webp,image/*,*/*;q=0.8

PNG画像に未対応な環境は現在はまずありませんから、省略するのは良いとして、今度はimage/webpとWebP画像を示すContent-Typeが含まれていますね。

WebPはGoogleが中心となって普及を進めている画像形式で、ChromeやOperaで利用できます。

WebP image format - Can I use

参考リンク

現状はIEやFirefoxで表示できないためあまり使われていませんが、技術的にはこれを利用してリクエストで送信されるAcceptヘッダで判別して、WebPに対応しているブラウザにはWebP画像を、そうでなければPNG画像を返すこともできます。

参考:WebP - Webを速くするためにGoogleがやっていること Make the Web Faster 01 | HTML5Experts.jp



WebPの話はさておきSVGに話を戻すと、実はSVGでも同じようにAcceptヘッダに記述するブラウザがあります。意外に思うかもしれませんがそれはInternet Explorerです。

Fiddler and the IE9 Release Candidate - Fiddler Web Debugger - MSDN Blogs

主要なモダンブラウザで唯一 Acceptヘッダにimage/svg+xmlと記述しているんですよね、それもIE9〜IE11, Microsoft Edgeで。


IE9〜IE11で img要素の場合に送信されるAcceptヘッダはこうですね。

Accept: image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5


またMicrosoft EdgeではJPEG XRも追加されています。

Accept: image/png, image/svg+xml, image/jxr, image/*; q=0.8, */*; q=0.5


このことを利用することで、つまりこんなことができます。

  • Acceptヘッダにimage/svg+xmlがあればSVGファイルを返す
  • それ以外はPNG画像ファイルを返す

というわけで、具体的にやってみましょう。

ここではApacheのmod_rewriteで設定します。.htaccessにはこのように指定しました。

#Options MultiViewsを無効に
Options -MultiViews

# mod_rewriteを有効に
RewriteEngine on
# ディレクトリが存在せず
RewriteCond %{REQUEST_FILENAME} !-d
# svgファイルは存在する場合に
RewriteCond %{REQUEST_FILENAME}\.svg -f
# AcceptヘッダにSVGが含まれるなら
RewriteCond %{HTTP_ACCEPT} "image/svg\+xml" [NC]
# 条件に合致するなら、svgに
RewriteRule ^(.*)$ $1.svg [L]

# 上記条件以外ならばpngに
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.png -f
RewriteRule ^(.*)$ $1.png [L]

# Vary HTTPヘッダ追加
<FilesMatch "\.(svgz?|png)$">
Header append Vary "Accept"
</FilesMatch>

この例では同じディレクトリに同名のSVG/PNGを配置しています。


設定の意図を説明をすると、普段の使い勝手を考えて

<img src="paint.svg">	<!-- SVGを必ず返す -->
<img src="paint.png">	<!-- PNGを必ず返す -->
<img src="paint">	<!-- Acceptヘッダに応じてSVG/PNGを返す -->

と、拡張子まで記述してあればそれに応じたファイルを(Acceptヘッダに関係なく)返すように設定しています。

その上で、拡張子を省略した場合にはAcceptヘッダにimage/svg+xmlの記述があれば、SVGファイルをそうでなければPNGファイルを返すように指定。


そしてこれは同じURIで異なるコンテンツを返す設定ですから、こうした事例では検索エンジン向けにVary HTTPヘッダにAcceptを追加しておきましょう。


そんなわけでこちらがデモページ

AcceptヘッダでSVG画像を振り分け

(IE11での表示)

Acceptヘッダに応じてSVGとPNGを振り分けます。

現状IE9〜IE11, Microsoft Edgeしか対象となりませんが、将来的に他のブラウザが対応すれば当然SVGが表示されます。ちなみにMicrosoft Edgeの場合はこのようになります。

(クリックで拡大)

Vary HTTPヘッダも記載されています。


ChromeはAcceptヘッダにimage/svg+xmlが含まれないためPNG画像が表示されます。


あと、Firefoxには先ほども紹介した、「開発ツール」から「ネットワーク」で

「ヘッダ」の「編集して再送信」で


要求(リクエスト)ヘッダを書き換えて再送信できる機能があります。

これを使えば手軽にAcceptヘッダを変えられるので、試しやすいかと。



というわけでこの方法と先のsrcset属性の手法と組み合わせたのがこちら。

<img src="paint" srcset="paint.svg">

デモページ

これは

  • srcset属性に対応した最新ブラウザはSVGが表示
  • srcset属性に未対応のブラウザの場合はsrc属性の指定が適用される
    • Acceptヘッダにimage/svg+xmlが含まれればSVG
    • それ以外はPNG画像

という動作になります。

これにより、srcset属性に未対応なIE9〜11でもSVGが表示されるようになりました。

Srcset attribute - Can I use

ただまだ、SVGに対応しているにもかかわらず代替画像が表示されるこれらの環境

  • Android3〜4
  • WiiU, New 3DS, PS4, PS Vita

については依然として解決していません。



そこでさらにもう一つ組み合わせてみました。

WebP画像に対応しているなら、SVGにも対応している……はず

上記で紹介した、WebP画像に対応した環境の表がありますね。

WebP image format - Can I use

WebP画像は

  • Chrome 23以降
  • Opera 12以降
  • Android Browser 4.2以降
  • Chrome for Android 25以降

で対応しています(参考)。

割と新しいバージョンから対応が始まっているわけですが、そのいずれの環境でもWebP画像だけでなくSVGにも対応しているんですよね。

ならば

Acceptヘッダにimage/webpが含まれていれば、SVGも対応しているはず

と言えるわけです。


そこで先ほどの.htaccessの記述をこのように変えてみました

#Options MultiViewsを無効に
Options -MultiViews

# mod_rewriteを有効に
RewriteEngine on
# ディレクトリが存在せず
RewriteCond %{REQUEST_FILENAME} !-d
# svgファイルは存在する場合に
RewriteCond %{REQUEST_FILENAME}\.svg -f
# AcceptヘッダにSVG、またはWebPが含まれていれば
RewriteCond %{HTTP_ACCEPT} "image/(svg\+xml|webp)" [NC]
# 条件に合致するなら、svgに
RewriteRule ^(.*)$ $1.svg [L]

# 上記条件以外ならばpngに
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.png -f
RewriteRule ^(.*)$ $1.png [L]

# Vary HTTPヘッダ追加
<FilesMatch "\.(svgz?|png)$">
Header append Vary "Accept"
</FilesMatch>

デモページ

これで

  • srcset属性に対応した最新ブラウザはSVGが表示
  • srcset属性に未対応のブラウザの場合はsrc属性の指定が適用される
    • Acceptヘッダにimage/svg+xmlimage/webpが含まれればSVG
    • それ以外はPNG画像


という動作を

  • img要素で
  • JavaScriptを使わず
  • 画像のリクエストも1回で完了させる

この条件で設定できました。


しかしながら、これでも

Android3〜4.1ゲーム機
  • Android3〜4.1
  • WiiU, New 3DS, PS4, PS Vita

これらのSVGに対応している環境にPNG画像が表示されてしまう問題は残っており、万全とは言えません。

ですが、

<img src="paint" srcset="paint.svg">

サーバーの設定は多少ややこしいですが、こうした記述でシンプルに書けるようになるのは便利じゃないかなー、と思うんですよね。

というわけで、以上が今回のAcceptヘッダで判別するサーバーサイドのSVGフォールバックでした。



まとめと、良いSVGフォールバックについて

様々なフォールバックの手法の利点と難点を説明・比較しつつ、今回の仕組みの解説を分かりやすく書こうとしたら随分と長い記事になってしまいました。それでもここまで読んでくださってありがとうございます。


最後に良いSVGフォールバックについて考えてみます。

……と言っても、一概に判断するのは難しいので逆に良くないフォールバックを挙げていくと理解しやすいでしょう。今回紹介した日本経済新聞のように代替画像が適切に表示されないのは論外として、良くないフォールバックは閲覧者に不要な負担のかかる手法……余計なリクエストが多用されるもの、JavaScriptなどの処理時間がかかるものが、そうだと言えます。

また制作者側の手間がかかるもの、も良くないフォールバックです。

既存のコンテンツを書き換える手順が複雑なものだったり、またPNG未対応の環境がそうであったように、SVGが表示できないレガシーな環境はいずれ何年かしたら無くなるでしょうから、そうした将来的にWebサイトを再び書き換える手間がかかってしまう手法というのも良いとは言えません。

その点でModernizrを使った手法はimg要素に新たに書き加えるものも少なくて済みますし、将来的にはスクリプトを適用しなければ良いだけなので優れたフォールバックと言えます。JavaScript無効の環境への対応の懸念はありますが。


それと比較して今回提案した、srcset属性&Acceptヘッダでのフォールバックは、閲覧者側・制作者側の両面から見て負担の少ない手法じゃないかな、と考えています。サーバーの設定は少し面倒ですし、JavaScriptライブラリを導入するより大変かもしれませんし、ベストでは決して無いかもしれませんが、そこそこベターな手段かなと。



またこの手法を着想するにあたって、これらの記事を参考に致しました。

後者は2012年の記事ですが、サーバーサイドでのSVGフォールバックの手法は海外のブログでもなかなか見かけないので非常に参考になりました。前者はまさにAcceptヘッダを用いた手法で、このテクニックも他に前例が見当たらない斬新なアイデアで今回の記事を書くに当たり大きく影響を受けました。


今回紹介した以外のSVGのフォールバックの手法についてはこれらの記事がまとまっています



補足などあれこれ

補足1:Acceptヘッダで判別はimg要素以外にも使えるか?

SVGはPNG画像などと同様に、img要素だけでなく様々な要素で使えます、そのいずれでも同じ手法が適用できるか?というと、一概にそうとは言えないんですよね。

Acceptヘッダは要素ごとに異なります、例えばIE11の場合はこのようになります。

img要素image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
CSSimage/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
input要素image/png, image/svg+xml, image/*;q=0.8, */*;q=0.5
embed要素text/html, application/xhtml+xml, */*
iframe要素text/html, application/xhtml+xml, */*
object要素 */*
直接表示text/html, application/xhtml+xml, */*

検証ページ

CSSはbackground-imageやborder-imageで指定した場合、直接表示はSVGファイルをそのまま表示させた場合です。


Microsoft Edge 20
img要素image/png, image/svg+xml, image/jxr, image/*; q=0.8, */*; q=0.5
CSSimage/png, image/svg+xml, image/jxr, image/*; q=0.8, */*; q=0.5
input要素image/png, image/svg+xml, image/jxr, image/*; q=0.8, */*; q=0.5
embed要素text/html, application/xhtml+xml, image/jxr, */*
iframe要素text/html, application/xhtml+xml, image/jxr, */*
object要素 */*
直接表示text/html, application/xhtml+xml, image/jxr, */*


Chrome 45
img要素image/webp,image/*,*/*;q=0.8
CSSimage/webp,image/*,*/*;q=0.8
input要素image/webp,image/*,*/*;q=0.8
embed要素text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
iframe要素text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
object要素text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
直接表示text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

Chromeでは、object要素のtype属性によってAcceptヘッダは変わりますが、ここではimage/svg+xmlを指定した際の値を記載。


Firefox 41
img要素image/png,image/*;q=0.8,*/*;q=0.5
CSSimage/png,image/*;q=0.8,*/*;q=0.5
input要素image/png,image/*;q=0.8,*/*;q=0.5
embed要素text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
iframe要素text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
object要素text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
直接表示text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

このように、要素によってAcceptヘッダは変わるため、img要素以外で利用するのはうまくいかないケースがあります。



補足2:UserAgent文字列を使うのはどうか

リクエストヘッダを利用するにあたりUserAgent文字列は良く使われています。

JavaScriptでも取得できることもあって、スマートフォン用にデザインを変更する際などにも設定しているケースは多いです。

ただ、UserAgent文字列を偽装できるアプリが多いんですよね。

古いAndroid向けのブラウザアプリ、フィーチャーフォン向けのjig browser、さらにはNew 3DSにもUserAgent文字列を変更できる機能がついています。使いやすい一方で、不確かな情報を元に判別するのはなるべく避けたいな、と私は考えています。



補足3:Acceptヘッダの偽装について

AcceptヘッダはUserAget文字列のように偽装ができない、というとそうでもなく上述の通りFirefoxの開発ツールなどで変更してアクセスすることは可能です。

ただ偽装するケースは滅多にないでしょう。



補足4:CSSだけでSVGフォールバック

ちなみにCSSだけで行うSVGフォールバックならCSS Gradientsを活用すると良いです。

div{
  background: url("fallback.png");
  background: url("background.svg"),
    linear-gradient(transparent, transparent);
}

デモページ

この手法はCSS Gradients対応環境とSVG対応環境がかなり似ていることを利用したフォールバックで、ミスマッチも少なくかなり使いやすいです。

SVG/PNGどちらも表示されない最悪の状況はありませんし、SVG対応環境で代替画像が表示されてしまうケースは

  • IE9
  • Android3
  • Opera mini
  • WiiU, New 3DS(PS4, PS Vitaは未検証)

参考:CSS Gradients - Can I use

これらになります。やはりこれだけで完璧というわけではありませんが、シンプルに書けますし使用しやすいでしょう。

*1:alt属性が表示されないのは3DSの問題ではあるのですが

*2:あとはvalidなSVGでなくなる、というのも欠点の一つではあります。

トラックバック - http://d.hatena.ne.jp/rikuo/20151017
Connection: close