在Web網頁中主要是以矩形分布的。而平面媒體則傾向于更多不同的形狀。造成這種差異的原因是因為缺少合适的工具去實現我們平面媒體中的内容。這也就造成了很多設計師的創意發揮,就算是有創意,前端實現也将付出巨大的開發成本。

雖然CSS Shapes Module Level 1(CSS形狀模塊标準1)的規範出現,可以打破矩形設計的限制。但仍需要一些不規則的圖形。而早前實現一些不規則的圖形,都需借助其它的元素功能,比如CSS繪制圖形,很多時候就依賴于僞元素,或多個元素。如此一來,CSS Shapes依舊無法發揮其強大的功能,讓我們的Web打破常規的矩形布局。不過值得慶幸的是,CSS的clip-path出現,它可以幫助我們繪制很多特殊的圖形(不規則的圖形),比如:

clip-path

那麼這篇文章,我們就一起來了解這個屬性。

基本概念

clip-path從單詞"clip path"的直譯上來說,表示的就是裁剪路徑。既然有裁剪,咱們就來了解這裡面的幾個簡單的概念。

裁剪就是從某樣東西剪切一塊。比如說,我們在<img>元素上,根據需要,剪切一部分需要留下的區域。而在整個裁剪中,将會碰到兩個相關的概念:裁剪路徑(Clipping Path)裁剪區域(Clipping Region)

裁剪路徑是我們用來裁剪元素的路徑,它标記了我們需要裁剪的區域。它可以是個簡單的形狀(比如Web中常見的矩形),也可以是一個複雜的多邊形(不規則的多邊形)。

裁剪區域是裁剪路徑閉合後所包含的全部區域。

clip-path

這樣一來,元素分為兩部分,裁剪區域和裁剪區域外。浏覽器會裁剪掉裁剪區域以外的區域,不僅是背景及其它類似的内容,也包括bordertext-shadow 等。更贊的是,浏覽器不會捕獲元素裁剪區域以外的 hoverclick 等事件。

即使如今一些特定元素不受長方形限制,但實際上元素周圍的内容還是會認為元素是原始形狀(長方形)的,并按此進行文檔流的布局。要想使周圍元素根據元素裁剪後的形狀進行布局,可以使用 shape-outside屬性。有關于shape-outside相關詳細的介紹,可以閱讀有關于CSS Shapes相關的教程,這裡不做過多闡述。

舊的clip

CSS Masking Module Level 1中也提供了一個clip屬性。可以說clip是CSS中出現的第一種裁剪技術。其實了解過clip的同學都知道,它就是通過overflow:hidden将裁剪區域外的元素隐藏掉了。可以說它不是真正的裁剪。

clip屬性到目前為止,僅支持rect()函數,就是裁剪出一個矩形(其它形狀還無法實現)。

clip: rect(<top>, <right>, <bottom>, <left>);

在CSS2.1中,rect()<top><bottom>指定偏移量是從元素盒子頂部邊緣算起;<left><right>指定的偏移量是從元素盒子左邊邊緣算起。

clip

更為無奈的是,clip屬性隻能在元素設置了position:absolute或者position:fixed起作用。無法在設置position:relativeposition:static上工作。

在CSS中,clip 屬性是已過時的,也就是說它已經不再建議被使用,因為有一個更新的、規範的版本,各個浏覽器也将集中努力使用它。

當然,clip也是有一些優勢的:因為clip是運行在浏覽器中的,它可能會一直有效。而浏覽器對它的支持是非常強大的:幾乎是有史以來的每一個浏覽器。另外,我也聽說過了,它作出的動畫效果勝過其它的新方法。

但是比起它的優勢,clip有兩個更為重要的弱點,這也使得它難以被廣泛地使用:

  • clip 隻對絕對定位的元素有效
  • clip 隻能用于矩形,即rect()函數

這真的是非常大的限制!所以來讓我們接着說接下來更為重要的屬性clip-path

如果你是第一次接觸過clip屬性,我建議您花點時間閱讀一下這篇文章,它能幫助你對clip有一個簡單的了解。

