SVGの影が切れる場合:フィルターとビューポートを確認する
SVGの影が切れる問題を、フィルター領域と外側のビューポートという2つの境界から解決します。パスを変える前に検証済みの例を確認します。
目次
SVGの影が切れる原因には、2つの異なる境界があります。フィルター領域は効果を計算する範囲を制限し、その後SVGのビューポートや親コンテナーが描画結果を切る場合があります。まずフィルターの領域を広げます。それでも影が画像の端で切れるなら、ビューポートとクリッピングの規則を確認します。
パスが正常なSVGを再トレースする必要はありません。このガイドでは、同じ元の輪郭を保持しながら、効果の処理領域と見えるキャンバスを変更します。
画像を変える前に、切れている端を診断する
形状の近くの直線的な端は、フィルター領域の制限を示唆します。SVGの枠と一致する端は、ビューポートのクリッピングを示唆します。ただし、手掛かりであって証拠ではありません。クリップパス、マスク、親コンテナーでも同じ症状が出ます。境界を1つずつ変えて結果を比較します。
同じパスにある2つの境界
小さな輪郭を手で作り、3つの版をブラウザーで開きました。どれも同じパスとfeDropShadow設定、dx="22"、dy="18"、stdDeviation="12"を使います。以下は実際のブラウザー描画であり、PerfectVectorの変換結果ではありません。

