開始使用 CSS 形狀

納入自訂路徑周圍的內容

Razvan Caliman
Razvan Caliman

長久以來,網頁設計人員不得不在矩形的限制範圍內建立網頁。大部分的創意冒險仍然是單純的方塊設計,因為大部分的創意冒險都會變成沒有矩形的版面配置。我們將自 Chrome 37 開始,導入 CSS 形狀。 CSS 形狀可讓網頁設計人員在自訂路徑 (例如圓形、刪節號和多邊形) 周圍納入內容,因此不必受限於矩形。

形狀可以手動定義,也可以從圖片中推論。

一起來看看這個簡單的範例。

或許在第一次疊加圖片時,您可能跟我一樣,看著包含透明部分的內容來填滿整個空間,而這只會對元素周圍的矩形環繞形狀感到失望。您可以使用 CSS 形狀解決這個問題。

從圖片擷取形狀
<img class="element" src="image.png" />
<p>Lorem ipsum…</p>

<style>
.element{
  shape-outside: url(image.png);
  shape-image-threshold: 0.5;
  float: left;
}
</style>

shape-outside: url(image.png) CSS 宣告會指示瀏覽器從圖片擷取形狀。

shape-image-threshold 屬性會定義要用來建立形狀的像素最小不透明度等級。這個值必須介於 0.0 (完全透明) 和 1.0 (完全不透明) 之間。因此,shape-image-threshold: 0.5 表示只有不透明度 50% 以上的像素才會用來建立形狀。

這裡的 float 屬性是關鍵。雖然 shape-outside 屬性會定義內容環繞區域的形狀,但如果沒有浮動,您也不會看到形狀效果。

元素的 float 值的相對浮動區域。舉例來說,如果含有咖啡杯圖片的元素向左浮動,系統會在杯子的右側建立浮動區域。即使您可以設計圖片兩側有間隔,內容仍只會沿著浮點屬性指定的相反方向 (左側或右側) 繞過形狀,無法兩者同時圍繞。

日後,只要是未以 CSS 排除功能浮動的元素,皆可使用 shape-outside

手動建立形狀

除了從圖片中擷取形狀之外,您也可以手動撰寫圖片。建立形狀時,您可以從幾個函式值中進行選擇:circle()ellipse()inset()polygon()。每個形狀函式都接受一組座標,並與建立座標系統的參照方塊配對。稍後將詳細介紹參考方塊。

Circle() 函式

插圖:Circle() 形狀值

圓形形狀值的完整標記法為 circle(r at cx cy),其中 r 是圓形的半徑,cxcy 則是圓形中心在 X 軸和 Y 軸上的座標。圓形中心的座標為選用。如果省略這些元素,將使用元素中心 (其對角線的交集) 做為預設值。

.element{
  shape-outside: circle(50%);
  width: 300px;
  height: 300px;
  float: left;
}

在上述範例中,內容會在圓形路徑的外圍繞。單一引數 50% 會指定圓形的半徑,在本例中,範圍是元素寬度或高度的一半。變更元素的尺寸會影響圓形的半徑。這是 CSS 形狀回應方式的基本範例。

繼續之前,請注意一個重點:請注意,CSS 形狀只會影響元素周圍的浮動區域形狀。如果元素有背景,就不會遭到形狀裁剪。為達成此效果,必須使用 CSS 遮罩的屬性 (clip-pathmask-image)。clip-path 屬性非常實用,因為它遵循與 CSS 形狀相同的標記法,因此您可以重複使用值。

`circle()` 形狀 + clip-路徑的插圖

本文件各處的插圖都會使用裁剪功能醒目顯示形狀,協助你瞭解效果。

返回圓形圖案。

使用百分比來表示圓形半徑時,系統會使用更複雜的公式來計算這個值:sqrt(width^2 + height^2) / sqrt(2)。瞭解這一點有助於瞭解當元素尺寸不相等時,最終產生的圓形形狀。

