svg要素の基本的な使い方まとめ

Written by defghi1977@xboxLIVE.この文書は全てテキストエディタで作成しています.えーと,そりゃもうゴリゴリと.

2.svg要素とsvg文書

svg画像を描くにはまずsvg要素について知っておく必要がある.ここでは最も基本のsvg要素の使い方について示し,svg画像をhtmlに挿入する様々な方法について説明する.また,svgを手書きする場合の注意点について述べる.

序・svgの構成

前のセクションでsvgの特色については理解できたはずなので,ここからは実際のsvgの構成について見ていくこととする.これまで何度も出てきたようにsvgはxmlで定義された2次元画像記述言語である.ここで「xmlで定義された」とはxmlの基本的な仕様,つまりテキストをベースとした文書である.様々なデータはツリー構造で表される.タグ(要素)と属性と呼ばれる機構でデータに意味付けを行う.に準拠している事を指す.かいつまんで言うとsvgはxmlである†

その上で,svgでは独自に定義したタグ名,属性名にグラフィック描画に必要となる色や処理等を対応付けている.従ってsvgを学ぶということは,このタグ名・属性名の意味合いを理解することに他ならない.

†正確には「svgファイルはxmlファイルである」.

※因みにhtmlはxmlではない.記述法こそ似ているが,htmlはxmlほどの厳密さを持たない.なお,このhtmlをxmlで再定義したもの(xml形式にコンパイルしたもの)がxhtmlである.

それではどのような要素が存在するのか?カテゴリ毎にざっと見てみよう.

この他にも便利な機能を提供する要素は沢山定義されている.初めてsvgに触れると言う人には数が多すぎて目眩がするくらいだろう.だが,これらを全て理解せずとも別に構わないと思う.svgは余りにも汎用的に設計されている節があるため,どうしても仕様が大きくなってしまっているのだ.逆に言えば,全ての仕様を同時に利用せざるを得ないような場面はそもそも存在しないものと思われる.現に最新のwebブラウザにおいてもサポートしている機能にばらつきがあったり,利用できない要素が存在している.これはブラウザに不備があると言うよりも,svgをブラウザで表示する場合にはそれほど重要ではないということなのだ.もちろん,その要素が他の用途(例えば印刷用途など)で重要な役割を果たすことは考えられる.

このようなことから,自分の興味の範囲で好きなところから触れてみるというのがsvg上達への早道かと思われる.確かに便利な機能が多数提供されているが,それらを知らずともsvgには様々な代替手段が提供されているので,意外と何とかなるのが面白いところだ.

以下,svgを構成する上で最も基本となるsvg要素から順に,様々な要素の意味合いについて見ていくこととする.

svg:ベクタ画像のカンバスの定義,title:タイトル,desc:説明

html文書においてsvg画像を挿入したい場合,iframe要素を用いるembed要素を用いるobject要素を用いるimg要素を用いるinput要素(イメージボタン)を用いるbackground-imageに設定する.svg要素を用いるのいずれかを選択することとなる.(1)〜(6)は外部svgファイルによるもので,(7)はhtml5から導入されたものだ.svg要素を用いると(x)html文書内にsvg記述をシームレスに埋め込むことが出来る.なお,svgによるグラフィックは複雑になるほど,その記述量が爆発的に増加する傾向があるため,実現したい要件に対してどの方法が最も適したやり方か予め検討する必要がある.

インラインでのsvgの表示

(7)を用いる場合はHTML5を用いることをブラウザに明示的に知らせるため,ドキュメントタイプ宣言に「<!DOCTYPE html>」を指定すること.それ以外では場合によりsvg要素が表示されない可能性がある.

実際にコードを記述してみよう.下記の内容をHTMLファイルの中に記述してインラインsvgに対応したブラウザで開くと,画像が表示されるはずだ.svgを学ぶにはサンプルを眺めるよりも実際にコードを弄ったほうが効果的だ.なお,svgはxmlで定義された言語であるため,要素名・属性名の大文字・小文字は混同してはならない.html埋め込みのsvg要素の場合は多少の間違いがあってもグラフィックが描画されてしまうが,これはブラウザが勝手に解釈しているだけなので,標準的な記法ではない事を憶えておこう.

svg要素はHTMLの世界とsvgの世界の境目となる要素で,この配下には原則としてsvgで定義された要素のみ記述できる(原則とあるのは,html要素を含める方法があるため).なおa要素のように名称が同じでも内部的に(名前空間が)異なるものとして処理されるものがあるので注意しよう.

