Hatena::ブログ(Diary)

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

2015-12-01 SVG未対応ブラウザにおけるインラインSVGの挙動を細かく検証しました

この記事はSVG Advent Calendar 2015への参加記事です。初日の今日は私(id:rikuoid:rikuo)が担当します。

第2日目は@masuPさんが「ラスタ画像を配置したSVGファイルを作成する際に気をつけること | トレンドウォッチ | デジパ株式会社」を投稿されています。

SVG Advent Calendarはまだまだ空きもあるので、気軽にご参加ください。



はじめに

SVGはJPEGやPNG, GIF画像と同じように様々な要素で利用でき、

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

このようにimg要素や


CSSのbackground-imageなどで使えます。

div{
	background-image: url("foo.svg");
}


このときSVGに未対応な古い環境ではどうなるかというと例えばimg要素であれば、何らかの理由で表示に失敗した画像(JPEG, PNG, GIF画像など)と同様に代替テキストが表示されるだけで、SVGだからといって特別変わった挙動をするわけではありません。


しかしSVGは画像ファイルという側面もありますが、実態はXMLを基盤にした画像記述言語ですから、HTML5では直接HTML内に記述するインラインSVGが使えます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>タイトル</title>
</head>
<body>
<svg width="200" height="200">
	<path d="m101 174c-8-1-29-7-51-24-25-19-42-54-42-77 0-26 14-50 48-50 21 0 32 14 38 23 3 4 4 7 6 10 1 1 1 1 2 0 2-3 3-6 6-10 7-10 18-23 38-23 34 0 48 24 48 50 0 23-17 58-42 77-22 17-43 23-51 24z" fill="#ff9fcb"/>
</svg>
</body>
</html>

こうした記述の仕方はJPEG, PNG, GIF画像などとは異なりSVG独特の利用方法です。

そんなインラインSVGをSVG未対応の古いブラウザではどのように扱うのか?といったところをこの記事ではまとめてみました。


……なぜなら、img要素のようにシンプルな挙動では無いんですよね。



検証した環境

手元にあるSVG未対応のこれらの環境で検証しました。

  • Xperia acro(SO-02C) - Android 2.3
  • Nintendo DSiブラウザー - Opera 9.5(Presto)
  • Nintendo 3DSブラウザー - NetFront Browser(WebKit)
  • PSP go - NetFront

残念ながらInternet Explorer8は実機で試せる環境が無かったために

  • IE11の開発ツールのエミュレータ

と一応、参考としてWindows98SEのIE6でも動作の確認を行っています。


なお、SVG未対応の環境として最も多くの割合を占めていたIE8については来年1月にサポート終了が決定しています。

2016年1月12日より、Internet Explorer のサポートポリシーが変わります | Windows Blog for Japan


あわせて2015年10月時点でのSVG未対応ブラウザシェア状況を調べた記事も参考として

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

現状、9割近い環境でSVGへの対応がされていますから、実際問題 今回のノウハウはあまり役に立たないのですが、良い機会なのでここでまとめておこうと思った次第です。

簡易目次


ほとんどの要素は描画されない

SVG*1の仕様では80の要素が規定されています

その内の71の要素についてはSVG未対応ブラウザでは何も表示されません。*2

altGlyph, altGlyphDef, altGlyphItem, animate, animateColor, animateMotion, animateTransform, circle, clipPath, color-profile, cursor, defs, ellipse, feBlend, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDiffuseLighting, feDisplacementMap, feDistantLight, feFlood, feFuncA, feFuncB, feFuncG, feFuncR, feGaussianBlur, feImage, feMerge, feMergeNode, feMorphology, feOffset, fePointLight, feSpecularLighting, feSpotLight, feTile, feTurbulence, filter, font, font-face, font-face-format, font-face-name, font-face-src, font-face-uri, g, glyph, glyphRef, hkern, line, linearGradient, marker, mask, missing-glyph, mpath, path, pattern, polygon, polyline, radialGradient, rect, set, stop, svg, switch, symbol, textPath, tref, tspan, use, view, vkern

SVG未対応の環境ですから表示されないの当然ですし、以降で紹介する他の要素とは異なり中途半端に表示されないのである意味扱いやすいとも言えます。


テキストノードは描画される

desc要素、metadata要素、text要素*3などの要素で記述されたテキストノードはSVG未対応ブラウザではそのまま表示されます。

<svg width="200" height="50" viewBox="0 0 200 50">
	<title>title要素の文字列</title>
	<desc>desc要素の文字列</desc>
	<text x="20" y="35" font-size="20" fill="blue">text要素の文字列</text>
</svg>

デモページ


(Internet Explorer11でのスクリーンショット)


(開発ツールによるIE8のエミュレーション)


特にdesc要素やmetadata要素はSVGに対応した環境であれば表示されない要素のため、意図しない情報が画面に現れてしまうことになります。


title要素は「HTMLのtitle要素」として扱われる

title要素もテキストノードなのですが、この場合はHTMLの同名のtitle要素として扱われます。例えばこのように、HTMLのtitle要素をわざと記述しない場合の挙動が分かりやすいでしょう。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<style>
	svg{
		border: 1px solid #444;
	}
</style>
</head>
<body>
<h1>インラインSVGの検証 - HTMLのtitle要素が無い場合の挙動</h1>
<svg width="200" height="50" viewBox="0 0 200 50">
	<title>title要素の文字列</title>
	<desc>desc要素の文字列</desc>
	<text x="20" y="35" font-size="20" fill="blue">text要素の文字列</text>
</svg>
</body>
</html>

デモページ


(Internet Explorer11でのスクリーンショット)


(開発ツールによるIE8のエミュレーション)