所有 CSS 單位類型可用於形狀函式座標,例如 px、em、rem、vw、vh 等。你可以視需要挑選靈活彈性或高度彈性的範本。

您可以設定圓形中心點的明確值,調整圓形的位置。

.element{
  shape-outside: circle(50% at 0 0);
}

這會將圓形中心放在座標系統的原點。座標系統為何?我們也在這裡介紹了參考資料方塊。

CSS 形狀的參考方塊

參考方塊是元素周圍的虛擬方塊,建立用來繪製形狀及定位形狀的座標系統。座標系統的起點位於左上角, X 軸指向右側,Y 軸則指向下方。

CSS 形狀的座標系統

請注意,shape-outside 會變更內容包裝周圍的浮動區域形狀。浮動區域會延伸至由 margin 屬性定義的方塊外邊緣。這會稱為 margin-box,如果沒有明確提及形狀,就會是形狀的預設參照方塊。

以下兩個 CSS 宣告的結果相同:

.element{
  shape-outside: circle(50% at 0 0);
  /* identical to: */
  shape-outside: circle(50% at 0 0) margin-box;
}

我們尚未在元素上設定邊界。此時,可以安全地假設座標系統的起點和圓中心位於元素內容區域的左上角。設定邊界時,此變更如下:

.element{
  shape-outside: circle(50% at 0 0) margin-box;
  margin: 100px;
}

座標系統的起點現在位於元素的內容區域 (100px 向上和 100px),和圓形中心一樣。圓形半徑的計算值也會不斷增加,以因應 margin-box 參照方塊建立的座標系統表面的增加。

帶有邊界和無邊界的邊界座標系統
我們提供「margin-box」、「border-box」、「padding-box」和「content-box」這幾個參考方塊選項,這些名稱所對應的是界線。我們先前介紹過「margin-box」。「border-box」受限於元素外緣的外緣,而「padding-box」會受限於元素的邊框間距,而「content-box」則與元素內內容使用的實際表面區域相同。
所有參考方塊的插圖

透過 shape-outside 宣告,一次只能使用一個參考方塊。每個參考方塊都會以不同 (有時甚至細微) 的方式影響形狀。請參閱另一篇文章深入探討,並協助您瞭解 CSS 形狀的參考方塊

ellipse() 函式

ellipse() 形狀值的插圖

橢圓看起來像擠壓的圓圈。這些元素定義為 ellipse(rx ry at cx cy),其中 rxry 是 X 軸和 Y 軸的橢圓半徑,而 cxcy 是橢圓中心的座標。