最初の版のフィルター領域は(50, 50)から(210, 180)です。そのため影の右端と下端がくっきり切れます。2つ目では、領域を(-20, -20)から(300, 280)へ広げましたが、SVGが表示する範囲はまだ0 0 240 220だけです。今度は影の右端がビューポートの枠に達し、そこで切れます。
3つ目は広いフィルター領域を保持し、viewBoxを-20 -20 320 300へ変えています。widthとheightも320と300にしたため、3つの例はどれも1 SVG単位が1 CSSピクセルのままです。パスのサイズを変えずに、追加した空間へ見える影を収めています。
適切な座標系でフィルター領域を広げる
<filter>のx、y、width、height属性が領域を定義します。既定値は-10%、-10%、120%、120%です。すでに余白がありますが、特定のずれやぼかしには不足する場合があります。MDNはこれらの既定値を説明しています。
数値を変える前にfilterUnitsを確認します。
- 既定の
objectBoundingBoxは、フィルター対象要素の境界ボックスに対する領域として解釈します。パーセントの余白は形状の寸法に依存します。 userSpaceOnUseでは、フィルターを参照する要素の現在のユーザー座標系で領域を定義できます。画像の座標が分かっている場合に便利です。
filterUnitsリファレンスが説明するように、これらの規則は領域に適用されます。影のずれやぼかしの単位を自動で変えるわけではありません。
primitiveUnitsは、フィルタープリミティブ内の長さの値を制御します。既定値はuserSpaceOnUseです。この例では、22、18、12がその意味を保つよう明示しています。objectBoundingBoxへ切り替えると、それらの値の解釈が変わります。MDNはプリミティブの単位とフィルター領域の単位を区別しています。
自分のファイルでは、フィルター対象のオブジェクトやグループの境界を確認し、影が伸びる方向へ十分な余裕を加えます。以下の数値は、このデモに合うものです。万能の影の余白ではありません。ぼかしを増やす、影を動かす、フィルター対象グループを変換する場合は、結果を再確認してください。
SVGのビューポートにも余裕を持たせる
完全な例をshadow.svgとして保存し、ブラウザーで開きます。3つ目の状態に使ったものと同じSVGで、単独のファイルとしても確認しました。
<svg xmlns="http://www.w3.org/2000/svg" width="320" height="300" viewBox="-20 -20 320 300" overflow="hidden">
<defs>
<filter id="shadow" filterUnits="userSpaceOnUse"
primitiveUnits="userSpaceOnUse" x="-20" y="-20" width="320" height="300">
<feDropShadow dx="22" dy="18" stdDeviation="12"
flood-color="#152b34" flood-opacity="0.7"/>
</filter>
</defs>
<path d="M 60 160 L 60 100 Q 60 60 100 60 L 200 60 L 200 120 Q 200 170 150 170 L 70 170 Q 60 170 60 160 Z" fill="#078875" filter="url(#shadow)"/>
</svg>viewBoxには、最小x、最小y、幅、高さの4つの値があります。そのユーザー座標の矩形をSVGのビューポートへ対応させます。表示する幅と高さを変えずにviewBoxの寸法を増やすと、画像は小さく見えます。要素の外側にレイアウト用の空間が追加されるわけではありません。MDNはviewBoxの対応付けを説明しています。
2つの失敗を再現するには、例のコピーで次の値だけを変えます。
- 中央の状態ではフィルターを変えず、ルートを
width="240"、height="220"、viewBox="0 0 240 220"にします。 - 最初の状態ではその小さいビューポートを保持し、フィルターも
x="50"、y="50"、width="160"、height="130"にします。 - 完全な例に戻し、右端と下端を比較します。パスデータは一度も変わりません。
画像全体がキャンバス外なら、空白のSVGの確認事項を参照します。画像は見えるものの読み込みで寸法が変わるなら、形状を調整する前にSVGの単位とサイズの関係を確認します。
overflowがインラインSVGに役立っても、ファイルの問題が直らない理由
この例は、ビューポートの境界を再現できるようoverflow="hidden"を明示しています。インラインSVGでは、overflow="visible"でビューポートのクリップを解除できます。ただし、フィルター領域ですでに破棄したピクセルは復元できず、祖先にクリッピングがあれば結果が隠れる場合もあります。CSSはSVGのプレゼンテーション属性を上書きできます。SVG overflowリファレンスはこれらのクリッピング規則を説明しています。
実際の組み込み方を確認します。余裕のあるページ上のインラインSVG、単独のSVG、HTMLの画像要素から読み込むSVGでは、周囲のレイアウトが同じではありません。今回の3状態の画像は画像要素を使い、固定ファイル内部に十分なキャンバスの余裕を持たせています。自己完結した画像としてSVGを渡す場合は、意図する境界内に効果を含め、その正確なファイルを対象環境で開き直す方法を使います。
単独では正しいのにカード内で切れるなら、カードのoverflow、クリッピング、マスクを確認します。特定のエディターや書き出しツールだけで失敗するなら、簡略化したコピーを比較し、そのアプリのフィルター対応を調べます。SVGの見た目が変わる問題のガイドは、その別の読み込み問題を扱っています。
形状を保持し、効果を別途作り直す
描画した影は、パスに見た目を追加するもので、ぼかしを別の編集可能な輪郭にするものではありません。元形状を持つSVGマスターを保持します。カット用途では、パスの輪郭を別途確認してください。見える影は追加のカット線ではありません。
元データがPNGやJPGしかない場合は、効果を加える前にPerfectVectorでSVGの形状を復元できます。影のない画像をベクターへ変換し、エディターで輪郭、隙間、不要な背景形状を確認します。そこで影を加え、上の確認方法で境界をテストします。
ぼかしが焼き込まれていない元データがあれば、それを使います。平坦化した画像のトレースでは、元のフィルター設定を復元したり、デザイナーがきれいな輪郭の終端をどこに意図したか証明したりはできません。きれいな元データがない単純なマークでは、手で描き直すほうが制御しやすい場合があります。画像のベクター化の概要は、トレースが復元するものを説明しています。
納品するファイルを確認する
エディターのキャンバスだけでなく、書き出したSVG自体を開きます。最終表示サイズで意図する影が収まり、必要なパスが出力に残っていることを確認します。周囲のクリップや非対応のフィルターで症状が再発する場合があるので、実際のWebページや対象アプリも確認します。
極端に大きなフィルター領域を標準の修正として残さないでください。効果に必要な範囲を大きく超える領域は、ファイルを理解しにくくし、外側のクリッピング境界も直せません。意図した余白を使い、フィルターなしの元データを保持して、ぼかしやずれを変えたら再確認します。
よくある質問
フィルターの幅を増やしても影が切れるのはなぜですか? SVGのビューポート、親コンテナー、クリップパス、マスクに別の境界があるかもしれません。フィルターの幅と高さだけでなくxとyも確認し、残る切れがどこに一致するか調べます。
filterUnitsはぼかし半径を変えますか? filterUnitsはフィルター領域の座標系を制御します。primitiveUnitsは、影のずれやぼかし設定を含む、フィルタープリミティブ内の長さの値を制御します。ファイルの診断では区別してください。
SVGを再びベクター化すれば切れを直せますか? SVGに使えるパスがすでにある場合は、フィルター領域やビューポートを修正します。ベクター化は元データがラスターの場合の前段階であり、元の影のパラメーターは復元しません。
参考資料
- MDN:filter要素 — filter要素と、既定の領域の余白を定義しています。
- MDN:filterUnits — フィルター領域の境界ボックス座標とユーザー空間座標を説明しています。
- MDN:primitiveUnits — プリミティブの長さと外側のフィルター領域を区別しています。
- MDN:viewBox — ユーザー座標と見えるSVGビューポートの対応付けを説明しています。
- MDN:overflow — ビューポートのクリッピング、インラインSVGの既定値、CSSの優先を説明しています。
ラスターの輪郭しかない場合は、PerfectVectorでSVGパスを準備し、復元した輪郭を先に確認してから影を加え、最終SVGを開き直して両方の境界を確認してください。