ブラウザのタイトル部分に、インラインSVG内の「title要素の文字列」が表示されているのが確認できます。


ですが通常であればHTMLのtitle要素が記述されているはずなので、その場合は重複したHTMLのtitle要素として扱われ、無視されます。


a要素は「HTMLのa要素」として扱われる

a要素もHTMLで同名のa要素として扱われます。SVGに未対応な環境ではXLink名前空間宣言を扱えないため、リンク先へ移動することはできませんがHTMLのa要素へ書いたスタイルシートが適用されます。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>インラインSVGの検証 - リンク</title>
<style>
	svg{
		border: 1px solid #444;
	}
	a{
		text-decoration: underline;
		color: red;
	}
</style>
</head>
<body>
<h1>インラインSVGの検証 - リンク</h1>
<svg width="200" height="50" viewBox="0 0 200 50">
	<a xlink:href="http://google.com/"><text x="20" y="35" font-size="20" fill="blue">リンク文字列</text></a>
</svg>
</body>
</html>

デモページ


(Internet Explorer11でのスクリーンショット)


(開発ツールによるIE8のエミュレーション)


image要素は「HTMLのimg要素」として扱われる

image要素は画像ファイルなどを表示できるSVGの要素ですが、これをSVG未対応のブラウザはimg要素として扱います。

<svg width="262" height="160" viewBox="0 0 262 160">
	<image xlink:href="photo.jpg" x="0" y="0" width="262" height="160"/>
</svg>
svg{
	border: 2px solid #444;
}
img{
	border: 2px solid red;
}

デモページ

前述の通りXLink名前空間接頭辞をSVG未対応の環境では適切に扱えないため、img要素として扱われたimage要素はそのままでは画像を表示できません。

(Internet Explorer11でのスクリーンショット)


(開発ツールによるIE8のエミュレーション)

xlink:hrefで指定した画像は表示されていませんが、img要素へ設定したCSSが適用されているのが分かります。



この挙動は他の要素と大きく異なるため厄介ではありますが、これを敢えて利用したfallbackもあります。

参考記事:SVG and <image> tag tricks

<svg width="150" height="150">
	<image xlink:href="foo.svg" src="foo.png" alt="代替テキスト" width="150" height="150"/>
</svg>

デモページ

SVGに対応したブラウザならSVGファイルが表示され、またSVG未対応のブラウザだとimg要素として扱いsrc属性のフォールバック画像を表示する仕組みです。

(Internet Explorer11でのスクリーンショット)


(開発ツールによるIE8のエミュレーション)


ちなみにDSi, 3DS, Android2.3.xではSVG要素にborderが設定してあるとこのようになります。


実際の使用例としてはニューヨークタイムズでこの手法を使ってフォールバックを行っています。

image要素へのsrc属性の指定はSVGの仕様上 規定されていませんからvalidではなくなるものの、SVG未対応のブラウザではalt属性もきちんと機能するため実用的な手法ではあります。


foreignObject要素とは

foreignObject要素はSVG以外の名前空間のものを含められます。

具体的には例えばp要素やspan要素などHTMLの要素をforeignObject要素内では記述できます。

<svg width="300" height="75" viewBox="0 0 300 75">
	<foreignObject width="300" height="75">
		<p>HTMLのp要素の文字列。このように長い文章の場合も折り返して表示されます。</p>
	</foreignObject>
</svg>

デモページ

SVG未対応のブラウザの場合は、foreignObject要素自体は描画されませんが子要素はそのまま表示されます。

(Chrome46でのスクリーンショット*4


(開発ツールによるIE8のエミュレーション)


そこでこれを利用したフォールバックの手法もあります。

<svg width="300" height="75" viewBox="0 0 300 75">
	<path d="..."><!-- 画像などのデータ -->
	<foreignObject width="300" height="75" display="none">
		<p>フォールバックの文字列</p>
	</foreignObject>
</svg>

これは

SVGに対応したブラウザでは

path要素などの図形を表示して、display=noneなforeignObject要素を含む子要素も表示しない

SVGに未対応なブラウザは

path要素などは表示できず、foreignObject要素も表示しないが子要素は表示する


という動作になります。

利用例としてはこちらの記事が分かりやすいでしょうか

SVGの利用 - to-R


style要素、script要素の扱い

インラインSVG内で記述されたstyle要素、script要素は、SVG未対応ブラウザではそれぞれHTMLの要素として扱われます。

HTMLの要素と共通のCSSというのは少ないため、これによる不具合はあまり無いと思うのですが、一応頭の片隅にでも気に留めておくと良いでしょう。


まとめ

以上、SVG未対応のブラウザでのインラインSVGの挙動についてまとめてみました。

なお同じSVG未対応の環境でも各ブラウザによってボックスモデルの差異などはあるものの、基本的にはほとんど変わらない動作をしています。


インラインSVGが全て表示されない、というのならばまだ良いのですが、desc要素などSVG対応のブラウザでは表示されないはずの要素が画面に出てしまうのは戸惑いやすい部分ではあります。

また最初にも書きましたが、現在SVGに対応した環境は9割近く普及しており、そして来年1月にはIE8のサポート終了も決まっています。それを鑑みるとこうした知識やノウハウは徐々に必要なくなってきそうですね。

*1:ここでは特に明記しない限り、原則SVG 1.1 Second Editionの仕様に基づいて書いています

*2:SVGに対応したブラウザでも表示しないdefs要素なども含めてカウントしています

*3:tspan要素などは単独で使うことがないため、描画されないグループに含めました

*4:IEではforeignObject要素の子要素がうまく表示されないため

トラックバック - http://d.hatena.ne.jp/rikuo/20151201