深入淺出 CSS Shape

譯者按:在WWDC 2014之前我就打算把這篇文章翻譯出來與大家分享;好在WWDC 2014上CSS Shape也露了一臉。快點閱讀本文,了解初出茅廬的CSS Shape是何方神聖吧!

n方框套方框:這就是目前網頁的樣子。長久以來,我們努力嘗試使用CSS來創建幾何形狀來突破這種限制。但是這些形狀無法影響其包含內容的形狀。同樣,元素的形狀也無法被其他元素所影響。

n2012年中旬,由Adobe提出的CSS Shape規範打破了這個限制。該規範的目標是為設計師提供一種新的方式,改變任意複雜形狀周圍或者內部內容布局。這些事情之情從來沒有被實現過,JavaScript也沒有。

例如,注意看在下面這個設計中文本環繞圓形圖片的樣子。沒有形狀的話,文本變成長方形——拋棄了精緻的邊緣,這種精緻可不是把設計帶到了下一個高度。

注意例子中文本是如何環繞圓形的那個碗的。通過CSS Shape,我們可以在網頁上創建類似的設計。

n接下來我們一起來看看Shape是如何工作,並開始使用它們。

瀏覽器支持

n目前只有Webkit Nightly和Chrome Canary支持CSS Shape,但是它的Model Level 1已經是Candidate Recommendation(候選推薦)了,因此在規範中定義的屬性和語法已經很穩定了。看來要不了多久其他瀏覽器也會實現CSS Shape。本Level的規範主要聚焦在幾個Shape屬性,這些屬性主要規定了形狀周圍的內容該如何環繞。更具體地說,它主要聚焦在形狀外圍屬性和其相關的屬性。

n結合其他一些最新的特性,例如Clipping與Masking、CSS Filters和Compositing與Blending,無需藉助像Photosho或者InDesign這樣 的圖像編輯器,CSS Shape允許我們創造更漂亮更精緻的設計。

n新版的CSS Shape規範也會聚焦形狀內部的內容。例如,現在可以很輕鬆地使用CSS創建一個菱形:只需把元素旋轉45度,然後把元素裡面的內容旋轉回來,相對頁面是橫向的。但是其形狀沒法受到其容器菱形的影響,因此還是矩形的。如果CSS Shape的shape-inside屬性實現了,我們就可以讓內容也是菱形的,要實現下這圖這樣的布局就沒什麼不可能了。

很快,CSS Shape將支持定義內部文本的形狀,比如這些菱形,與它的容器邊緣保持一致,而不溢出或者被截斷。

n為了在Chrome Canary中使用CSS Shape,你需要開啟試驗特性標記。如果你不知道怎麼打開,可以看看Adobe博客上的這篇參考。

創建CSS Shape

n你可以使用Shape屬性來給元素添加形狀。你需要給Shape屬性傳遞一個Shape函數。你可以給這個Shape函數傳遞參數來定義元素的形狀。

可以使用下面這幾個函數來定義形狀:

  • circle()
  • ellipse()
  • inset()
  • polygon()

n每個形狀都由一組坐標定義。有些函數接受坐標點作為參數,另外一些接受偏移量——但是最終它們都把形狀當做元素上一系列的點來描繪。在下面的例子中,我們將為大家講解每個方法所接受的參數。

n一個形狀還可以通過提取圖片的一個Alpha通道來定義。如果把一張圖片傳遞給Shape屬性,瀏覽器就會基於圖片的臨界值提取形狀。形狀的定義基於圖片上每一個點的Alpha通道是否高於臨界值。不過圖片必須是CORS compatible的。無論何種原因(比如圖片不存在),只要圖片不能正常顯示,就不會產生形狀。

n可接受上面這些函數作為值的Shape屬性有:

  • shape-outside:限制形狀周圍的內容
  • shape-inside:限制形狀內部的內容

n可以把shape-margin和shape-outside屬性結合使用,定義形狀周圍的margin,以此隔開浮動的內容和形狀,在形狀和內容之間留出更多的空間。與shape-outside和shape-margin對應一樣,shape-inside有對應的shape-padding屬性,用來添加內間距。

n一行代碼就可以使用Shape屬性和函數來定義一個形狀:

.element {n shape-outside: circle(); /* content will flow around the circle defined on the element */n}n

n或者:

.element {n shape-outside: url(path/to/image-with-shape.png);n}n

n但是。。。

n要讓這行CSS生效,必須滿足兩個條件:

  • 元素必須是浮動的。新版的CSS Shape可以循序我們定義一個非浮動元素的形狀,但是現在還不行;
  • 元素必須有確定的尺寸。元素的寬度和高度被用來建立這個元素上的坐標系統。

