SVG を data URI に変換する方法
- SVG のマークアップを テキスト ボックスに貼り付けます。
.svgファイルは任意のテキストエディターで開けばコピーできます。ボックスには最初からサンプルのアイコンが入っています。 - MIME タイプ はすでに
image/svg+xmlに、エンコード方式 は 最適化 SVG に設定されています。 - オプションの下の表を確認します。Base64、URL エンコード、最適化 SVG のそれぞれについて URI の長さと gzip 後のサイズが並び、最小のものに印が付き、各行に 使用 ボタンがあります。
- 出力形式 を選びます。生の Data URI、CSS の
url()、HTML の<img>、HTML の<a>、Markdown から選べます。その後 出力をコピー します。
ファイルから モードで .svg をドロップすることもできます。その場合は、ファイルをそのまま Base64 または URL エンコードします。最適化版と比較表を使うには、マークアップがテキストボックスに入っている必要があります。
Base64 と URL エンコードの SVG のサイズ比較
組み込みのサンプル(角丸の四角形、円、線からなる 309 バイトのアイコン)では、表は次のようになります。
| エンコード方式 | URI の長さ | gzip 後 |
|---|---|---|
| Base64 | 438 | 337 |
| URL エンコード | 492 | 239 |
| 最適化 SVG | 347 | 220 |
単純な URL エンコードは、そのままでは最も長くなります。スペース、引用符、<、>、改行がどれも 3 文字になるからです。ところが gzip 後は Base64 を大きく引き離します。マークアップは繰り返しの多い構造を保っていますが、Base64 はそれをかき混ぜてしまうからです。スタイルシートはほぼ必ず圧縮して配信されるので、ユーザーに届くのは gzip 後の列の値です。
最適化 SVG はどちらの列でも最小です。103 バイトの小さな三角形アイコンでも差は同じで、Base64 が 166 文字、URL エンコードが 172 文字、最適化版が 136 文字です。アイコン一式での比較は SVG を Base64 に にあります。
「最適化 SVG」が行うこと
最適化ではマークアップに 4 つの変更を加えます。
- 改行を含む連続した空白をすべて 1 つのスペースにまとめ、両端を切り詰めます。
"を'に置き換えます。ただし、SVG にもともと'が含まれていない場合に限ります。encodeURIComponentでパーセントエンコードした後、URI 内で安全な文字(スペース、=、:、/、,、;)を元に戻します。- 残ったエスケープを小文字で書きます(
%3Cではなく%3c)。こうすると gzip がわずかに効きやすくなり、サンプルでは 222 バイトが 220 バイトになります。
三角形アイコンの結果は次のとおりです。
data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath d='M8 1 15 15H1z' fill='%23e33'/%3e%3c/svg%3e
色の # は %23 になっています。このエスケープは必須です。エスケープされていない # は URL のフラグメントの開始を意味し、それ以降はすべて黙って捨てられます。
引用符と使う場所のルール
最適化した出力には一重引用符、生のスペース、生の括弧が含まれます。二重引用符の中なら問題ありませんが、それ以外の場所では使えません。
.icon { background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' ...%3e"); }
<img src="data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' ...%3e" alt="">
引用符なしの url(...) はスペースで壊れ、一重引用符で囲んだ属性は最初の ' で終わってしまいます。URI を JavaScript で組み立てる場合、テンプレートエンジンで挿入する場合、引用符を書き換えるシステムに貼り付ける場合は、Base64 のほうが安全です。英字、数字、+、/、= しか含まないので、どんな場所でも壊れません。切り替えるには表の 使用 ボタンを使ってください。
ほかの制限は小さなものです。最適化 SVG は常に UTF-8 で、ほかの文字コードを選んでも警告を出して無視します。空白をまとめると、空白を保持する <text> 要素のテキストが変わることがあります。そして、画像として使う SVG はすべてそうですが、ルート要素に xmlns="http://www.w3.org/2000/svg" が必要です。
JavaScript での最適化
同じ変換は数行で書けるので、ビルドスクリプトや CSS-in-JS で使えます。
function svgToDataUri(svg) {
let s = svg.trim().replace(/\s+/g, " ");
if (!s.includes("'")) s = s.replaceAll('"', "'");
const keep = { "%20": " ", "%3D": "=", "%3A": ":", "%2F": "/", "%2C": ",", "%3B": ";" };
return "data:image/svg+xml," + encodeURIComponent(s)
.replace(/%[0-9A-F]{2}/g, m => keep[m] || m.toLowerCase());
}
これで上に示した三角形の URI が得られます。ブラウザと Node でのエンコードについては JavaScript での Base64 で詳しく解説しています。既存の SVG data URI を読むには、Base64 から SVG か Data URI パーサー に貼り付けてください。
よくある質問
SVG を data URI に入れる最も短い方法は?
たいていは最適化した URL エンコードです。空白をまとめ、二重引用符を一重引用符に変え、必要な文字だけをエスケープします。サンプルのアイコンでは、Base64 の 438 文字に対して 347 文字です。
URL エンコードした SVG で CSS が壊れるのはなぜですか?
最も多いのは引用符の衝突です。最適化した出力は内部で一重引用符を使うので、外側は二重引用符で囲む必要があります:url("data:image/svg+xml,...")。また、#f00 のような色指定のエスケープされていない # も URI をそこで途切れさせます。%23 にしなければなりません。
最適化したエンコードで SVG の見た目は変わりますか?
普通の図形では変わりません。空白をまとめて引用符の種類を入れ替えるだけです。ただし、xml:space="preserve" や CSS の white-space ルールが付いた <text> 内のテキストは、余分な空白が失われることがあります。
SVG の data URI に ;charset=utf-8 は必要ですか?
必須ではありません。SVG は XML で、XML はファイルが別のエンコードを宣言しない限り UTF-8 として読まれるので、アクセント付きのラベルも問題なく表示されます。文字コード の初期値は(なし)です。UTF-8 を選ぶと 14 文字増えますが、害はありません。