HTML5でのSVGファイル操作のおさらい

最近、HTML5でベクターグラフィックスを取り扱う時にSVG形式のファイルを利用しているWEBサイトが増えて来ている。iOS系のデバイスが超高解像度のRetinaディスプレイを採用しているので、PCサイト向けに準備した800×600や1024×740といった大きめな画像でも、Retina端末で見るとぼやけてしまうという状況になったのが原因かもしれない。この状況でRetinaディスプレイでも綺麗に見れる高精細な画像を提供しようとすると、今度はファイルサイズが肥大化して、トラフィック側に悪影響が出るというジレンマに悩まされる。それらを解決すべく利用が進んだのがSVG形式のベクター画像だ。
数年前、SVGGirlとかいうコンテンツが流行っていた時は、まだSVG形式のファイルを利用できるブラウザが少なかったんだが、今どきのモダンブラウザは普通の画像ファイルと同じ感じに簡単に取り扱えるようになった。
今後、SVGファイルの取り扱いが増えそうな感じがするので、ここでおさらいしておこうかと思った次第。


### SVG形式のファイルをHTMLで表示する方法
- - -
* **&lt;IMG&gt; を使う** ─ HTMLのIMGタグにSVGファイルを直接指定するやり方。

```html:
<img src="logomark.svg" width="32" height="32">
```

* **CSSを使う** ─ CSSの`background-image`プロパティで背景画像として指定するやり方。

```css:
<div style="width:32px; height:32px; background-image:url(logomark.svg); background-size:100%;"></div>
```

* **&lt;SVG&gt; タグを使う** ─ HTML内に（インラインで）直接SVGタグでベクターパスを指定して描画するやり方。

```html:
<svg id="logomark" x="0px" y="0px" width="155px" height="155px" viewBox="0 0 155 155" enable-background="new 0 0 155 155">
  <polygon id="logomark-polyline" fill-rule="evenodd" clip-rule="evenodd" fill="#0CB9C7" points="128.25,26 147.19,96.69 95.44,148.44 24.75,129.5 5.81,58.81 57.56,7.06 "/>
</svg>
```

* **&lt;OBJECT&gt; タグを使う** ─ HTMLのOBJECTタグでSVGファイルを埋め込むやり方。

```html:
<object type="image/svg+xml" data="logomark.svg" width="256" height="256"></object>
```

どの表示方法も現在のモダンブラウザで利用可能なので、表示するだけなら、お手軽にIMGタグやCSSを使うのがベストだろう。ただ、マウスオーバー時やクリック時にイベントを拾ってSVG形式のスタイルを変更したい場合などは、各ブラウザで挙動が異なる。

**SVG形式ファイルの各ブラウザの対応状況**

| 表示手法 \ ブラウザ | Chrome | Safari | Firefox | Opera | IE11 |
|-----------|----------|---------|----------|---------|---------|
| &lt;IMG&gt; で表示 | ○ | ○ | ○ | ○ | ○ |
| CSSで表示（読込み型） | ○ | ○ | ○ | ○ | ○ |
| CSSで表示（インラインスタイル） | ○ | ○ | ○ | ○ | ○ |
| インライン&lt;SVG&gt; で表示 | ○ | ○ | ○ | ○ | ○ |
| インライン&lt;SVG&gt; ＋ JavaScript操作 | ○ | ○ | ○ | ○ | ○ |
| &lt;OBJECT&gt; で表示 | ○ | ○ | ○ | ○ | ○ |
| JavaScript埋込型SVG ＋ &lt;OBJECT&gt; | ○ | ○ | × | × | × |

IMGタグやCSSで表示してしまうと、表示されたSVG形式ファイルに対してJavaScript等で一切操作ができないので、インラインSVGタグとして埋め込むか、イベントハンドラ処理のJavaScriptをSVG（XML文書）内に直接埋め込んだSVGファイルをOBJECTタグで埋め込むかの二択になる。
しかし、JavaScript埋め込み型SVGファイルのOBJECTタグでのイベント発動に対応しているのは現時点でChromeとSafariのWebkit系ブラウザだけなので、クロスブラウジングを考えるのならインラインSVGタグ＋JavaScriptというセットが無難である。ただ、このインラインSVGタグの方法はHTMLの可読性を著しく下げるので避けたいところなんだが…今のところどうにもならない。