n看上面函數的定義,形狀都是由一組坐標定義的。因為這些點是坐標,所以需要坐標系統,這樣瀏覽器才知道把這些點放在元素的什麼位置上。因此,加上下面這段代碼上面的例子就可以正常工作。

.element {n float: left;n height: 10em;n width: 15em;n shape-outside: circle();n}n

n給定固有的維數並不會影響響應性(隨後我們進行更深入的探討)。

n既然形狀是由一系列帶坐標的點定義的,那更改這些點的坐標就可以相應的更改形狀。舉個例子,下面的六邊形是使用polygon()這個方法創建的。整個形狀由六個點構成。更改黃點的橫坐標將會影響產生的形狀,應用了此形狀元素的內部或者外部的內容布局方式也會受到影響。

如果元素右浮動,且應用了這個形狀,當在polygon()函數中黃點的橫坐標變化的時候,在元素左側的內容的浮動方式也會改變。

Shape的Reference Box

nCSS Shape在一個Reference Box(參考框)里被定義和創建,這個Box用來繪製在元素上的形狀。除了元素的寬高之外,元素的和模型——外邊界Box、內容Box、內邊界Box和邊框Box——也會作為元素上形狀大小的參考。

n默認把外邊界Box作為參考——因此,如果你應用了形狀的元素的底部有外邊界,則形狀會延伸到外邊jie上,而不是元素的邊框區域。如果你想使用其他Box值,你可以在形狀函數之後指定,然後傳遞給Shape屬性。

shape-outside: circle(250px at 50% 50%) padding-box;n

n上面這條規則中的padding-box關鍵字,把形狀限定在了元素的內邊框Box中。circle()函數定義了一個環狀的形狀,包括這個形狀的大小和在這個元素上的位置。

使用Shape函數定義Shape

n我們從把信息環繞在圓形的頭像上開始,我們常常在用戶信息或者推薦中用到。

使用CSS Shape,讓文本環繞圓形的用戶頭像。文本將不再是長方形的。

n使用circle()函數給頭像添加一個圓形:

<img src="http://api.randomuser.me/0.3.2/portraits/men/7.jpg" alt="profile image" />nn<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum itaque nam blanditiis eveniet enim eligendi quae adipisci?</p>nn<p>Assumenda blanditiis voluptas tempore porro quibusdam beatae deleniti quod asperiores sapiente dolorem error! Quo nam quasi soluta reprehenderit laudantium optio ipsam ducimus consequatur enim fuga quibusdam mollitia nesciunt modi.</p>n

n你可能會問,「為什麼不使用border-radius來做出圖片的圓角?」答案就是border-radius無法影響元素周圍或者內部的內容的布局。它只能影響元素的邊框和背景。背景區域會被裁剪成圓角,但是它功能僅限於此。元素內部的內容任然是矩形的,而且周圍的內容還是把元素當做一個矩形的存在——本質上它還是。

n我們使用border-radius讓圖片變圓——我們通常都是這樣讓圖片等其他元素變圓的。圖片bianyuan

img {n float: left;n width: 150px;n height: 150px;n border-radius: 50%;n margin-right: 15px;n}n

不添加CSS Shape,文本任然把圖片當做矩形的,因此還是圍繞成一個矩形,而不是圓的。

n在不支持CSS Shape屬性的瀏覽器中,原型圖片周圍的內容就像環繞在一個不是圓形的圖片周圍。這就是在較老瀏覽器中CSS Shape降級的效果。的

n為了改變內容布局以適應特定的形狀,我們使用Shape屬性:

img {n float: left;n width: 150px;n height: 150px;n border-radius: 50%;nn shape-outside: circle();n shape-margin: 15px;n}n

n有了這些代碼,文本會看到一個圓的形狀在圖片上,環繞之,就像第一張截圖那樣(你可以在這裡看到)。在不支持的瀏覽器中,將降級為第二張圖顯示的哪樣。

n你可以像上面那樣使用circle()函數,也可以傳遞參數給它。下面是它的語法:

circle() = circle( [<shape-radius>]? [at <position>]? )n

n問號標示這些參數是可選的。省略的參數將會被瀏覽器使用默認值補全。如果你直接使用circle()而未指定圓形的位置,它會定義一個放在元素正中間的圓形。

n你可以指定圓形的半徑,什麼單位都可以(px、em、pt等等)。你甚至可以指定使用closest-side或者furthest-side作為半徑,closest-side是默認值,即瀏覽器會把從中點到最近邊的長度作為圓形的半徑。furthest-side則是使用中心到最遠邊的距離。

