Base64のSVGが表示されない? 実務で使える原因切り分けと対処法
実案件で頻発する典型例です。
img src="data:image/svg+xml;base64,..."が正しそうなのに表示されない- 同じSVG文字列が
<img>では動くのに CSS background で壊れる - コードレビューで見逃されやすく、デバッグコストが高い
この問題は、再現可能な手順で分解すると解決しやすくなります。
なぜデバッグが難しいのか
1行のミスではなく、複数要因の連鎖で起きることが多いためです。
- 元SVGがすでに不正な場合がある
- エンコード方式が利用先コンテキストと合っていない
- HTML / CSS / JSON で必要なエスケープが異なる
- セキュリティ処理やレンダリング仕様が環境ごとに異なる
その結果、同じSVGでも場所によって表示可否が変わります。
よくある根本原因(優先順)
-
MIMEプレフィックスが誤っている
data:image/svg+xml;base64,またはdata:image/svg+xml,を使う -
Base64エンコード手順が不正
btoa(svg)を直接使うと非ASCII文字で壊れることがある -
コンテキスト別エスケープ不足
特にCSSでは#や引用符の扱いで失敗しやすい -
危険要素やブロック対象が含まれる
script、イベント属性、外部参照が削除・無効化される -
SVG構造自体が壊れている
viewBox欠落、XML不正、タグ不整合など
SVGViewでの解決アプローチ
推測で直すのではなく、3レイヤーで処理します。
1) 入力層: 取り込み前に検証
src/lib/svg/import-handler.ts では次を実施します。
- ファイル種別・サイズ上限(10MB)の検証
<svg>ルート必須のXMLパース検証- パースエラーを明示して早期診断
不正入力を先に落とす設計です。
2) 安全層: プレビュー前にサニタイズ
src/lib/svg/sanitizer.ts で次を除去します。
<script>on*イベント属性<foreignObject>- 外部参照(
href,xlink:href,src)
安全性を高め、環境依存の表示差異を減らします。
3) 出力層: Base64とURLエンコードを両方提供
src/lib/svg/exporter.ts:
export function exportToDataUri(svg: string): string {
const encoded = btoa(unescape(encodeURIComponent(svg)));
return `data:image/svg+xml;base64,${encoded}`;
}
export function exportToDataUriEncoded(svg: string): string {
const encoded = encodeURIComponent(svg);
return `data:image/svg+xml,${encoded}`;
}
これにより次が可能です。
- 互換性重視ならBase64
- 短く読みやすくしたいならURLエンコード
- どちらも
image/svg+xmlを保証
どのエンコードを選ぶべきか
- 利用先が未確定: まずBase64
- 文字列を短く可読に: URLエンコード
- CSS背景用途: URLエンコードを優先(適切にエスケープ)
以下のツールを使うと切り替え確認が速くなります。
再現可能なトラブルシュート手順
- プレフィックスを確認(
data:image/svg+xml;base64,/data:image/svg+xml,) <svg>ルートとviewBoxを確認- UTF-8安全なエンコード手順を確認
- CSS/JSON向けエスケープを確認
- サニタイズ後に再出力
- Base64とURLエンコードを相互に試す
FAQ
<img> では表示されるのにCSSで失敗するのはなぜ?
CSS文字列解析の方がエスケープ要件が厳しいためです。CSSではURLエンコードの方が安定しやすいです。
image/svg+xml に変えれば必ず直る?
いいえ。MIMEは要素の1つで、エンコード・エスケープ・SVG妥当性も同時に必要です。
Data URIは常に外部ファイルより良い?
いいえ。小さなインライン素材には有効ですが、大きい・再利用回数が多い素材は外部ファイルの方が適する場合があります。
まとめ
「Base64 SVGが表示されない」は単一バグではなく、パイプライン上の問題です。
validate -> sanitize -> dual encoding -> context match を標準化すれば、再現可能に扱える問題へ変えられます。