SVGのforeignObject文字:書き出しで消えるラベルを直す
ブラウザーでは見えるのに書き出すと消えるSVGラベルを修正します。foreignObjectとネイティブ文字を比較し、名前空間を確認して既存の図形を保持します。
目次
SVGの形状は書き出し後も残るのにラベルが消える場合は、欠けたラベルに <foreignObject> が使われていないか確認してください。ブラウザーでは正常にレイアウトできるHTMLでも、利用先のレンダラーが対応していない場合があります。該当するラベルをSVG標準の <text> と <tspan> に置き換えるか、見た目を保持できる書き出し方法を選びます。
まず、実際に書き出したファイルをブラウザーで開いてください。そこでもラベルが欠けているなら、読み込み側の問題と決める前に、名前空間、境界、スタイルを確認します。元の図形は保持してください。テキストのコンテナーだけが失敗した場合、画像全体のトレースは不要です。
絵は残るのにラベルが消える理由
SVGには、通常の形状と別のXML名前空間の内容を混在させられます。<path> で描く山や <circle> で描く太陽はSVG標準の要素です。<foreignObject> 内の段落はHTMLの場合があり、独自の折り返しやレイアウトの規則を持ちます。MDNのforeignObjectリファレンスでは、この違いを説明しています。
したがって .svg という拡張子は、すべての部分が同じ描画機能を使うことを保証しません。利用先は山と太陽を描けても、HTMLの段落を省く場合があります。文字色を変えたり書き出し解像度を上げたりしても、そのレンダラーにHTML対応は追加されません。
| 見える症状 | 次の確認 | 想定される修正 |
|---|---|---|
| 形状は両方で見え、ラベルはブラウザーだけで見える | 欠けたラベルは foreignObject を使っているか | そのラベルを置き換えるか、書き出し方法を変える |
| HTMLラベルがブラウザーでも見えない | XHTML名前空間、明示的な境界、可視性、スタイル | まずHTMLコンテナーを修正する |
| ネイティブ文字の書体や行の長さが異なる | フォントの利用可否と指定した行位置 | フォントを解決するか、最終的な文字をアウトライン化する |
| 図の大半が欠けている | ビューポート、クリッピング、文書構造 | より広い範囲の空白SVGの確認を行う |
ラベルだけを変える小さなテスト
私たちはパス、円、「Keep artwork and labels separate」という文字を持つ480 × 240のSVGカードを作りました。最初のファイルはHTMLラベルを使います。2つ目は同じ形状を保持し、ラベルだけをネイティブ文字と明示的な3行に置き換えています。
ブラウザープレビューでは両方のラベルが表示されました。同じファイルをsharp 0.34.4と同梱のlibrsvg 2.61.1でPNGに描画すると、以下の結果になりました。HTMLラベルは消え、ネイティブのラベルは残りました。HTMLラベルの出力は、ラベルを除いた対照ファイルとピクセル単位でも一致しました。これは今回のファイルとレンダラーのバージョンに対するテストであり、すべての編集ソフトについての互換性の判定ではありません。