shape-outside: circle(farthest-side at 25% 25%); /* defines a circle whose radius is half the length of the longest side, positioned at the point of coordinates 25% 25% on the element』s coordinate system*/nnshape-inside: circle(250px at 500px 300px); /* defines a circle whose center is positioned at 500px horizontally and 300px vertically, with a radius of 250px */n

eclipse()函數與circle()還是函數是一樣,除了接受兩個半徑參數以外(後者是一個參數列表)——一個是x軸的半徑,一個是y軸的——是一直的。

ellipse() = ellipse( [<shape-radius>{2}]? [at <position>]? )n

n與circle和eclipse沒有直接的關係,inset()函數再元素內部創建一個矩形。既然元素本身就是矩形的,我們當然不需要更多的矩形。inset()實際上可以幫助我們在元素內部創建一個帶有圓角的矩形。文本內容可以環繞在圓角周圍。

inset()函數接受1到4個值指定從參考Box邊緣向內的距離。這可以控制這個矩形在元素內部的位置。這個函數還接受一個可選參數,設置內部矩形的圓角。且圓角的設置於border-radius的方法一致,使用一到四個值,於關鍵字round結合在一起。

inset() = inset( offset{1,4} [round <border-radius>]? )n

n在一個浮動的元素中創建一個帶圓角的矩形:

.element {n float: left;n width: 250px;n height: 150px;n shape-outside: inset(0px round 100px) border-box;n}n

在這裡查看實際的例子。

n最後一個Shape函數是polygon(),它可以是用任意數量的點來定義更加複雜的形狀。這個函數接受一系列的坐標,每個坐標定義多邊形的一個邊角,合在一起組成整個圖形。

n在下面的例子中,一張右浮動的圖片使用viewport單位,佔滿了整個屏幕。我們希望左側的文本可以沿著圖片內部的沙漏浮動,因此,我們使用polygon()函數在圖片上定義了一個不規則的的圖形。

圖片的CSS:

img.right {n float: right;n height: 100vh;n width: calc(100vh + 100vh/4);n shape-outside: polygon(40% 0, 100% 0, 100% 100%, 40% 100%, 45% 60%, 45% 40%);n}n

n你可以使用長度單位或者百分比來定義邊角的坐標,我使用的是百分比。

n這段代碼就是顯示出圖片的效果,你可以看到,Shape函數無法影響形狀外的圖片。事實上,一個形狀除了影響內容的浮動之外無法對元素造成其他任何影響,不管這個元素是圖片還是容器或者其他的什麼。

n為了讓我們創建的多邊形更有存在感,我們需要把形狀之外的圖片摳掉。這就需要CSS Masking模塊的clip-path屬性來幫忙了。

nclip-path屬性接受同樣的Shape函數和參數座位形狀屬性。如果我們把傳遞給shape-outside的多邊形傳遞給clip-path屬性,它會把形狀之外的圖片全部摳掉。

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

n看效果:

目前,使用clip-path還需要使用前綴,這個例子clip-path使用了-webkit-前綴,因此可以在Chrome中工作,你點擊查看demo。

nclip-path屬性確實是Shape屬性的好夥伴,因為它可以幫助凸顯被創建的形狀,摳掉元素上所有不再形狀內部的部分。你自然會經常發現把clip-path個Shape屬性結合使用。

npolygon()函數還接受一個可以可選的參數fill,有兩個值,nonzero和even odd。指明如何對待多邊形自己內部的交錯區域。更多信息可以查看SVG fill-rule。

使用圖片定義Shape

n使用圖片來確定一個形狀,需要用到這張圖片的alpha通道,瀏覽器可以據此提取出圖形。

n像素的alpha通道的值是否超過某個臨界值,這是定義形狀的依據。默認的臨界值是0.0(完全透明),你也可以通過shape-image-threshold屬性來定義。因此,所有不透明的像素點都是形狀的一部分。

n有可能,新版的CSS Shape不但可以使用alpha通道,還可以使用亮度。果真如此的話,shape-image-threhold將被擴展,支持亮度或者alpha通道,基於不同狀態間的切換。

n我們將使用下面這張圖,定義元素的形狀,讓文本環繞之:

使用shape-outside屬性,傳遞一個url()值,指向我們想要的圖片。

