N2
NanToo
デザイン6 分で読める

CSS clip-path のブラウザ差 — Safari で崩れるケースと実践的な対策

CSS clip-path は、要素を任意の形に切り抜ける便利なプロパティです。Chrome/Edge/Firefox では素直に動きますが、Safari(特にiOS Safari)では複数の"崩れポイント"があります。本記事では、実務で引っかかる代表的なケースと、影(box-shadow)やアニメーションと組み合わせる際の実用的なワークアラウンドを解説します。

#CSS#clip-path#Safari#ブラウザ差分
AD

clip-path の基本おさらい

clip-path は、要素を多角形・円・楕円・SVGパス等の形状で切り抜きます。

.hexagon {
  clip-path: polygon(
    25% 0%, 75% 0%, 100% 50%,
    75% 100%, 25% 100%, 0% 50%
  );
}

モダンブラウザはすべて対応していますが、Safari は長らく -webkit-clip-path プレフィックスを必要としていた歴史があり、古いiOSをサポートする場合は併記が推奨されます。

.hexagon {
  -webkit-clip-path: polygon(/* ... */);
          clip-path: polygon(/* ... */);
}

崩れケース1: transform との合成でレンダリングが乱れる

iOS Safari では、clip-path を当てた要素に transform: rotate()scale() を組み合わせると、描画が一瞬消えたりギザギザしたりする現象が報告されています。

/* 不安定なパターン */
.card {
  clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
  transform: rotate(-2deg);
  transition: transform 0.3s;
}
.card:hover { transform: rotate(0deg) scale(1.05); }

対策: GPU合成レイヤーに載せることで改善するケースが多いです。

.card {
  clip-path: polygon(0 0, 100% 0, 100% 90%, 0 100%);
  transform: rotate(-2deg);
  will-change: transform;           /* or */
  backface-visibility: hidden;      /* GPU 層を強制 */
  -webkit-transform: translateZ(0); /* Safari の暗黙の合成ヒント */
}

will-change は万能ではなく、過剰に指定するとメモリを食います。1ページに数か所までにとどめるのが原則です。

崩れケース2: box-shadow が clip-path で切られてしまう

これはSafari固有ではなく仕様通りの挙動ですが、実務でハマりやすいポイントです。clip-pathで切り抜いた要素のbox-shadowは常にクリップされてしまい、影が表示されません。

/* 影が消える */
.badge {
  clip-path: polygon(/* 六角形 */);
  box-shadow: 0 4px 12px rgba(0,0,0,.2);  /* 見えない */
}

対策: filter: drop-shadow() を使う

filter: drop-shadow()クリップされた後の形状に対して影を落とすため、box-shadowの代替として機能します。

.badge {
  clip-path: polygon(/* 六角形 */);
  filter: drop-shadow(0 4px 12px rgba(0,0,0,.25));
}

ただしfilter: drop-shadow は box-shadow より描画コストが高い点には注意してください。大量に使うページではパフォーマンスを計測することを推奨します。

崩れケース3: polygon() のアニメーションで頂点数が違うと崩れる

clip-pathのアニメーションで、開始状態と終了状態で polygon の頂点数が異なると、ブラウザは補間できず、カクついたり最終状態に瞬間スナップしたりします。

/* NG: 4頂点 → 6頂点 */
.el { clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%); }
.el:hover { clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }

対策: 開始・終了で同じ頂点数にする。変化させたくない頂点は同じ座標に2つ重ねて配置する方法もあります。

/* OK: 両方 6頂点 */
.el {
  clip-path: polygon(0 0, 100% 0, 100% 0, 100% 100%, 0 100%, 0 100%);
}
.el:hover {
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}

Chrome と Firefox は頂点数不一致でも"ジャンプ"で終わるのに対し、Safari は中間状態で polygon が破綻した表示になることがあるため、特に注意が必要です。

崩れケース4: モバイル Safari で overflow: hidden と競合

親要素に overflow: hidden を当て、子に clip-path を使うパターンで、iOS Safari だけ clip-path が無視されるように見えるケースがあります。

原因は多くの場合、親要素の position: static 下で overflow とクリッピング処理の順序が決定的でないことにあります。

対策: 親要素を明示的に position: relative + isolation: isolate でスタッキングコンテキストを確立する。

.parent {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}
.child {
  clip-path: polygon(/* ... */);
}

崩れケース5: clip-path と CSS Grid/Flex の IntrinsicSize

Grid/Flex内の要素にclip-pathを当てると、IntrinsicSize(要素の自然サイズ)の計算に clip-path は影響しません。つまりクリップされた"見えない部分"もレイアウト計算上は存在します。

視覚的に小さく見えるアイコンが、実際は周囲に余白を作ってしまう現象です。

対策: width/height を明示するか、aspect-ratio で縦横比を固定すると予測可能になります。

.icon {
  width: 32px;
  height: 32px;
  aspect-ratio: 1 / 1;
  clip-path: polygon(/* ... */);
}

デバッグのコツ

  1. Safari Web Inspector で表示 — Chrome DevTools で動くものが Safari で動かない場合、Safari で直接見るのが最速
  2. transform: none; でアニメを切って確認 — 静的な形状は正しいか? transformとの合成が原因か切り分ける
  3. clip-path: none; でレイアウトを確認 — クリップなしで要素がどこにあるか確認してから戻す
  4. CanIUse で機能単位の対応状況を確認clip-path: path()(SVGパス)などは対応が遅れているケースあり

まとめ

  • Safariは-webkit-clip-path を併記すると安全
  • clip-path + transform は will-change や translateZ(0) でGPU合成を促す
  • box-shadow は切られる → filter: drop-shadow() に置換
  • polygonアニメーションは開始と終了で頂点数を揃える
  • 親のスタッキングコンテキストが不確実なら position: relative + isolation: isolate を付ける
  • 本質的にレイアウト計算は"クリップ前のサイズ"で行われるため、width/height/aspect-ratioで明示する

参考文献・ソース

NanToo 編集部

本記事は NanToo(ナンツー)運営の株式会社ヨネマスが編集・公開しています。 ツールの開発現場で得た知見をもとに、実務で役立つ内容を発信しています。

🔧 関連ツール

📚 関連記事

AD