svg要素におけるwidth,height属性はhtml要素のそれと同じくブラウザ(ユーザーエージェント)上での表示のサイズを表す.単位にはem,ex,px,pt,pc,cm,mm,in,%が利用可能である.この他一般のスタイル属性を指定することも可能で,img要素と同等に取り扱うことが出来る.一方,svgの内部の要素にはsvgに由来するスタイルが適用される.

なお一般的な画像ファイルが暗黙的に描画サイズが決定されるのに対し,svgにおいてはwidth,height属性を指定しなかった場合,サイズ不定のグラフィックとなる.つまり,htmlファイルと同様に表示サイズに応じた描画を行うことも可能である.

viewBoxによる表示範囲の指定

viewBox(min-x,min-y,width,height)(単位は無し)属性はsvg固有のものであり,記述した図形の座標系と表示範囲(ビューポート)を定義するものである.svg要素の左上の座標を(x,y),右下の座標を(x+width,y+height)に割り当てる.なお,外部表示サイズとviewBoxのサイズとでアスペクト比が異なる場合,後述するpreserveAspectRatio属性にて描画方法を指定することができる.幅,高さ,viewBox属性のいずれも設定されていない場合,暗黙的に(0,0,表示上の幅,表示上の高さ)として扱われる.

viewBoxのサンプル1 viewBoxのサンプル1 circle要素の属性値が同じ点に注目

付加情報の挿入

title要素では画像のタイトルを設定する.この内容はスタンドアロンのsvg文書であればウインドウのタイトルとして利用され,埋め込みsvg要素であればカーソルを当てた際に表示されツールチップとして表示される.また,図形要素の子とした場合はその図形のタイトルを表す.

desc要素では画像に対する説明を記述する.また,図形要素の子とした場合はその図形に対する説明を表す.これらの要素はグラフィックのレンダリングには影響を及ぼさないが,スクリーンリーダーや,google等の検索エンジンからは参照されうる.なお,ソースコードとしてのコメントは「<!---->」で記述する.

svg要素の中に各種図形を表す要素(例えばpath要素や,rect要素)を記述していく.htmlとの違いとしては図形の描画順は全て要素が現れた順である.htmlにおけるz-indexのような描画順を変更するようなものはなく,先に現れた図形から順に下から上に重ねられていく.スクリプトを記述する際もこの原則に従う必要がある.

width
カンバス幅(単位はpx,cm,%…).htmlではsvg要素のレンダリング幅と同じ.
height
カンバス高(単位はpx,cm,%…).htmlではsvg要素のレンダリング高と同じ.
xmlns
svgの名前空間(固定).html5であればsvg要素はsvgに決まっているので,記述の必要はない.なおxhtml5やスタンドアロンのsvgファイルを記述する際は,加えてxlinkの名前空間を定義しておく必要がある.参考のため主な物を示す.
svg
http://www.w3.org/2000/svg
xlink
http://www.w3.org/1999/xlink
xsl
http://www.w3.org/1999/XSL/Transform
xhtml
http://www.w3.org/1999/xhtml
mathml
http://www.w3.org/1998/Math/MathML
smil
http://www.w3.org/ns/SMIL
viewBox
図形の表示範囲.x y width heightの順に記述する.
zoomAndPan
svg図形がズーム(拡大縮小)・パン(表示範囲の移動)の操作を許すか否か.ブラウザによってはctrl+plusキー,ctrl+minusキーにより図形の拡大・縮小を行えるが,この操作を許すかどうか.余り使わない属性かもしれない.
disable
行わない
magnify
行う
contentScriptType
要素のonXXX属性に記述するスクリプトの言語を指定する.application/ecmascriptが規定値で,これはつまりjavascriptの事なので,規格上は存在するものの現実的にはそれほど意味のない属性.
contentStyleType
要素のstyle属性に記述するスタイル指定言語を指定する.text/cssが規定値.滅多に用いることはなく,実際将来的に削除される予定である.
baseProfile
言語プロファイルの指定.埋め込みsvgであれば必要ない.
none
=full
fill
svg(full)
basic
svg basic
tiny
svg tiny
version
バージョン1.1.現状1.0,1.1,1.2(svg tiny 1.2)のいずれか.埋め込みsvgなら必要ない?

入れ子になったsvg要素

svg要素は入れ子にして利用することもできる.グラフィックの一部に新たなviewBoxを定義して図形を描画したい場合に用いる.

グラフィック描画の基準を変更する

htmlにおいてはcssのrightやbottomプロパティにより図形の描画を右辺や下辺を基準に行うことができる.通常svgでは左上を基準としたグラフィックを描画するが,入れ子のsvg要素を用いるとsvgにおいても任意の位置を基準にグラフィックを描くことが可能となる.このテクニックを用いると,ウインドウをリサイズした時に右端や下端に図形が沿うといった動作を実現できる.

