SVGO:必要な構造を失わずにSVGを最適化する
SVGのコピーでSVGOを実行し、ページが使うIDを保持して結果を比較します。最適化でCSSの参照が壊れる、測定済みのバッジ例を紹介します。
目次
SVGOでSVGを最適化し、ページでの使用を壊さないためには、元データを保持し、ページが依存する構造を特定してから、別に最適化したコピーをそのページでテストします。ファイルが小さくなり、単独のプレビューが同じでも、CSSセレクター、スクリプト、参照が動く証明にはなりません。
今回の独自バッジで、その違いが分かります。SVGOの既定プリセットは元データを437から263バイトへ減らしましたが、周囲のHTMLが太陽の色変更に使うIDを削除しました。cleanupIdsを無効にすると、その参照を残した281バイトのコピーになりました。これはSVGO 4.1.0でこの素材を測定した結果であり、他の画像の圧縮率の保証ではありません。
SVGOは既存のSVGマークアップを編集します。PNGやJPGしかない場合は、先にベクター形状を作るか復元します。最適化はビットマップ内のオブジェクトを編集可能なパスへ変換できません。
保持する必要があるSVG構造を決める
最適化前に、見えるものと、別の文書やアプリが参照するものを区別します。SVGOの既定プリセットには、ID、グループ、スタイル、パスデータを変える操作があります。組み込み側が別のプラグイン一式を選ぶこともあるので、実際にファイルを処理するツールの設定を確認します。
| 依存関係 | 最適化後に確認するもの |
|---|---|
| CSSが内部IDを選択する | IDが残り、期待する描画が現れるか |
| JavaScriptが形状を選択する | セレクターが目的の要素を取得するか |
| グラデーション、クリップ、マスクの参照 | 参照が解決し、対象画像が描画されるか |
| スプライトの利用側がsymbolを参照する | 書き出したsymbol IDと利用側の参照が一致するか |
| デザイナーが部品を別々に編集する | 必要なオブジェクトとグループが使えるか |
| レイアウト内で画像を拡大縮小する | viewBox、寸法、実際の表示サイズが動作するか |
これらは別々の確認です。IDを保持しても、すべてのグループ、ノード、編集可能なオブジェクトが保持されるわけではありません。同様に、正しい描画でも、エディターが希望するレイヤー構造を復元できる証明にはなりません。編集可能なマスターを保持し、対象環境用の納品コピーを作ります。
再利用するsymbolには、SVGスプライトガイドが参照の利用側を扱っています。この記事は、ファイルが利用側へ届く前に、最適化が何を変えるかに焦点を当てます。
外部CSSの参照が壊れる例を再現する
Node.jsとnpmが使える空の作業フォルダーを使います。最後の改行も含め、この手書きイラストをinput.svgとして保存します。設定のテスト素材であり、PerfectVectorの変換結果ではありません。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 160">
<title>Mountain badge</title>
<!-- Original illustration for an SVGO configuration test. -->
<metadata>Editable master: preserve the badge-accent CSS hook.</metadata>
<path d="M80 12 139 46v68l-59 34-59-34V46Z" fill="#157d78"/>
<circle id="badge-accent" cx="108" cy="53" r="12" fill="#ef8067"/>
<path d="m38 111 32-49 21 30 10-15 25 34Z" fill="#fffdf5"/>
</svg>この例の正確なバージョンをインストールし、新しい出力ファイルを作ります。
npm install --save-exact svgo@4.1.0
npx svgo input.svg -o default.svg既存のsvgo.config.mjsが予期しない設定を与えないよう、空のフォルダーで実行します。SVGOの公式リポジトリは、別の出力ファイル名と設定読み込みを説明しています。プロジェクトのビルドでは、バージョンと設定をバージョン管理し、更新を意図的な変更にします。
default.svgをテキストとして開きます。円の塗りはコーラルのままですが、badge-accentのIDはありません。そのIDはSVG文書内では参照されていませんでした。cleanupIdsのドキュメントは、未使用のIDを削除し、参照されるIDを短縮すると説明しています。外部ページのセレクターは、この入力素材の外にあります。
影響を見るため、SVGのマークアップをHTMLページへ直接置き、SVGの外に次のスタイルを置きます。
<style>
#badge-accent { fill: #f5bf42; }
</style>このテストでは、各ページに1つのコピーを使います。元SVGの太陽は、セレクターが一致するため金色になります。既定の最適化後の太陽は、IDがないためコーラルのままです。img要素で読み込むのは別のテストになります。ホストページが、同じ文書内の内部形状を選択するわけではありません。
参照を保持して再テストする
同じフォルダーにsvgo.config.mjsとして保存します。
export default {
plugins: [
{
name: 'preset-default',
params: {
overrides: {
cleanupIds: false,
},
},
},
],
};もう1つのコピーを書き出します。
npx svgo input.svg --config svgo.config.mjs -o preserved.svg
wc -c input.svg default.svg preserved.svgこの上書きは、既定プリセットの他の部分を保持しながら、1つのプラグインだけを無効にします。示したID依存関係の出発点です。任意の画像、アニメーション、アクセシビリティの関係、アプリ固有の構造に対する万能の安全な設定ではありません。
上のコマンドを空のフォルダーで実行し、同等の設定をSVGO 4.1.0のJavaScript APIでも独立して実行しました。CLIとAPIの出力はバイト単位で一致し、最適化したファイルに末尾の改行は追加されませんでした。その後、同じ外部CSSの規則を使う個別のHTML文書で各結果を描画しました。ブラウザーの報告結果は次のとおりです。
| ファイル | 生のバイト数 | アクセントIDがあるか | 計算された太陽の色 |
|---|---|---|---|
| 元データ | 437 | あり | 金色:rgb(245, 191, 66) |
| 既定プリセット | 263 | なし | コーラル:rgb(239, 128, 103) |
| cleanupIdsを無効化 | 281 | あり | 金色:rgb(245, 191, 66) |
ID保持の出力は156バイト、元データの約35.7%を削減しました。既定出力より18バイト大きい代わりに、必要な動作を保持しました。空白、改行、バージョン、出力書式でバイト数は変わります。