ちなみに、JavaScriptでSVGファイルのスタイルを変更する例を下記に紹介しておく。私のサイトの元記事では、128x128と256x256のサイズのSVG画像はマウスを上に乗せると色が変わるようなJavaScriptを書いてあったんだけど、QiitaにはSVG形式のファイルをアップロードできず、本文内のscriptタグ等の動作が制限されていたので、便宜的にこの表の画像は私のサイトからすべて&lt;img&gt;タグで読み込んでます。そのため、JavaScriptでのマウスオーバーイベントなどは動かなくなってます。もし実際の挙動を確認したい場合は、[私のサイトの元記事](https://ka2.org/controll-svg-files-by-html5 "HTML5でのSVGファイル操作のおさらい")をご覧いただけると助かります。

<table>
<tr>
<td style="vertical-align: middle; text-align: center;">
	<img src="http://ka2.org/assets/official/ms_logomark.svg" width="16" height="16" style="border:0">
</td>
<td style="vertical-align: middle; text-align: center;">
	<img src="http://ka2.org/assets/official/ms_logomark.svg" width="32" height="32" style="border:0">
</td>
<td style="vertical-align: middle; text-align: center;">
	<img src="http://ka2.org/assets/official/ms_logomark.svg" width="64" height="64" style="border:0">
</td>
<td style="vertical-align: middle; text-align: center;">
	<img src="http://ka2.org/assets/official/ms_logomark.svg" width="128" height="128" style="border:0">
</td>
<td style="vertical-align: middle; text-align: center;">
	<img src="http://ka2.org/assets/official/ms_logomark.svg" width="256" height="256" style="border:0">
</td>
</tr>
<tr>
<td align="center" style="font-size: 14px;">&lt;IMG&gt;<br>(16x16)</td>
<td align="center" style="font-size: 14px;">&lt;IMG&gt;<br>(32x32)</td>
<td align="center" style="font-size: 14px;">inline style<br>(64x64)</td>
<td align="center" style="font-size: 14px;">&lt;SVG&gt;<br>(128x128)</td>
<td align="center" style="font-size: 14px;">&lt;OBJECT&gt;<br>(256x256)</td>
</tr>
</table>

さて、上記の表の画像部分のソースをそれぞれ書き出してみると、

```html:IMG(16x16)
<img src="http://ka2.org/assets/official/ms_logomark.svg" width="16" height="16">
```

```html:IMG(32x32)
<img src="http://ka2.org/assets/official/ms_logomark.svg" width="32" height="32">
```

```html:InlineStyle(64x64)
<div style="width: 64px; height: 64px; background-image: url(http://ka2.org/assets/official/ms_logomark.svg); background-size: 100% 100%; background-repeat: no-repeat;"></div>
```

```html:SVG(128x128)
<svg id="inline-monaural-sound-logomark" x="0px" y="0px" width="155px" height="155px" viewBox="0 0 155 155" enable-background="new 0 0 155 155">
  <polygon id="inline-ms-logomark-line" fill-rule="evenodd" clip-rule="evenodd" fill="#0CB9C7" points="128.25,26 147.19,96.69 95.44,148.44 24.75,129.5 5.81,58.81 57.56,7.06 "/>
  <path id="inline-ms-logomark-mask" fill-rule="evenodd" clip-rule="evenodd" fill="#FFFFFF" d="M142.21,78.07l-8.35-31.14c-1.28-1.4-2.49-2.54-3.63-3.42c-2-1.54-4.85-2.33-8.59-2.33c-4.11,0-7.45,1.02-9.99,3.06c-2.57,2.04-3.82,4.69-3.82,7.89c0,2.79,1,5.24,3.02,7.36c2.03,2.16,5.77,4.17,11.22,6.09c5.42,1.92,9.67,3.87,12.69,5.85C137.79,73.44,140.27,75.65,142.21,78.07z M106.08,84.88v4.59c0,11.6,4.86,17.36,14.62,17.36c4.31,0,7.72-1.54,10.27-4.63c2.33-2.85,3.59-6.7,3.77-11.52c-0.32-1.22-0.8-2.44-1.43-3.67c-1.26-2.45-2.83-4.46-4.71-6.03s-5.22-3.2-9.96-4.86c-3.37-1.16-6.22-2.32-8.53-3.48c-0.92-6.58-3.5-12.08-7.76-16.54c-2.15-2.27-4.58-4.08-7.27-5.44c0.29-5.52,2.7-10.3,7.3-14.28c4.91-4.25,10.84-6.38,17.83-6.38c3.14,0,6.31,0.49,9.51,1.48L128.25,26L57.56,7.06L5.81,58.81l3.9,14.55c1.1-5.18,3.47-9.64,7.08-13.38c5.17-5.35,11.79-8.03,19.82-8.03c8.21,0,14.86,2.68,19.93,8.03c0.37,0.39,0.73,0.78,1.08,1.19c0.35-0.41,0.71-0.8,1.09-1.19c5.17-5.35,11.79-8.03,19.82-8.03c8.21,0,14.86,2.68,19.93,8.03c5.1,5.35,7.62,12.31,7.62,20.95V84.88z M100.46,111.97c-4.27-4.48-6.73-10.08-7.42-16.87l-0.2,0.04v-4.12v-6.14v-2.4c0-11.6-4.86-17.36-14.62-17.36c-4.31,0-7.72,1.55-10.27,4.63c-2.52,3.09-3.79,7.34-3.79,12.73V120H50.92V82.48c0-11.6-4.86-17.36-14.62-17.36c-4.31,0-7.72,1.55-10.27,4.63c-2.52,3.09-3.79,7.34-3.79,12.73V120H22.2l2.55,9.5l70.69,18.94l28.64-28.64c-1.19,0.13-2.43,0.2-3.69,0.2C112.18,120,105.53,117.32,100.46,111.97z"/>
  <polygon id="inline-ms-logomark-stroke" fill-rule="evenodd" clip-rule="evenodd" fill="none" stroke="#7D7D7D" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points="128.25,26 147.19,96.69 95.44,148.44 24.75,129.5 5.81,58.81 57.56,7.06 "/>
</svg>
<script>
var svg_img = document.getElementById('inline-monaural-sound-logomark');
svg_img.setAttribute('width', '128');
svg_img.setAttribute('height', '128');
svg_img.onmouseover = changeHoverColor;
svg_img.onmouseout = changeDefaultColor;
function changeHoverColor() {
	document.getElementById('inline-ms-logomark-line').setAttribute('fill', '#FFFFFF');
	document.getElementById('inline-ms-logomark-mask').setAttribute('fill', '#0CB9C7');
	document.getElementById('inline-ms-logomark-stroke').setAttribute('stroke', '#0CB9C7');
}
function changeDefaultColor() {
	document.getElementById('inline-ms-logomark-line').setAttribute('fill', '#0CB9C7');
	document.getElementById('inline-ms-logomark-mask').setAttribute('fill', '#FFFFFF');
	document.getElementById('inline-ms-logomark-stroke').setAttribute('stroke', '#7D7D7D');
}
</script>
```

```html:OBJECT(256x256)
<object type="image/svg+xml" data="http://ka2.org/assets/official/ms_logomark.svg" width="256" height="256"></object>
```

──となる（というHTMLで実表示させて例示したかった）。

中でも、とりわけ最後のOBJECTタグ型の呼び出しは使い勝手が非常に良い。
というのも、SVGファイル内に画像自体のイベントは全て埋め込んでおいて、HTML側ではOBJECTタグで呼び出すだけでその画像に対してのイベントは考えなくていいという、今どきで言うと「Web Components」的なやり方が、HTML側の可読性を全く損なわずにSVG画像を利用できるからだ。
個人的にもすごく気に入っているので、ぜひ他のブラウザもこのやり方ができるようにしてもらいたいものだ。