CSS clip-path 常見陷阱:陰影、插值、版面與 Safari 相容性
GDESIGN
設計發布: 7 分鐘閱讀

CSS clip-path 常見陷阱:陰影、插值、版面與 Safari 相容性

CSS clip-path 可以改變元素的可見形狀,但不會同時改變所有與方框有關的行為。陰影被裁走、圖示周圍仍有空位,未必是瀏覽器出錯。本文先說明裁剪、插值及版面尺寸的規則,再把 WebKit 曾出現的 SVG 參照問題獨立處理,方便逐項排查。

日文原文發布: 2026-04-17

先了解 clip-path 的基本用法

clip-path 可把元素裁成多邊形、圓形、橢圓形,或其他支援的路徑形狀。

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

主要瀏覽器已廣泛支援基本裁剪功能,但不同語法的支援程度仍須分開確認。舊版 Safari 曾需要 -webkit-clip-path 前綴;如要支援這些版本,可把相容宣告放在前面,標準宣告放在後面。請查閱相容性資料,並在實際需要支援的裝置及版本測試。

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

WebKit 的過往問題:SVG 參照與堆疊上下文

WebKit Bug 233553 記錄了一個特定個案:在 <img> 使用 SVG 參照 clip-path: url(#shape),再加入 transform 等會建立堆疊上下文(stacking context)的宣告,圖片可能完全消失。該個案的 SVG 使用 clipPathUnits="objectBoundingBox"。

修正已於 2024 年 11 月 5 日合併至 WebKit,問題狀態為 RESOLVED FIXED。合併日期本身不足以確定哪個 Safari 正式版本最先包含修正。因此,不應把它描述成現行 Safari 普遍存在的未解決問題,也不能由此推論所有 polygon() 與 transform 的組合都有問題。

/* 歷史個案的 CSS 片段;須另外提供圖片及 SVG #shape 定義。 */
.masked-image {
  clip-path: url(#shape);
  transform: translate3d(0, 0, 0); 
}

排查時,請在目標 Safari 版本依次測試只有 SVG 參照、只有建立堆疊上下文的宣告,以及兩者同時存在的情況。若仍能重現問題,可移除不必要的合成相關宣告;如果基本形狀能表達同一輪廓,也可考慮 polygon(),然後在目標裝置驗證。不要把促使合成的宣告當成通用修正,因為它可能再次構成上述個案的觸發條件。

要保留外陰影:外層加濾鏡,內層做裁剪

超出裁剪範圍的 box-shadow 也會被裁走,這是規格定義的行為,並非 Safari 特有問題。在不透明元素上直接加入一般外陰影,不會自動得到沿新輪廓向外延伸的陰影。

/* 裁剪範圍以外的陰影不會顯示。 */
.badge {
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
  box-shadow: 0 4px 12px rgba(0,0,0,.2);  
}

CSS Masking 定義的處理次序是先套用濾鏡,再做裁剪。因此,即使改用 filter: drop-shadow(),只要放在同一元素,陰影仍會受到裁剪。做法是把濾鏡放到外層容器,讓子元素負責 clip-path。以下範例前半是 HTML,由 .badge-shadow 開始則是 CSS,應分別放到對應位置。

<div class="badge-shadow">
  <div class="badge-shape">徽章</div>
</div>

.badge-shadow {
  display: inline-block;
  filter: drop-shadow(0 4px 12px rgba(0,0,0,.25));
}
.badge-shape {
  width: 160px;
  height: 100px;
  display: grid;
  place-items: center;
  background: #2563eb;
  color: white;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}

外層容器本身應保持透明背景,讓子元素的形狀成為陰影的輪廓。若更外層的祖先元素設有 overflow: hidden,陰影仍可能被裁走。濾鏡的繪製負擔與使用數量及面積有關,大量使用時應在目標裝置量度。

polygon() 插值:頂點數、填充規則及參照框要一致

起點與終點的多邊形頂點數不同,就不能對座標作連續插值。CSS 關鍵影格動畫及 Web Animations 可作離散切換;一般 CSS transition 預設不會為離散變化啟動過渡效果。以兩個關鍵影格及線性進度為例,離散切換發生在區間中點;預設 transition 則可直接套用新值,不能一概說成到最後才跳轉。

/* 無法連續插值:由 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%); }

要連續變形,先把兩端的頂點數對齊。把同一座標重複列出,可令額外的頂點在起始狀態與另一頂點重疊。

/* 起點及終點均有 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%);
}

CSS Shapes 對這種多邊形插值亦要求相同的參照框(reference box)及填充規則(fill-rule)。上例兩端均使用預設的 border-box 及 nonzero。只有 hover 形狀宣告並不會產生動畫;如要加入過渡效果,還須設定例如 transition: clip-path 250ms linear。亦應尊重用戶減少動態效果的偏好,例如在該設定下停用過渡效果。

父元素的 overflow 與子元素的裁剪要分開查

父元素的 overflow: hidden 與子元素的 clip-path 是兩項不同的裁剪限制,可見範圍會同時受兩者約束。若只看子元素的形狀,容易把父元素造成的裁剪誤當成 clip-path 出錯。

可先暫時把父元素的 overflow 改為 visible,檢查子元素單獨裁剪的結果,再恢復所需的父元素尺寸及 overflow 設定。未確認裁剪邊界前,不應隨意加入 position 或 isolation 作為修正。

.parent {
  position: relative;
  overflow: hidden;
}
.child {
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}

裁剪不會縮小版面所用的方框

clip-path 改變繪製結果,不會改變元素本身的幾何尺寸,也不會改變固有尺寸(intrinsic size)的計算。即使元素位於 Grid 或 Flexbox 內,被隱藏的部分仍屬於版面計算所用的方框,所以視覺上細小的圖示,周圍仍可能佔用空間。

請按需要設定 width 及 height。當某一方向的尺寸為 auto,aspect-ratio 可協助推算該方向的尺寸,但比例本身不會指定實際大小。父層限制及 Flex 項目的縮小行為也須一併檢查。

.icon {
  width: 32px;
  height: 32px;
  clip-path: polygon(25% 0%, 75% 0%, 100% 50%, 75% 100%, 25% 100%, 0% 50%);
}

建議的排查次序

  1. 目標是 Safari,就在 Safari 檢查。在 Chrome 運作正常,並不足以證明 Safari 也有相同結果。
  2. 先停止動畫及過渡效果,再獨立移除 transform。transform: none 不會停止 clip-path 的動畫。可利用開發者工具暫停動態效果,再逐項排除宣告。
  3. 暫時使用 clip-path: none。先查看原本的版面方框及位置,然後恢復裁剪形狀。
  4. 把語法支援與繪製正確性分開驗證。polygon、path 及 SVG 參照不是同一項相容性測試。CSS.supports() 可檢查宣告是否受支援,但不能證明繪製沒有錯誤。

重點回顧

  • 需要支援舊 Safari 時,把前綴宣告放在標準宣告之前。
  • WebKit Bug 233553 是已修正的過往個案;仍應在目標版本分開驗證 SVG 參照及堆疊上下文的條件。
  • 要讓外陰影沿形狀延伸,外層容器套用濾鏡,子元素套用裁剪。
  • 多邊形連續插值需要相同的頂點數、填充規則及參照框。
  • 父元素的 overflow 與子元素的 clip-path 應逐項排查。
  • 裁剪不會縮小版面方框;請設定所需尺寸,並檢查父層限制。

參考資料及來源

編輯說明

本文使用 AI 協助編輯,並在發布前由編輯核對。內容仍可能包含事實、理解或時效上的錯誤;作出重要決定前,請查閱所列的一手資料或官方文件。

相關文章