補足)svg文書片とは

svgの表す意味を文章内で明確にする目的でsvg文書片という用語を使う場合がある.これはsvg要素を頂点としたグラフィック要素ツリーの全体を指し,この定義を使ってここまでの内容をまとめると次のようになる.

svgの記述ミスを少なくするために

先にsvgは画像を記述すためのスクリプト言語的な側面があると書いた.本文書ではそのsvgを手入力で構築して行こうというのが主な目的であるため,一般のプログラム言語と同様に記述ミスの危険性を常に孕む.つまり,1箇所のタグの記述間違いが致命的な問題を引き起こす場合が多々あるのだ.svgはxmlで定義されている言語であるから,原則xmlにおける文法に従わなければならない.しかし普段htmlに慣れ親しんだユーザーなら次のようなケースにはかなり遭遇してきたはずだ.

全てxmlにおいてエラーとなる記述であるにもかかわらず,htmlの場合は(多少のレイアウトの崩れを生じるものの)何の問題もなくブラウザで表示できてしまう.特に一つ目はは<br>要素等,そもそも右閉じ部の"/"を必要としないものもある.だが,同じことをsvg要素に当てはめてしまうと,意図した図形が全く表示できないと言った問題を引き起こす.ブラウザ側である程度勝手に要素を解釈するというhtmlのもつ柔軟性がかえって仇となってしまうのだ.これは単純に見えて非常にやっかいな問題である.というのも,svgはhtmlと比較しても記述が複雑となりがちな面があり,自ずと記述する要素の数・種類共に膨大な量となる.従って,問題のある箇所を探すのが一苦労なのだが,その際にこれまで慣れ親しんだタグの記法が問題の原因となりうると言われたら,どのように対処すべきというのか?

実際,この文書を作成することで,非常に長い文書に多数のsvg要素を埋め込むと,管理上非常に不味い問題を引き起こすことがわかった.図形の描画に問題のあるsvg要素自体に記述ミスはなく,それ以前の正常に描画されているsvg要素に先程の不具合の原因となるコードが含まれていたというケースに実際に遭遇した.これは,グラフィック描画における問題点の切り出しが非常に困難であることを示している.

常日頃から正しいコードを記述することに気をつけるのも結構だが,人間の作業である以上ふとしたきっかけで問題のあるコードを記述してしまうのは避けられない.ではその間違いを機械的に判別してくれる機構は無いのだろうか? javascriptに導入された"use strict"宣言のようにである.結論から言うと,ある.主に次の2つの方法である.

  1. スタンドアロンのsvgファイルを利用する.
  2. 文書そのものをxhtmlで作る.

このようにしておいてxmlのエラーチェック機構を利用するのである.svg,xhtmlは何れもxmlで定義されている言語である.よって記述に問題のあるファイルをブラウザで表示しようとするとエラーとなり,問題のある箇所を明示できるのだ.このことでsvg構文の修正が容易となり,問題のある描画の原因から構文の記述ミスを除外できる.

スタンドアロンsvgファイルについて

スタンドアロンのsvgファイルは,単体でブラウザ表示可能なsvg画像ファイルを指す.この内容をhtml5文書にそのまま挿入してもほとんどのケースで埋め込みsvg要素として動作する.スタンドアロンのsvgファイルを作る場合は,テキストエディタで下記のコードをテンプレートとして保存しておくと良いだろう.

<?xml version="1.0" standalone="no"?>
<svg width="100px" height="100px" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
</svg>

作り方は埋め込みsvgと全く同じだが,xmlに準じた記述を行う必要がある.ここで単体のsvgファイルとして動作確認をした上でhtml文書にimg要素やiframe要素・object要素などで画像を埋め込むのだ.文書と画像が完全に分離しているため,コードの健全性を保つと言った面で有効な方法である.

複数の文書に分かれることを嫌うなら,html文書の編集の際にsvg要素単位でsvgファイルに書き出し,もとの文書にコピーする(埋め込む)と言った方法も考えられる.この場合,svg要素間でidが重複しやすい点に注意する事と共に,絶対にhtml文書内で直接svg要素を編集してはならない.必ずスタンドアロンのファイルとして動作確認を行うこと.

xhtmlにおけるsvg画像の埋め込みについて