元のファイルは再現できるほど小さなものです。次を html-label.svg として保存し、ブラウザーで開きます。
<svg xmlns="http://www.w3.org/2000/svg"
width="480" height="240" viewBox="0 0 480 240">
<rect width="480" height="240" rx="20" fill="#f5f1e7"/>
<path d="M40 135Q90 15 140 135Z" fill="#087f75"/>
<circle cx="90" cy="95" r="18" fill="#f4bc45"/>
<foreignObject x="180" y="70" width="230" height="110">
<div xmlns="http://www.w3.org/1999/xhtml"
style="font: 28px/1.25 Arial, sans-serif; color: #172b34;">
Keep artwork and labels separate
</div>
</foreignObject>
</svg>2つ目のファイルでは、foreignObject 要素全体を次のラベルで置き換え、native-label.svg として保存します。
<text x="180" y="96" font-family="Arial, sans-serif"
font-size="28" fill="#172b34">
<tspan x="180" dy="0">Keep artwork</tspan>
<tspan x="180" dy="35">and labels</tspan>
<tspan x="180" dy="35">separate</tspan>
</text>x は各行を同じ横位置から始めます。dy は後続の行を下に移動します。これはHTMLの自動折り返しを意図的に使わず、作成者が改行を選んで収まりを確認する方法です。MDNはtspanの配置を説明し、librsvgは対応するSVG要素を一覧にしており、text と tspan も含まれています。
画像変換ツールやPDF生成ツールなど、実際の納品経路に両ファイルを通してください。元のプレビューだけでなく、保存した結果を比較します。例と同じ寸法にしても、別のマシンでフォントが同じになるとは限りません。
ブラウザーでもラベルが欠けている場合
作成元のページだけでなく、シリアライズされた .svg ファイルを確認してください。HTML内のインラインSVGと独立したSVG文書では、解析される文脈が異なります。
この例では div を明示的に http://www.w3.org/1999/xhtml に置いています。MDNは、インラインHTMLの例では省けても、独立したSVG文書のHTML内容にはこの名前空間宣言が必要としています。JavaScriptで要素を作る場合は、HTMLの子要素に適切な名前空間を使ってください。SVG名前空間で作った div はHTMLの段落コンテナーではありません。
次に、ラベルの以下の部分を確認します。
foreignObjectに、意図したラベル領域のための明示的で正のwidthとheightを与えます。xとyを見える図の中に置き、すべての行のための空間を確保します。- コンテナーと子要素の
display、visibility、不透明度、文字色を確認します。 - 周囲のWebページのスタイルシートに依存せず、書き出したファイルが必要なスタイルを含むことを確認します。
この例ではすべてのラベルスタイルがインラインで、枠は幅230、高さ110単位です。これで外部CSSを変数から除けます。ただし、機能に対応していないレンダラーで foreignObject を使えるようにするものではありません。
draw.ioの書き出しでは元データでラベルを変換する
編集可能な図が残っていれば、XMLを手で編集する前に、その場所でラベルの書き出しを修正してください。現在のdraw.ioの書き出しドキュメントでは、対応する書式付きラベルに Convert Labels to SVG(ラベルをSVGに変換) を提供しています。形状またはコネクターを選び、TextタブのAdvanced欄を開いてチェックボックスを有効にします。
この選択肢には制限があります。ドキュメントでは、表、リスト、リンク、背景色などの構造を含むラベルは変換対象外としています。選択肢が使えない場合は、Formatted Text(書式付きテキスト) と Word Wrap(自動折り返し) を無効にする方法も記載されています。手動の改行を入れ、レイアウトを再確認する必要がある場合があります。
新しいコピーを書き出し、受け取り側のアプリで開き直してください。「Text is not SVG」の警告を隠してもラベルは変換されません。フォントの埋め込みが解決するのはフォントの依存関係で、HTMLレイアウトの非対応ではありません。
イラスト付きの図では、読み込んだ図形とラベルを分けて保持してください。draw.ioのカスタムSVG形状ガイドでは、この手順の図形側を扱っています。
次に使う人に合う文字形式を選ぶ
受け取り側が文言を編集する必要がある場合、ネイティブ文字は有用な修正ですが、使用可能なフォントに依存します。ラベルの書体が違う場合は、コンテナーが欠けた問題と同じだと扱わず、SVGのフォント確認に従ってください。
| 納品要件 | 実用的な選択 | 確認事項 |
|---|---|---|
| 文言を編集できること | 行位置を意図的に決めたネイティブ text | フォント、行の長さ、受け取り側の編集ソフト |
| 文字形状を固定すること | 元の編集ソフトで最終的な文字をアウトライン化 | 正しい見た目と、編集可能なマスターの保持 |
| ブラウザー専用のリッチなレイアウト | そのブラウザーで要件を満たすなら foreignObject を保持 | 実際の埋め込みファイルまたは独立したファイル |
| 見た目だけ必要 | 全デザインを表示するレンダラーからPNGを書き出す | 納品サイズでのピクセル寸法と最小文字 |
アウトライン化は、元ツールが文字を表示して変換できる場合だけ有効です。すでに不完全な書き出しを開いて残ったオブジェクトを変換しても、読み込んだ文書に存在しない文言は戻りません。PNGが保持するのはピクセルなので、編集可能な文字やベクターのカットパスが必要な場合には適しません。
イラスト付きカードでのPerfectVectorの役割
カードのイラストがPNGやJPGでしか存在しない場合、PerfectVectorのクリップアートからSVGへの手順で、その図形のベクター候補を作れます。文言はデザイン編集ソフトで別のテキスト要素として保持します。イラストのエッジと内側の隙間を確認し、ラベルを追加して、組み立てたファイルを利用先のレンダラーでテストしてください。
画像ベクター化ガイドでは、ピクセルがパスになる仕組みを説明しています。PerfectVectorはSVGのHTMLラベルを修復しません。イラストにすでに良いパスがあるなら、保持して失敗しているラベルだけを変えます。ラベルが欠けたスクリーンショットには復元する文字がなく、見える文字をトレースしても編集可能な文言ではなく形状になります。
修正したSVGを送る前に
- 書き出したコピーをブラウザーと使用予定の利用先で開き直します。
- 最後の行も含め、すべてのラベルが見えることを確認します。
- 図形が移動したりサイズが変わったりしていないことを確認します。
- フォントを検証するか、アウトライン化した文字を予定のサイズで確認します。
- 納品コピーとともに編集可能な元データを保管します。
よくある質問
ChromeではSVGの文字が見えるのに、PNGの書き出しでは消えるのはなぜですか? ラベルがforeignObject内のHTMLで、PNGレンダラーはSVGの別の範囲にしか対応していない可能性があります。欠けたラベルのマークアップを確認し、ネイティブ文字版を同じ書き出し経路で描画してください。
XHTML名前空間を加えると、foreignObjectの書き出しはすべて直りますか? いいえ。独立したSVG内のHTML内容の名前空間を修正するものです。利用先はその内容に対応する必要があり、ラベルにも適切な寸法と見えるスタイルが必要です。
tspanはHTMLの段落のように折り返せますか? この例は明示的な行と縦オフセットを使い、HTMLの段落レイアウトを再現しません。利用できる空間に合わせて改行を選び、利用先のフォントで確認してください。
ラベルを復元するためにカード全体をベクター化すべきですか? 既存のパスを保持し、元の文言からラベルを作り直してください。ベクター化するのはピクセルでしか存在しない図形だけです。トレースした文字は形状であり、編集可能な文言は保持しません。
参考資料
- MDN — foreignObject要素 — 別名前空間の内容、形状属性、独立SVG内のXHTML名前空間を定義しています。
- MDN — tspan要素 — SVG標準の文字の一部を配置する方法を説明しています。
- draw.io — 書き出したSVGの文字の問題 — ネイティブラベルへの変換、書式の制限、別の書き出し設定を説明しています。
- GNOME — Librsvgが対応するSVGとCSSの機能 — レンダラーが対応する要素と属性を一覧にしています。
イラストがまだビットマップなら、クリップアートをSVGとして準備し、形状を確認して、文字を別に追加してください。渡す前に、書き出したファイルで両方を検証します。