このテストでは3つすべてにviewBox="0 0 160 160"が残りました。見える結果とブラウザーの計算済みfillを確認しました。通信時間は測定せず、すべてのブラウザー、エディター、SVG機能、ビルド組み込みもテストしていません。
特定の依存関係に合わせて設定を調整する
公開の参照となるIDが少数なら、cleanupIdsにはpreserveとpreservePrefixesもあります。依存関係を名前で指定できる場合に使い、同じ利用側のテストを繰り返します。複数のSVGをインライン化する場合は、IDの重複も確認します。すでに重複するIDを残しても一意にはなりません。名前を変えるなら利用側も更新する必要があります。
SVG内のスタイルやスクリプトは、最適化の動作を変える場合があります。cleanupIdsのドキュメントは、それらがあると処理を控える保護策を説明しています。その保護を別文書のCSSへ一般化したり、IDに依存する参照を理解せず強制的に削除したりしないでください。
数値精度は別に扱います。小数桁を減らすとマークアップが減る場合がありますが、許容できる変化は画像の座標倍率と最終表示サイズに依存します。使用サイズで小さな隙間、角、曲線を確認します。IDの確認成功は、それらの細部について何も示しません。
レイアウトが拡大縮小の動作に依存するなら、viewBoxを保持します。removeViewBoxプラグインのドキュメントは、拡大縮小とクリッピングへの影響を警告しています。ここで使う文書化された既定プリセットには含まれません。明示的に追加するのは別の判断です。どのバージョンとプリセット用か確認せず、古い設定をコピーしないでください。
トレースによってノードが多くなった輪郭では、マークアップ最適化と意図したノード整理も異なる問題を扱います。SVGのノードガイドで形状の簡略化が必要か判断し、編集後に輪郭を比較します。元データが小さくなっても、自動的にきれいなカットパスになるわけではありません。
実際の使用先で納品用コピーを検証する
設定を選んだ後、最適化したファイルを実際の受け取り工程へ置きます。既定状態と、それに依存するホバー、選択、テーマ、アニメーション状態を確認します。静止プレビューは、操作後だけに実行するセレクターを見逃す場合があります。
Web画像では、ローカルの最適化ファイルだけでなく、最終ビルドの出力も確認します。フレームワークやバンドラーが後で独自に最適化する場合があります。配信されるマークアップが異なるなら、再テストします。
編集用の受け渡しでは、対象エディターでコピーを開き、受け取り手が必要とする部品を選択します。小さな文字、穴、別々の色、クリッピングを確認します。Web用コピーが合格しても、元マスターを保持します。
ファイル最適化と転送圧縮も別です。SVGZとSVGの比較ガイドは、同じ元バイトを復元するgzipの往復を示しています。SVGOは配信前の元データを変更し、そのバイトをgzipで符号化できます。各操作をそれぞれの目的で比較します。
最適化前にベクター化が必要な場合
ベクターマスターがなく、平面的なPNGやJPGしかないなら、PerfectVectorの画像をベクターに変換する手順でSVG候補を準備できます。結果を元画像と比較し、穴、細部、別々の領域を確認してから承認します。画像を確認した後にページ用のIDやグループを追加し、納品用コピーを最適化してそれらの参照をテストします。
PerfectVectorは既存SVGの最適化ツールではなく、Webサイトのセレクターを復元しません。ベクターマスターがあれば使います。連続階調の細部が編集可能な輪郭より重要な写真は、ラスターで保持します。ブログのベクター準備ガイドは、それらの元データの選択を扱っています。
よくある質問
cleanupIdsを無効にすれば、どのSVGも安全に最適化できますか? いいえ。そのプラグインによるID削除と短縮は防ぎますが、他のプラグインがスタイル、グループ、形状、パスデータを変える場合があります。受け取り工程が使う機能と参照を検証してください。
最適化したSVGは単独では正しいのに、ページでは違うのはなぜですか? 単独のプレビューは外部CSSやスクリプトを実行しない場合があります。この例ではSVG自身のコーラルの塗りは正常に描画されましたが、選択するIDが削除されたためページの金色への変更が失敗しました。
唯一の編集可能なマスターを最適化するべきですか? マスターを保持し、最適化した納品用コピーを書きます。最適化後も正しく描画されても、後の編集に使いにくい構造になる場合があります。
SVGOはPNGをベクターパスにできますか? いいえ。SVGOはSVGマークアップを処理します。ラスターからベクターへのトレースは、編集可能な形状が必要で適したベクターマスターがない場合の前段階です。
参考資料
- SVGOリポジトリ — インストール、コマンドライン出力、設定読み込み、optimize API。
- SVGOの既定プリセット — プラグイン一覧、上書き、組み込みの違い。
- SVGO cleanupIds — ID削除、短縮、保持オプション、関連する保護策。
- SVGO removeViewBox — viewBoxを明示的に削除する拡大縮小のリスク。
画像と動作の確認に合格する、最小のコピーを保持します。開始ファイルにまだ編集可能なベクター形状がない場合は、ラスター画像からSVGを準備し、形状を確認して、追加した参照を保持してから納品用コピーを最適化します。