xhtml(eXtensible HyperText Markup Language)はhtmlをxmlによって再定義したもので,先のスタンドアロンのsvgファイルと同様,記述ミスを構文エラーとして扱える.文書全体がxmlとして扱われるため,これまで正しかった一部の構文が不正なものとして扱われるようになる.よって,既にhtmlで運用している文書をxhtmlに移行するのは現実的ではない.一方,htmlでの曖昧さがxhtmlでは存在しないためか,ブラウザにおけるsvgの動作が良くなるケースが見受けられた.以下に例を示す.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink">
    <head>
        <title>サンプル</title>
        <style><![CDATA[
            body{
                margin:0;
            }
            svg{
                border:2px outset black;
            }
        ]]></style>
    </head>
    <body>
        <svg xmlns="http://www.w3.org/2000/svg" width="200px" height="200px" viewBox="0 0 200 200">
            <foreignObject x="10" y="10" width="180" height="180">
                <div xmlns="http://www.w3.org/1999/xhtml">あいうえお</div>
            </foreignObject>
            <use xlink:href="defs.svg#c" x="120" y="110" fill="purple"/>
            <circle cx="150" cy="150" r="50" fill="yellow"/>
        </svg>
    </body>
</html>

xhtml5を利用する場合は,xml宣言「<?xml version="1.0" encoding="utf-8"?>」をファイルの先頭に追加する.html要素にxhtmlの名前空間「http://www.w3.org/1999/xhtml」を指定する.svg,xlinkの名前空間を宣言する.コード記述をxmlに合わせる.ファイル拡張子をxhtmlとして保存する.とする.

svgの名前空間の宣言はsvg要素で行うと良い.接頭辞として定義(html要素において「xmlns:svg="http://www.w3.org/2000/svg"」として宣言)すると,何かと複雑となりがちなsvg要素の記述が更に煩雑となる点に注意する.foreignObject要素を用いる際は,xhtmlの要素が内部に含まれるため,名前空間の再宣言が必要となるケースがある.なお一般的なxhtml5を利用する際の注意点についてはこちらを参照のこと.

svgの表示方法についての補足

先に示した6つのsvgの表示方法についてブラウザごとに細かい動作の差異が存在する.

A群(Dynamic Interactive Mode) B群(Animated Mode)
iframe object embed img input[type=image] background-image
<iframe src="clock.svg" height="100" width="100" style="border:none;"></iframe> <object data="clock.svg" type="image/svg+xml" height="100" width="100"</object> <embed src="clock.svg" height="100" width="100"/> <img src="clock.svg" height="100" width="100"/> <input type="image" src="clock.svg" height="100" width="100"/> <div style="width:100px;height:100px;background-image:url(clock.svg);display:inline-block;background-size:100px 100px"></div>

※この他にもSVG画像を表示するものとして,favicon画像cursor画像content関数border-image/mask-imageプロパティ等が考えられる.

細かい部分まで挙げていくと切りが無いので,要件に合わせて適宜動作確認を行うこと.

object要素に対するtype属性の設定有無について

object要素におけるtype属性はdata属性に指定したデータソースのmimeタイプを指定することとなっている.従ってSVG画像を表示する場合は本属性に「image/svg+xml」を指定することとなる.なお,HTML5ではSVGを表示する場合にはtype属性を省くことができるが,環境によってはこの属性値を設定しないと正常に動作しない場合もある.そのため,予防的なルールとして「常にtype属性を記述すること」としても良い.

†windows環境に於いて,レジストリ内部の拡張子「.svg」に対するContent-type値が書き換わっている場合等.ドローツールのインストーラ等により,本来「image/svg+xml」であるべき部分が「application/svg」と誤った内容に置き換わるケースがある.
InkscapeのインストーラーがChromeでのSVG表示を壊す

インラインフレームで表示したsvgに対するハイパーリンクの指定

svg文書をiframe要素,object要素,embed要素で参照した場合,新たにインラインフレームが生成されその中にsvgが表示される.この時,マウスクリックを始めとしたイベントはこのインラインフレーム内部で処理され,親となるhtml文書にはイベントの通知がなされない.この動作により,object要素等をa要素で囲んでもそのままではハイパーリンクとしては動作しないと言った問題が発生する.例を示す.

ここからsvg/objectここまで

従ってこれを回避するにはa要素内のobject要素等にpointer-events:noneを指定し,インラインフレームに対するカーソルイベントの発生を切り,クリック可能な範囲を揃えるためにa要素にdisplay:inline-blockを指定すると良い

ここからsvg/objectここまで

なお今度はフレーム内部のsvgでのイベント処理がなされないため,マウスホバーによるsvg図形に対するスタイルの変更を行うことが出来なくなるなどの弊害もある.このような場合はsvgのa要素を使ってsvg文書そのものにハイパーリンクを挿入する方法もある.この方法であれば,フレーム内部のイベント処理を維持しつつ,ハイパーリンクも正しく動作させることが可能となる.

なお,埋め込みsvgであればイベントバブリングはsvg要素とhtml要素との間で透過的に行われるため,このような問題は発生しない.

svgの参照モードについて