clip-path語法

W3C官方規範提供的clip-path語法:

clip-path: <clip-source> | [ <basic-shape> || <geometry-box> ] | none

其默認值是none。另外簡單介紹clip-path幾個屬性值:

  • clip-source: 可以是内、外部的SVG的<clipPath>元素的URL引用
  • basic-shape: 使用一些基本的形狀函數創建的一個形狀。主要包括circle()ellipse()inset()polygon()。具體的說明可以看CSS Shapes中有關于說明。另外在CSS Shapes 101一文中也有詳細介紹。
  • geometry-box: 是可選參數。此參數和basic-shape函數一起使用時,可以為basic-shape的裁剪工作提供參考盒子。如果geometry-box由自身指定,那麼它會使用指定盒子形狀作為裁剪的路徑,包括任何(由border-radius提供的)的角的形狀。

開始使用clip-path

在開始使用clip-path繪制圖形,或者說裁剪圖形之前,有兩點需要大家注意:

  • 使用clip-path要從同一個方向繪制,如果順時針繪制就一律順時針,逆時針就一律逆時針,因為polygon是一個連續線段,若線段彼此有交集,裁剪區域就會有相減的情況發生,當然如果你特意需要這樣的效果除外。
  • 如果繪制時采用比例的方式繪制,長寬就必須要先行設定,不然有可能繪制出來的長寬和我們想像的就會有差距,使用像素繪制就不會有這樣的現象。

先來看一個使用polygon()函數繪制的示例:

img {
  clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
}

這段代碼會将所有的圖片裁剪為菱形。但是為什麼圖片會被裁剪為菱形而不是梯形或平行四邊形之類的呢?這主要取決于函數頂點的值。下圖将說明一切:

clip-path

每個點的第一個坐标值決定了它在 x 軸上的位置,第二個坐标值指定了它在 y 軸的位置,所有點是順時針繪制的。比如菱形最右邊的點,它位于 y 軸下方一半處,所以它的 y 坐标是 50%。同時這個點位于 x 軸的最右側,所以它的 x 坐标是 100%。其它點的坐标同理可得。

最後效果如下所示:

記得以前CSS繪制圖形總得束手束腳,而且還得想法設法,使用clip-path繪制什麼六邊形、八邊形、五角形、心形等,都不再是難事了。OXXO.STUDIO有一篇文章《運用 clip-path 的純 CSS 形狀變換》詳細介紹了這些圖形是如何繪制的。當然除此之外,在線的CSS clip-path maker提供了很多不規則的圖形案例:

利用 geometry-box 裁剪元素

在具體使用geometry-box來裁剪元素之前,對geometry-box做一下相關的了解。

geometry-box可以是shape-boxfillstroke或者view-box。其中shape-box應用于HTML元素,它具有四種值:margin-boxborder-boxpadding-boxcontent-box

shape-box

來看個簡單的示例:

.clip-me {
    clip-path: polygon(10% 20%, 20% 30%, 50% 80%) margin-box;
    margin: 10%;
}

在上例中,元素的 margin-box 會作為參考,來決定裁剪點的實際位置。點(10%,10%)是 margin-box 的左上角,所以clip-path 的定位會根據此點進行計算。

其實shape-box和CSS Shapes中的引用框概念非常類似,有關于這方面的介紹,可以花點時間閱讀《理解CSS Shapes的引用框》一文。

如果geometry-boxbasic-shape一起使用,可以引用basic-shape提供的引用框。其作用和shape-outside屬性類似,更多的細節可以看看shape-outside屬性介紹

如果geometry-box由自身指定,那麼它會使用指定盒子形狀作為裁剪的路徑,包括任何(由border-radius提供的)的角的形狀。

除了shape-box值,還可以運用SVG元素上,它具有另外三個值:fillstrokeview-box

clipPath 和clip-path

在SVG中有一個clipPath元素。<clipPath>元素不會直接在頁面上呈現,他唯一的作用就是可以通過clip-path來引用。它和CSS的clip-path還是有很大的區别。有關于兩者的詳細介紹可以閱讀《CSS和SVG中的剪切:clip-path屬性和<clipPath>元素》一文。