.element{
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

百分比值是由座標系統的維度計算。這裡不需要好玩的數學。您可以省略橢圓中心的座標,讓系統從座標系統中心推測這些座標。

您也可以使用關鍵字定義 X 和 Y 軸的半徑:farthest-side 產生的半徑等於橢圓形中心與參考方塊側邊之間的距離,closest-side 則代表與本邊距最遠的距離 (使用中心和一側的最短距離)。

.element{
  shape-outside: ellipse(closest-side farthest-side at 50% 50%);
  /* identical to: */
  shape-outside: ellipse(150px 300px at 50% 50%);
  width: 300px;
  height: 600px;
}

當元素尺寸 (或參考方塊) 產生無法預測的改變,但您希望橢圓形狀隨之調整時,這個做法就非常實用。

相同的 farthest-sideclosest-side 關鍵字也可用於 circle() 形狀函式中的半徑。

Polygon() 函式

Polygon() 形狀值的插圖

如果圓形和刪節號的限制過多,多邊形圖形函式會開啟一個選項。格式為 polygon(x1 y1, x2 y2, ...),您可指定多邊形每個頂點 (點) 的 x y 座標組合。可指定多邊形的配對數量下限為三個,也就是三角形。

.element{
  shape-outside: polygon(0 0, 0 300px, 300px 600px);
  width: 300px;
  height: 600px;
}

控制在座標系統上。對於回應式多邊形,您可以使用百分比值做為部分或所有座標。

.element{
  /* polygon responsive to font-size*/
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  width: 20em;
  height: 40em;
}

透過從 SVG 匯入的選用 fill-rule 參數,指示瀏覽器在自我相交路徑或封閉形狀時,如何考量多邊形的「內部性」。Joni Trithall 非常清楚地說明 fill-rule 屬性在 SVG 中的運作原理。如未定義,fill-rule 預設為 nonzero

.element{
  shape-outside: polygon(0 0, 0 100%, 100% 100%);
  /* identical to: */
  shape-outside: polygon(nonzero, 0 0, 0 100%, 100% 100%);
}

inset() 函式

inset() 形狀函式可讓您建立矩形形狀來包裝內容。考量到 CSS 形狀可透過簡易方塊免費網路內容構成的先例,這聽起來可能會違反直覺。那可能還好。我尚未找到 inset() 的用途,但這個用途目前無法透過浮點值和邊界,或與 polygon() 達成。雖然 inset() 提供的矩形形狀運算式比 polygon() 更清晰,

插邊形狀函式的完整標記法為 inset(top right bottom left border-radius)。前四個位置引數會從元素邊緣往內偏移。最後一個引數是矩形形狀的邊界半徑。至於不一定要填寫,該字串與你在 CSS 中使用的 border-radius 簡寫標記法一致。

.element{
  shape-outside: inset(100px 100px 100px 100px);
  /* yields a rectangular shape which is 100px inset on all sides */
  float: left;
}

使用參考方塊建立形狀

如果您不為 shape-outside 屬性指定形狀函式,可以讓瀏覽器從元素的參照方塊擷取形狀。預設參照方塊為 margin-box。目前為止都沒有比較怪東西,這就是花盆已經運作的了。不過,運用這項技巧,您就可以重複使用元素的幾何圖形。我們來看看 border-radius 屬性。

如果使用這種元件將浮動元素的圓角填入,即可得到裁剪效果,但浮動區域仍為矩形。新增 shape-outside: border-box,以納入 border-radius 建立的輪廓。

使用邊框方塊參照方塊,從元素的框線半徑中擷取形狀
.element{
  border-radius: 50%;
  shape-outside: border-box;
  float: left;
}

當然,您也可以按照上述方式使用所有參考方塊。以下為衍生形狀的另一個使用 - 偏移拉引號。

使用內容方塊參考方塊建立偏移提取式引用

可以透過只使用浮點屬性和邊界屬性來實現偏移拉引號效果。不過,您必須將引用元素放置在 HTML 樹狀結構中希望轉譯的時間點。

以下說明如何達到相同的偏移提取式效果,同時增加彈性:

.pull-quote{
  shape-outside: content-box;
  margin-top: 200px;
  float: left;
}

我們為形狀的座標系統明確設定 content-box 參照方塊。在此情況下,引文中的內容量會決定外部內容圍繞的形狀。無論其在 HTML 樹狀結構中的位置為何,margin-top 屬性都用於放置提取報價的位置 (偏移)。

形狀邊界

您會發現,在形狀周圍納入內容可能會導致元素與元素之間過度貼合。您可以利用 shape-margin 屬性在形狀周圍加入間距。

.element{
  shape-outside: circle(40%);
  shape-margin: 1em;
  float: left;
}

這種效果與慣用的 margin 屬性類似,但 shape-margin 只會影響 shape-outside 值前後的空格。只有在座標系統中設有空間時,它才會在形狀周圍新增間距。因此,上方範例中的圓形半徑設定為 40%,而非 50%。如果半徑設為 50%,圓形會佔滿座標系統的所有空間,以致 shape-margin 的效果。請注意,形狀最終受限於元素的 margin-box (元素及其周圍的 margin)。如果形狀較大且溢位,就會裁剪為 margin-box,最終會得到矩形。

請務必瞭解 shape-margin 只接受一個正值。沒有長效標記。但圓形的形狀是形狀的邊界嗎?

建立形狀動畫

您可以將 CSS 形狀與許多其他 CSS 功能混用,例如轉場效果和動畫。不過,我必須強調,使用者在閱讀文字版面配置時,會覺得很煩。如果您決定要使用動畫形狀,請密切留意相關體驗。

您可以為 circle()ellipse() 形狀定義其可插入的值,藉此為形狀和中心製作動畫效果。有可能從 circle(30%) 飛往 circle(50%)。不過,在 circle(closest-side)circle(farthest-side) 之間建立動畫效果就會限制瀏覽器。

.element{
  shape-outside: circle(30%);
  transition: shape-outside 1s;
  float: left;
}

.element:hover{
  shape-outside: circle(50%);
}
動畫圓圈的 GIF

polygon() 形狀建立動畫時,可以達到更多有趣的效果,重點是請注意,多邊形在兩個動畫狀態之間必須有相同數量的頂點。如果您新增或移除頂點,瀏覽器便無法插入。

其中一項技巧是新增所需的頂點數量上限,然後將它們集中成動畫狀態,也就是您要減少形狀的邊緣。

.element{
  /* four vertices (looks like rectangle) */
  shape-outside: polygon(0 0, 100% 0, 100% 100%, 0 100%);
  transition: shape-outside 1s;
}

.element:hover{
  /* four vertices, but second and third overlap (looks like triangle) */
  shape-outside: polygon(0 0, 100% 50%, 100% 50%, 0 100%);
}
動畫三角形的 GIF

將內容納入形狀

Alice 在 Wonderland 示範的螢幕截圖,使用 CSS 形狀包裝內容

CSS 形狀規格的初始草稿包含 shape-inside 屬性,可讓您將內容納入形狀中。Chrome 和 Webkit 的實作已有一段時間。然而,將任意位置的內容納入自訂路徑中,需要耗費大量心力與研究,才能涵蓋所有可能情況並避免錯誤。因此,shape-inside 屬性已延後到 CSS 形狀 2,並撤銷了實作。

然而,只要稍有點努力並稍加折衷,您仍然能達到將內容納入自訂形狀的效果。做法是使用兩個浮動元素搭配 shape-outside,並放置在容器的另一側。而破壞就是您必須使用一或兩個沒有語意含義的空白元素,但可用來做為在內部建立形狀錯覺的阻礙。

<div>
  <div class='left-shape'></div>
  <div class='right-shape'></div>

  Lorem ipsum...
</div>

.left-shape.right-shape 的跨圈元素在容器頂端的位置非常重要,因為這些元素會向左或向右浮動,藉此抑制內容。

.left-shape{
  shape-outside: polygon(0 0, ...);
  float: left;
  width: 50%;
  height: 100%;
}

.right-shape{
  shape-outside: polygon(50% 0, ...);
  float: right;
  width: 50%;
  height: 100%;
}
插圖:Alice 示範的形狀空間

這個樣式會讓兩個浮動的虛線會佔據元素中的所有空間,但 shape-outside 屬性卻能保留空間供其餘內容使用。

如果瀏覽器不支援 CSS 形狀,那麼將所有內容向下推,會造成異常效果。因此,請務必逐步使用此功能。

在前面的形狀動畫範例中,您就會注意到文字轉移可能會造成困擾。並非所有用途都能套用動畫形狀。但是,您可針對與 CSS 形狀互動的其他屬性加上動畫效果,視需要增添效果。

在「Alice in Wonderland」示範的 CSS 形狀中,我們使用了捲動位置來變更內容的頂端邊界。文字會在兩個浮動元素之間擠壓。當它向下移動時,必須根據兩個浮動式元素的 shape-outside 重新安排版面配置。這讓使用者認為文字走在兔子洞裡,而且可以提升敘事體驗。無邊框界線?不一定。但看起來很酷

由於文字版面配置是由瀏覽器原生完成,因此效能比使用 JavaScript 解決方案更好。不過,如果在捲動時變更邊界頂端,確實會觸發許多重新版面配置和繪製事件,而這可能會大幅降低效能。請謹慎使用!然而,如果在沒有動畫的情況下使用 CSS 形狀,就無法有效發揮預期效果。

漸進式增強

請先假設瀏覽器不支援 CSS 形狀,並在偵測到這項功能時加以擴充。Modernizr 是執行功能偵測的絕佳解決方案,可在「非核心偵測」部分中測試 CSS 形狀。

部分瀏覽器可以透過 @supports 規則在 CSS 中提供功能偵測功能,不需要使用外部程式庫。Google Chrome (也支援 CSS 形狀) 能瞭解 @supports 規則。請透過下列方式逐步強化:

.element{
  /* styles for all browsers */
}

@supports (shape-outside: circle(50%)){
  /* styles only for browsers which support CSS Shapes */
  .element{
    shape-outside: circle(50%);
  }
}

Lea Verou 詳閱如何使用 CSS @supports 規則的詳細說明。

與 CSS 排除條件區分

我們至今所知,CSS Shapes 過去在規格的早期階段稱為「CSS 排除和形狀」。雖然命名方式似乎很細微,但實際上是非常重要的。CSS 排除是現在獨立的規格,可針對任意位置的元素包裝內容,不需要使用 float 屬性。假設將內容包裝在絕對位置的元素周圍,這是 CSS 排除條件的用途。CSS 形狀只會定義內容環繞的路徑。

因此,形狀和排除項目雖然各自獨立,但會相輔相成。目前瀏覽器支援 CSS 形狀,但 CSS 排除功能尚未與形狀互動一起實作。

CSS 形狀使用工具

您可以在傳統圖片編寫工具中建立路徑,但這些項目在本文撰寫期間無法匯出,以便匯出 CSS Shapes 值的必要語法。即使這麼做,努力做到的成果也比較不切實際。

CSS 形狀應用於瀏覽器,以回應網頁上的其他元素。建議您透過視覺化方式,瞭解調整形狀在周圍內容中所造成的影響。以下幾項工具可協助您完成這個工作流程:

括號Brackets 適用的「CSS Shapes Editor」擴充功能會使用程式碼編輯器的即時預覽模式,疊加在可編輯形狀值的互動式編輯器上。

Google ChromeGoogle Chrome 的「CSS Shapes Editor」擴充功能擴充了瀏覽器的開發人員工具,並提供相關控制項來建立和編輯形狀。這會在所選元素上方放置互動式編輯器。

Google Chrome 的檢查器內建支援醒目顯示圖案的功能。將滑鼠遊標懸停在含有 shape-outside 屬性的元素上,系統會醒目顯示該元素,表示其形狀。

使用圖片建立形狀:如果您想讓瀏覽器從圖片擷取形狀,而想讓瀏覽器擷取圖片,Rebecca Hauck 撰寫了很好的 Photoshop 教學課程

Polyfill:Google Chrome 是第一個提供 CSS Shape 的主要瀏覽器。我們即將在 Apple iOS 8 和 Safari 8 中支援這項功能。但其他瀏覽器供應商日後可能會考慮使用。在那之前,可以使用 CSS Shapes polyfill 來提供基本支援。

結論

網頁的內容大多採用簡單的方塊,而 CSS Shapes 可用來建立風格明確的版面配置,彌合網頁設計和列印設計之間的擬真度。當然,形狀可能會遭到濫用,並製造幹擾元素。不過,只要採用品味和仔細判斷,塑造出更佳的內容呈現方式,並以獨特方式聚焦於使用者的注意力。

我會為您留下其他人的一系列作品,其中大部分是出自紙本,對於非矩形版面配置也很有趣。希望以上說明能鼓勵您試用 CSS 形狀,嘗試新的設計構想。

感謝 Pearl Chen、Alan Stearns 和 Zoltan Horvath 感謝閱讀這篇文章並提供寶貴的見解。