先程,同じsvgでもその表示方法により動作が異なることを見た.この動作の違いをブラウザにおけるsvgの参照モード(Referencing Modes)と呼び,svgの動作要素スクリプトの実行外部リソースの参照アニメーションの実行イベントの捕捉リンクの実行の有無により細かく分類されている.ここでA群の動作は「Dynamic Interactive Mode」と呼ばれるsvgのフル機能が動作するもので,B群の動作は「Animated Mode」(firefoxのみ「Secure Animated Mode」)と呼ばれるアニメーション機能のみ有効のモードとなっている.

スクリプトの実行 外部リソースの参照 アニメーションの実行 イベントの捕捉 リンクの実行
Dynamic Interactive Mode
Animated Mode
Secure Animated Mode
Static Mode
Secure Static Mode

だが,この参照モードについては現状仕様が確定しておらず,ブラウザ毎に実装の差として現れてしまっている.特に外部リソースの参照においては,関連するオブジェクトがsvg文書,フォント,画像,スクリプト,スタイルシート等多岐に渡り,クロスドメインでの参照をどう扱うかについて解釈がわかれるところとなっている.特にクロスドメインでの画像の参照はセキュリティに関わる(応用次第で悪用が可能)部分でもあり,ブラウザによっては意図的に不可としているものもある.何れにせよ単一のファイルであればこのような問題は発生しないはずなので,ファイルの参照に関わる不具合が出るなら,参照先の内容を(次で示すdataスキーム等を使って)svg文書の中に埋め込むことができないか検討してみよう.(もちろん,根本的な解決策ではない.)

埋め込みsvgにより簡単な図形を描く分にはそれほど問題は無いだろうが,svg文書の機能分割を行う際の意外な落とし穴となる可能性があったため掲載した.

セキュリティの観点から見た要素の選択

このようにiframe要素・object要素・embed要素においてはDynamic Interactive Modeとしてsvgファイルに挿入されたスクリプトプログラムが実行される.その為,不特定多数のユーザーが作成したsvg画像を表示する際,不用意にこれらの要素を採用してしまうと,重大なセキュリティホールとなる可能性がある

この問題による影響はsvg画像をより制限の多いimg要素で表示することで軽減することが出来る.img要素による描画処理はメインとなる文書と明確に隔離されており,静的な構造のみが描画の対象となるなど,object要素などと比べるとはるかに安全性が高い.

dataスキームによるsvgの挿入

最近のブラウザではpng画像をbase64形式でエンコードしdataスキーム形式の文字列とすることで,img要素などの属性に直接画像データを埋め込むことができる.svg文書も例外ではなく,しかもテキストベースであることからjavascriptを用いることで簡単にdataスキーム形式への変換が可能だ.javascriptにおいてsvg文書をdataスキーム形式に変換する場合は次のようにする.

  1. svg文書を読み込み,encodeURIComponent関数を用いてURI形式の文字列に変換する.
  2. 先頭にdataスキームであることとsvg画像であることを示す「data:image/svg+xml;charset=utf-8,」を付加する.「image/svg+xml」はsvgのmime-typeである.

例)data:image/svg+xml;charset=utf-8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20width%3D%22100px%22%20height%3D%22100px%22%20viewBox%3D%220%200%20200%20200%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%3E%0A%09%3Cview%20id%3D%22view1%22%20viewBox%3D%220%200%20100%20100%22%20%2F%3E%0A%09%3Cview%20id%3D%22view2%22%20viewBox%3D%22100%20100%20100%20100%22%20%2F%3E%0A%09%3Ccircle%20cx%3D%2260%22%20cy%3D%2260%22%20r%3D%2250%22%20fill%3D%22red%22%2F%3E%0A%09%3Cpolygon%20points%3D%22100%2C50%2050%2C140%20150%2C140%22%20fill%3D%22yellow%22%2F%3E%0A%09%3Crect%20x%3D%2280%22%20y%3D%22120%22%20width%3D%22100%22%20height%3D%2260%22%20fill%3D%22blue%22%2F%3E%0A%3C%2Fsvg%3E

なお同様の処理をencodeURL関数で行うと,svgにおけるid参照を表す「#」が残ってしまうので,この文字を「%23」に置換する必要がある.

例)data:image/svg+xml;charset=utf-8,%3C?xml%20version=%221.0%22%20standalone=%22no%22?%3E%0A%3Csvg%20width=%22100px%22%20height=%22100px%22%20viewBox=%220%200%20200%20200%22%20xmlns=%22http://www.w3.org/2000/svg%22%20version=%221.1%22%3E%0A%3Ccircle%20cx=%2260%22%20cy=%2260%22%20r=%2250%22%20fill=%22red%22/%3E%0A%3Cpolygon%20points=%22100,50%2050,140%20150,140%22%20fill=%22yellow%22/%3E%0A%3Crect%20x=%2280%22%20y=%22120%22%20width=%22100%22%20height=%2260%22%20fill=%22blue%22/%3E%0A%3C/svg%3E