而很多時候兩者可以結合一起使用。

你不需要在CSS中定義clip-path的值,因為它能夠引用SVG中定義的 <clipPath>标簽元素。下面是它的使用示例:

HTML

<img class="clip-svg" src="harry.jpg" alt="Harry Potter">
<svg width="0" height="0">
  <defs>
    <clipPath id="myClip">
      <circle cx="100" cy="100" r="40" />
      <circle cx="60" cy="60" r="40" />
    </clipPath>
  </defs>
</svg>

CSS

.clip-svg {
    clip-path: url(#myClip);
}

clip-path和masking

剪裁和遮罩都是用來隐藏元素的一些部分、顯示其他部分的。當然了,這兩者還是有區别的。區别主要在于這幾方面:他們能做的東西,不同的語法,涉及到的不同技術,是新的還是舊的,以及浏覽器支持的差異。

兩者最主要的區别:遮罩使用的是圖像,剪裁使用的是路徑

想象一張從左到右、從黑到白漸變的正方形圖像,它可以是一個遮罩。對于應用了這個漸變遮罩圖像的元素,它在遮罩圖像的黑色部分是透明(透視)的,而在遮罩圖像的白色的部分是不透明(正常)的。所以作出的結論是:這個元素是從左到右淡入的。

而剪裁一直都是矢量路徑的。路徑之外的部分是透明的,路徑裡邊的部分是不透明的。

個人覺得有點混亂。因為很多時候可能會碰到某個關于遮罩的教程用的是一個在黑色上有白色矢量形狀的遮罩圖像,這和剪裁基本是同一個原理。但這還好,它隻是混淆了一點東西。

有關于兩者相關的詳細介紹可以點擊這裡閱讀

clip-path和CSS Shapes

前面已經多次提到CSS Shapes了,是的,因為CSS Shapes可以幫助我們打破常規則的Web排版,讓Web頁面可以像媒體雜志一樣布局,這将是激動人心的一件事情。

而在CSS Shapes中同樣會有clip-path的身影。

clip-path接收與basic-shape相同的形狀函數和值(前面提到過)。如果我們定義相同的多邊形形狀,同時用于shape-outsideclip-path屬性上,它将裁掉圖像上你定義的形狀之外的圖像。

img.right {
    float: right;
    height: 100vh;
    width: calc(100vh + 100vh/4);
    shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);
    /* clip the image to the defined shape */
    clip-path: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);
}

結果如下:

clip-path

看下在線示例:

有關于這方面的詳細介紹,可以點擊這裡

clip-path示例和工具

前面内容簡單的提到過了,clip-path是一個強大的屬性,除了自身能實現一些特殊效果之外,還可以和SVG結合在一起。另外還可以和Masking以及CSS Shapes在一起,做出我們意想不到的效果。那麼有關于clip-path相關的案例,網上已經有大把了。除此之外,clip-path還有一些在線的工具,可以直接幫助我們做一些事情。比如Chrome插件CSS Shapes 編輯器Clip Path生成器CSS clip-path Maker: Clippy

最後強列建議大家收藏好下面這篇文章,因為這篇文章整理了18個有關于clip-path的教程、案例和工具

clip-path

浏覽器兼容性

看到這裡,大家肯定會問,浏覽器兼容性如何?

IE 和 Edge 不支持這個屬性。Firefox 僅部分支持 clip-path (它隻支持 url() 語法)。但是 47 以上的版本,激活 Firefox 的 layout.css.clip-path-shapes.enabled選項就可以支持這個屬性了。

Chrome、Safari 和 Opera 需要使用 -webkit- 前綴支持此屬性。不幸的是,它們還不支持外部的 SVG 形狀。更多浏覽器支持性信息如下:

參考資料

總結

本文介紹了有關 clip-path 的基本内容,可以幫助你入門。學習使用這個屬性并不會花費太多的時間,但是創造性的使用就需要多多練習了。當浏覽器廣泛支持此屬性時,你就可以使用 clip-path制作出酷炫的效果了。