.leaf-shaped-element {n float: left;n width: 400px;n height: 400px;n shape-outside: url(leaf.png);n shape-margin: 15px;n shape-image-threshold: 0.5;n background: #009966 url(path/to/background-image.jpg);n mask-image: url(leaf.png);n}n

n當然,如果元素有背景圖片的話,需要把形狀之外的部分去掉。不過clip-path無法接受一張帶透明度的圖片座位參數,我們 可以使用Masking Module的mask-image(需要對應的前綴)屬性來實現。看看效果:

如果你需要創建一個複雜的形狀,推薦你使用圖片來定義。你可以通過Photoshop來定義alpha通道,比起手動指定定點方便多了。

n還有,如果你元素上又多個浮動或者多個被排除的區域,你更願意使用圖片而不是形狀。因為,至少是現在,你無法在一個元素上定義多個形狀。但是如果圖片包含多個區域,瀏覽器可以把這些區域提取出來並使用之。

響應式設計中的CSS Shape

nCSS Shape可以適應響應式布局么?在目前的規範中,shape-outside已經可以滿足了。因為它允許你使用百分比或者其他長度單位來指定元素的尺寸,而且形狀也可以使用百分比(即形狀函數的參數接收百分比)來定義。這意味著帶著shape-outside的元素可以是響應式的,與其他使用百分比尺寸實現伸縮的方式沒什麼區別。

n不過shape-inside還不是響應式的,原因是它被推遲到了Module Level 2中。當前版本中不盡人意的地方將在下一版本中解決。

Shape工具

n使用Shape函數創建複雜形狀令人生畏,尤其是使用ploygon()使用很多點很多左邊來創建形狀。這要感謝Adobe的Web平台開發組正在開發一個可交互的工具簡化這個工作。Bear Travis已經創建了一組Shape工具,幫助我們可視化地創建形狀,並幫助我們生成Shape函數,這很有用,但是它也有局限,在你想基於一張圖來創建形狀時,因為目前你沒法往工具中插入一張圖,然後為它創建一個形狀。

nAdobe Web平台開發組開發出了一個更高級,互動式的Shape工具。這個工具最近作為Brackets編輯器的一個插件公布出來,Brackets編輯器是Adobe團隊打造的一個免費編輯器。它允許你直接在瀏覽器中可視化地編輯圖形,還包含一個預覽版的功能——在你在頁面上編輯圖形的同時,更新編輯器中的樣式表。這給你提供了直接視覺反饋,可以讓你看到你的形狀是如何與頁面上的其他元素交互的。

使用Brackets的預覽模式,在右邊的瀏覽器中編輯多邊形。截圖由Razvan Caliman提供。

n這個工具不可或缺,因為它大大簡化了形狀的創建、編輯和調試。 Razvan Caliman再Brackets的博客上發布了一篇文章,說明如何再Brackets中使用Shape編輯器。

未來:CSS Exclusion

nCSS Shape規範實際上包括CSS Shape和Exclusion兩個草案,不過這兩個草案是分開的。CSS Shape定義shape-inside和shape-outside屬性,而CSS Exclusion則定義那些允許文本環繞在非浮動元素周圍的屬性。這些元素可能是絕對定位的元素。這使得內容從四面八方環繞真箇形狀成為可能,就如下面這張圖所示:

將來,CSS Exclusion允許我們像引文一樣讓文本環繞著形狀,如這張雜誌的布局所示。引文甚至可以是圓形的,文本也可以很好的環繞在它周圍。圖片來自Justin Thomas Kay。

n類似的布局,具有形狀的元素絕對定位在文本在中間——四面都有文本環繞——將來也沒什麼不可能。

將來的CSS Shape

n目前的CSS Shape規範只是第一步,很快,會有新的選項,我們有更多的控制,創建形狀,讓文本填充在形狀裡面,或者環繞在其四周。讓模型到活的設計更加方便,只需要簡單的幾行代碼就行。目前,草案編輯把注意力放在發布shape-outside上,到2014年底,你將會看到有更多的瀏覽器支持CSS Shape。

n現在你就可以使用CSS Shape,作為漸進增強的一部分,確保在不支持的瀏覽器中可以優雅的降級。我最近開始把它們用在我自己的網站上,降級很」正常」。對於更加複雜的設計,你可以使用腳本來檢測瀏覽器是否支持Shape,提供降級方案。你也可以使用這段腳本擴展Modernizr的測試集,來測試瀏覽器是否支持shape-outside,也可以直接下載一份自定義的包含了這個測試的版本。

nCSS Shape填平了印刷排版和Web設計之間的溝壑。本文中的示例都很簡單,不過你應該學到的這些基礎,有助於你實現像雜誌或者海報一樣複雜的設計——無需擔心你還需要針對屏幕重新設計。無論你在尋找什麼——從非矩形布局到Shape動畫——馬上開始實驗吧。

n原文:CSS Shapes 101 · An A List Apart Article
推薦閱讀:

iOS 7 的五點信號指示器(●●●●●)是好設計嗎?
iOS 7 全新外觀界面有哪些讓人心動的細節?
如何評價 iOS 7?

TAG:CSS | 前端开发 | Safari | WWDC | 苹果公司AppleInc | Adobe | Brackets | Design |