base64形式への変換

javascriptがbtoa関数をサポートするならbase64形式に変換することもできる.先程の例と接頭辞が若干異なる点に注意する.

  1. svg文書を読み込み,btoa関数を用いてbase64形式の文字列に変換する.
  2. 先頭にdataスキームであることとbase64形式でエンコードされたsvg画像であることを示す「data:image/svg+xml;charset=utf-8;base64,」を付加する.

例)data:image/svg+xml;charset=utf-8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pjxzdmcgd2lkdGg9IjEwMHB4IiBoZWlnaHQ9IjEwMHB4IiB2aWV3Qm94PSIwIDAgMjAwIDIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2ZXJzaW9uPSIxLjEiPgk8dmlldyBpZD0idmlldzEiIHZpZXdCb3g9IjAgMCAxMDAgMTAwIiAvPgk8dmlldyBpZD0idmlldzIiIHZpZXdCb3g9IjEwMCAxMDAgMTAwIDEwMCIgLz4JPGNpcmNsZSBjeD0iNjAiIGN5PSI2MCIgcj0iNTAiIGZpbGw9InJlZCIvPgk8cG9seWdvbiBwb2ludHM9IjEwMCw1MCA1MCwxNDAgMTUwLDE0MCIgZmlsbD0ieWVsbG93Ii8+CTxyZWN0IHg9IjgwIiB5PSIxMjAiIHdpZHRoPSIxMDAiIGhlaWdodD0iNjAiIGZpbGw9ImJsdWUiLz48L3N2Zz4=

これらをimg要素に適用すると,次のようになる.

何れにせよdataスキーム文字列に変換する際にはエスケープ処理に伴ってサイズが増大するため,予め描画に影響しないタブ文字や改行等必要のない文字は削除しておくとよい.また,dataスキームを利用したsvgの表示はブラウザでのサポートが比較的遅れており,filterを含めるような複雑な描画を行う際に正しく動作しないケースがある.

またこの方法ではsvgでよく用いられるハッシュデータ(#)によるsvg部品の参照が有効とならないケースがある点に注意しよう.

cssにおける例外と注意点

上記のdataスキーム形式には元となるsvgの内容が判りにくいといった欠点がある.この問題はcssにsvg画像を埋め込む場合に限り次のように解決することができる.

div#a{
background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle fill='orange' cx='5' cy='5' r='5'/></svg>");
}

上記スタイルを設定したdiv要素

encode文字列としてutf8を指定することで直接svgのコードが記述されるため,後から内容を修正することが容易である(改行を挿入することは出来ない).なお,コードをよく見ると単一引用符と二重引用符の二つが既に使われてしまっているため,これを更にimg要素のsrc属性に指定することは困難である.また,ieにおいてこの設定は無視されてしまうため,クロスブラウザでの動作を見込むのであればこの方法は避けたほうが無難である.

webkit系環境におけるcharset設定の必要性について

ツール等によりsvgファイルをdataスキーム形式に変換した場合,chrome等を含むwebkit系の環境において日本語テキストの内容が表示されないもしくは文字化けするケースがある.この問題はdataスキーム形式の文字列に「charset=utf-8」の記述が含まれていないことに起因する

例を示す.下記のsvgコードをcharset設定を含まないdataスキーム形式に変換し,object要素とimg要素とで表示したものである.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="20">
    <text x="0" y="20" font-size="20" stroke="none" fill="black" text-anchor="start">abc123日本語</text>
</svg>

data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22200%22%20height%3D%2220%22%3E%0A%3Ctext%20x%3D%220%22%20y%3D%2220%22%20font-size%3D%2220%22%20stroke%3D%22none%22%20fill%3D%22black%22%20text-anchor%3D%22start%22%3Eabc123%E6%97%A5%E6%9C%AC%E8%AA%9E%3C%2Ftext%3E%0A%3C%2Fsvg%3E

左がobject要素で右がimg要素で同じsvgを表示している.firefox環境では問題ないものの,chromeではobject要素において日本語の部分のみが文字化けしてしまっている.そこで今度はcharset記述を追加したものを示そう.

data:image/svg+xml;charset=utf-8,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22200%22%20height%3D%2220%22%3E%0A%3Ctext%20x%3D%220%22%20y%3D%2220%22%20font-size%3D%2220%22%20stroke%3D%22none%22%20fill%3D%22black%22%20text-anchor%3D%22start%22%3Eabc123%E6%97%A5%E6%9C%AC%E8%AA%9E%3C%2Ftext%3E%0A%3C%2Fsvg%3E

このように正しく修正された.

※この問題は日本語の内容を数値文字参照で書き換えることでも回避できる.

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="20">
    <text x="0" y="20" font-size="20" stroke="none" fill="black" text-anchor="start">abc123&#26085;&#26412;&#35486;</text>
</svg>

data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20width%3D%22200%22%20height%3D%2220%22%3E%0A%3Ctext%20x%3D%220%22%20y%3D%2220%22%20font-size%3D%2220%22%20stroke%3D%22none%22%20fill%3D%22black%22%20text-anchor%3D%22start%22%3Eabc123%26%2326085%3B%26%2326412%3B%26%2335486%3B%3C%2Ftext%3E%0A%3C%2Fsvg%3E

svg形式ファイルのサイズの縮小について

svgは単純なグラフィックであればそれほど気にならないが,複雑なものとなると次第にファイルサイズが肥大していく特性をもつ.特にドローイングツールで作成したベクタ形式のグラフィックをsvg形式に変換した場合,元のデータよりもファイルサイズが著しく大きくなるケースがある.これはsvgがxmlをベースとしている事に依るもので,数値データを文字列として扱うために起こる.簡単な例を挙げれば,バイナリと文字列とで同じ数値を記述する場合,1byteで表現可能な数値はバイナリで「0〜127」であるのに対し,文字列では「0〜9」しか表現できない.文字列「127」を扱う為には実に3byteが必要となるのだ.特にドローツールが出力するsvgには,グラフィックの精度を高めるために小数点以下の桁数が非常に長い数値文字列が多数含まれており,その結果ファイルサイズが著しく肥大するのである.

従って,このグラフィックの精度を犠牲にすることでsvgファイルのサイズの肥大をある程度抑制することができる.用途にも依るが,ディスプレイに表示するだけであれば小数点以下の値はせいぜい0〜1桁程度で十分である.画像データとしては細部の情報が失われるため元の図形と異なる形となってしまうが,それ以上の精度があったとしても,見た目でその誤差を判断することは出来ないはずだ.もちろん,地図データや,印刷に直接関わるもの等,精度そのものが重要となるものについてはこの方法をとるのは得策ではない.下記に示すsvgz形式の利用を検討したい.

ちなみにこの精度はファイルの変換を行う毎に(浮動小数点の処理に伴い)徐々に失われていくため,ベクタ形式であっても画像データとしては劣化しうる.ラスタ形式におけるブロックノイズと言ったものとは異なり,ベクタ形式ではパス細部の傾き,座標のズレとしてデータが劣化していく.従って画像の拡大・縮小に強いと言われるベクタ形式であっても,不必要な拡大・縮小変換,ファイル形式の変換を行うことは避けたほうが良い.

また,ツールによるsvgの出力結果にはグラフィック描画に直接関わらない様々なメタデータが挿入されていることが多く,これらを削除することによってもsvgのファイルサイズを下げる効果を期待できる.この作業を手で行うのは効率的でないため,下記のようなツールを用いると良いだろう.

圧縮形式svgzについて

一般にテキストファイルは,何らかの圧縮操作を施すことでそのファイルサイズを大幅に削減することが出来る.svgにおいても元がテキストであるため同様のことが言える.このとき画像の編集をする頻度とデバイスに表示する頻度とを考慮すると,ファイルを圧縮したまま表示が可能となっていたほうが使い勝手が良い.そこでsvg文書をgzip形式(zip形式ではない)で圧縮したものがsvgz形式として定められている.

svg文書をsvgz形式に変換するには,元となるsvg文書を(tar等のファイル結合を経ずに直接)gzip形式で圧縮し,適宜拡張子を「svgz」とするだけである.なおブラウザによっては直接svgz形式の文書を表示できないものもあるし,webで利用する場合はサーバー側の設定が必要となるケースもある(httpコンテンツ圧縮,Content-Typeをキーワードに調べてみると良い).例えばwebサーバーとしてapache2を利用している場合は,.htaccessファイルに次の記述を追加することでsvgz形式が使えるようになる

AddType image/svg+xml .svg
AddType image/svg+xml .svgz
AddEncoding gzip .svgz

†なお本文書を公開しているサーバーのように.htaccess自体が無効となっている環境もある.

‡operaはsvgzファイルを直接表示することが出来る.

ラスタ画像を用いたsvgの生成

今日jpg,pngを始めとしたラスタ形式の画像は様々な場面で利用されており,これを元にsvgファイルを生成して活用したいと言ったケースはよくあるものと思う.しかし,ラスタ形式からベクタ形式の画像を得るのはそれほど簡単なことではない.というのも,ラスタ形式には目に見える色の他にベクタ形式で重要となる方向と言った情報が存在しないためである.従って最も信頼できる方法としては,人の目で見て色の境界をベクタ情報に書き換えていく方法が挙げられる.だがいかんせん効率が悪いので,精度を犠牲にして何らかのツールを利用する事となるのだが,市販のドローイングツールを用いずともフリーのソフトウェアを用いることで対処可能だ.

ここではGPLソフトウェアのpotraceを紹介する.potraceは利用する上での様々な制約があるものの,ロゴのベクタ化等の簡単な処理であればこれだけで十分事足りる.さて,potraceの特徴は次のとおりである.

bmpファイルをsvgに変換するには,potraceをsスイッチを指定して実行するだけである.詳しい使い方についてはヘルプドキュメントを参照のこと.この後の微調整はinkscape等で行えばよいだろう.

変換例

なおpotraceは様々な環境に移植されているが,こちらではjavascript上で動作するモジュールを公開している.使いようによってはラスタ画像をブラウザ上でsvg要素に変換すると言ったことも実現できるので,試してみるのも良い.

その他,inkscapeにも「パス」→「ビットマップをトレース」の項目から同様の処理を行うことが可能だ.こちらではカラーでのトレースが行えるなど,非常に高機能だ.

また,拙作のスクリプトでも変換可能なので,いろいろ試してみて欲しい.

htmlのmeta要素の代替作業

svgとhtmlとを比較した際,meta要素が存在しないことが挙げられる.htmlではこの要素によって様々な処理を行うことも出来たが,svgにおいては別の手法を用いる必要がある.

キャラクタセットの指定

htmlではmeta要素によるキャラクタセットの指定が可能だったが,svgにおいてはxml宣言において行う.

検索エンジンへの対応

検索エンジン最大手googleではhtml文書の他にsvg文書のインデックス化も行なっている.従ってインターネットに公開されたsvg文書や画像は何も対処しない限りクローラの検索対象となりうる.その際,htmlではインデックス作業の対象外とするmeta要素の記述方法が存在したが,svgではこれとは別の対策を施す必要がある.googleではこのようなユースケースを想定し,x-robots-tagによるクローラの制御機構を提供している.この機構はsvgに限らず一般的なファイル形式に適用可能であり,httpヘッダーの内容を元にインデックス化の有無を判断する.なおこの機構を利用するにはwebサーバー側の設定が必要となるため,詳しくは専門の解説ページを参考として欲しい.

キャッシュの制御

htmlではファイルのキャッシュ期間をmeta要素で指定できたが,svgではwebサーバー側で行う必要がある.

svgにおける基底uriの指定

html文書にuri文字列を挿入する際,base要素を使うことで相対パス指定時の基準となるuri位置(基底uri)を指定することができる.この設定はa要素のリンク先(href属性)だけでなく,img要素のsrc属性やobject要素のdata属性にも適用されるが,ではインラインsvgにおいてはどうであろうか?

結論から言うと必ずしも適用されるとは限らない.image要素のxlink:href属性についてはfirefox及びchromeではbase要素の内容を加味した結果となるものの,operaではそのようにはならずhtmlファイルを基準としたパスの解釈となる.

xml baseを用いた基底uri情報の設定

svgにおける基底uri情報はxml baseとして別に規定されており,ここで定義されているxml:base属性をsvg要素に指定することでhtmlと同様の基底uriの指定を行うことが可能である.

また,xml:base属性を用いたuri情報の解決は階層をさかのぼって行われるため,ディレクトリ状にリンクを生成すると言ったことも容易に出来る.たとえば下の例では二つのリンクを定義しているが,そのリンク先を階層状に分けて定義しており,前者は「http://hoge/link1.ht」,後者は「http://hoge/dir/link2.htm」へのリンクとして解釈される.

xml:base
svg(xml)文書における基底uriを定める.
リンクその1 リンクその2

svgのフォールバック手法

htmlにおいてはwebページに対するアクセシビリティを確保する目的で,環境によって動作するとは限らない要素(canvas要素やaudio要素等)についてフォールバック(代替)コンテンツを定義しておく事が望ましい.ieやandroid osにおいてはsvgの描画に対応していないものの,sieやcanvg等のjavascriptライブラリを導入し,擬似的にsvgを描画する方法がある.が,そこまでせずともラスタ画像の表示に振り替えるといったもので十分な場合も多い.以下その方法について考えてみよう.

その他にも対処策は考えられるが,svgの利用形態により有効な対処策が変わるため,注意深く動作検証する事をおすすめする.