> 译者按:在WWDC 2014之前我就打算把这篇文章翻译出来与大家分享;好在WWDC 2014上CSS Shape也露了一脸。快点阅读本文,了解初出茅庐的CSS Shape是何方神圣吧! 方框套方框:这就是目前网页的样子。长久以来,我们努力尝试使用CSS来创建[几何形状][1]来突破这种限制。但是这些形状无法影响其包含内容的形状。同样,元素的形状也无法被其他元素所影响。

2012年中旬,由Adobe提出的[CSS Shape规范][2]打破了这个限制。该规范的目标是为设计师提供一种新的方式,改变任意复杂形状周围或者内部内容布局。这些事情之情从来没有被实现过,JavaScript也没有。

例如,注意看在下面这个设计中文本环绕圆形图片的样子。没有形状的话,文本变成长方形——抛弃了精致的边缘,这种精致可不是把设计带到了下一个高度。

![][3]

_注意例子中文本是如何环绕圆形的那个碗的。通过CSS Shape,我们可以在网页上创建类似的设计。_

接下来我们一起来看看Shape是如何工作,并开始使用它们。

## 浏览器支持

目前只有Webkit Nightly和Chrome Canary支持CSS Shape,但是它的Model Level 1已经是Candidate Recommendation(候选推荐)了,因此在规范中定义的属性和语法已经很稳定了。看来要不了多久其他浏览器也会实现CSS Shape。本Level的规范主要聚焦在几个Shape属性,这些属性主要规定了形状周围的内容该如何环绕。更具体地说,它主要聚焦在形状外围属性和其相关的属性。

结合其他一些最新的特性,例如[Clipping与Masking][4]、[CSS Filters][5]和[Compositing与Blending][6],无需借助像Photosho或者InDesign这样 的图像编辑器,CSS Shape允许我们创造更漂亮更精致的设计。

新版的CSS Shape规范也会聚焦形状内部的内容。例如,现在可以很轻松地使用CSS创建一个菱形:只需把元素旋转45度,然后把元素里面的内容旋转回来,相对页面是横向的。但是其形状没法受到其容器菱形的影响,因此还是矩形的。如果CSS Shape的**shape-inside**属性实现了,我们就可以让内容也是菱形的,要实现下这图这样的布局就没什么不可能了。

![][7]

_很快,CSS Shape将支持定义内部文本的形状,比如这些菱形,与它的容器边缘保持一致,而不溢出或者被截断。_

为了在Chrome Canary中使用CSS Shape,你需要开启试验特性标记。如果你不知道怎么打开,可以看看Adobe博客上的[这篇][8]参考。

## 创建CSS Shape

你可以使用Shape属性来给元素添加形状。你需要给Shape属性传递一个Shape函数。你可以给这个Shape函数传递参数来定义元素的形状。

![][9]

可以使用下面这几个函数来定义形状:

* **circle()**
* **ellipse()**
* **inset()**
* **polygon()**

每个形状都由一组坐标定义。有些函数接受坐标点作为参数,另外一些接受偏移量——但是最终它们都把形状当做元素上一系列的点来描绘。在下面的例子中,我们将为大家讲解每个方法所接受的参数。

一个形状还可以通过提取图片的一个Alpha通道来定义。如果把一张图片传递给Shape属性,浏览器就会基于图片的临界值提取形状。形状的定义基于图片上每一个点的Alpha通道是否高于临界值。不过图片必须是[CORS compatible][10]的。无论何种原因(比如图片不存在),只要图片不能正常显示,就不会产生形状。

可接受上面这些函数作为值的Shape属性有:

* **shape-outside**:限制形状周围的内容
* **shape-inside**:限制形状内部的内容

可以把shape-margin和shape-outside属性结合使用,定义形状周围的margin,以此隔开浮动的内容和形状,在形状和内容之间留出更多的空间。与shape-outside和shape-margin对应一样,shape-inside有对应的shape-padding属性,用来添加内间距。

一行代码就可以使用Shape属性和函数来定义一个形状:

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

或者:

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

但是。。。

要让这行CSS生效,必须满足两个条件:

* **元素必须是浮动的。**新版的CSS Shape可以循序我们定义一个非浮动元素的形状,但是现在还不行;
* **元素必须有确定的尺寸。**元素的宽度和高度被用来建立这个元素上的坐标系统。
看上面函数的定义,形状都是由一组坐标定义的。因为这些点是坐标,所以需要坐标系统,这样浏览器才知道把这些点放在元素的什么位置上。因此,加上下面这段代码上面的例子就可以正常工作。
“`
.element {
float: left;
height: 10em;
width: 15em;
shape-outside: circle();
}
“`

给定固有的维数并不会影响响应性(随后我们进行更深入的探讨)。

既然形状是由一系列带坐标的点定义的,那更改这些点的坐标就可以相应的更改形状。举个例子,下面的六边形是使用polygon()这个方法创建的。整个形状由六个点构成。更改黄点的横坐标将会影响产生的形状,应用了此形状元素的内部或者外部的内容布局方式也会受到影响。

![][11]

_如果元素右浮动,且应用了这个形状,当在**polygon()**函数中黄点的横坐标变化的时候,在元素左侧的内容的浮动方式也会改变。_

## Shape的Reference Box

CSS Shape在一个Reference Box(参考框)里被定义和创建,这个Box用来绘制在元素上的形状。除了元素的宽高之外,元素的和模型——外边界Box、内容Box、内边界Box和边框Box——也会作为元素上形状大小的参考。

默认把外边界Box作为参考——因此,如果你应用了形状的元素的底部有外边界,则形状会延伸到外边jie上,而不是元素的边框区域。如果你想使用其他Box值,你可以在形状函数之后指定,然后传递给Shape属性。

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

上面这条规则中的padding-box关键字,把形状限定在了元素的内边框Box中。circle()函数定义了一个环状的形状,包括这个形状的大小和在这个元素上的位置。

## 使用Shape函数定义Shape

我们从把信息环绕在圆形的头像上开始,我们常常在用户信息或者推荐中用到。

![][12]

使用CSS Shape,让文本环绕圆形的用户头像。文本将不再是长方形的。

使用circle()函数给头像添加一个圆形:

profile image

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Harum itaque nam blanditiis eveniet enim eligendi quae adipisci?

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.

你可能会问,“为什么不使用border-radius来做出图片的圆角?”答案就是border-radius无法影响元素周围或者内部的内容的布局。它只能影响元素的边框和背景。背景区域会被裁剪成圆角,但是它功能仅限于此。元素内部的内容任然是矩形的,而且周围的内容还是把元素当做一个矩形的存在——本质上它还是。

我们使用border-radius让图片变圆——我们通常都是这样让图片等其他元素变圆的。图片bian’yuan

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

![][13]

_不添加CSS Shape,文本任然把图片当做矩形的,因此还是围绕成一个矩形,而不是圆的。_

在不支持CSS Shape属性的浏览器中,原型图片周围的内容就像环绕在一个不是圆形的图片周围。这就是在较老浏览器中CSS Shape降级的效果。的

为了改变内容布局以适应特定的形状,我们使用Shape属性:

img {
float: left;
width: 150px;
height: 150px;
border-radius: 50%;

shape-outside: circle();
shape-margin: 15px;
}

有了这些代码,文本会看到一个圆的形状在图片上,环绕之,就像第一张截图那样(你可以在[这里看到][14])。在不支持的浏览器中,将降级为第二张图显示的哪样。

你可以像上面那样使用circle()函数,也可以传递参数给它。下面是它的语法:

circle() = circle( []? [at ]? )

问号标示这些参数是可选的。省略的参数将会被浏览器使用默认值补全。如果你直接使用circle()而未指定圆形的位置,它会定义一个放在元素正中间的圆形。

你可以指定圆形的半径,什么单位都可以(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*/

shape-inside: circle(250px at 500px 300px); /* defines a circle whose center is positioned at 500px horizontally and 300px vertically, with a radius of 250px */

![][15]

eclipse()函数与circle()还是函数是一样,除了接受两个半径参数以外(后者是一个参数列表)——一个是x轴的半径,一个是y轴的——是一直的。

ellipse() = ellipse( [{2}]? [at ]? )

与circle和eclipse没有直接的关系,inset()函数再元素内部创建一个矩形。既然元素本身就是矩形的,我们当然不需要更多的矩形。inset()实际上可以帮助我们在元素内部创建一个带有圆角的矩形。文本内容可以环绕在圆角周围。

![][16]

inset()函数接受1到4个值指定从参考Box边缘向内的距离。这可以控制这个矩形在元素内部的位置。这个函数还接受一个可选参数,设置内部矩形的圆角。且圆角的设置于border-radius的方法一致,使用一到四个值,于关键字round结合在一起。

inset() = inset( offset{1,4} [round ]? )

在一个浮动的元素中创建一个带圆角的矩形:

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

[在这里][17]查看实际的例子。

最后一个Shape函数是polygon(),它可以是用任意数量的点来定义更加复杂的形状。这个函数接受一系列的坐标,每个坐标定义多边形的一个边角,合在一起组成整个图形。

在下面的例子中,一张右浮动的图片使用viewport单位,占满了整个屏幕。我们希望左侧的文本可以沿着图片内部的沙漏浮动,因此,我们使用polygon()函数在图片上定义了一个不规则的的图形。

![][18]

图片的CSS:

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%);
}

你可以使用长度单位或者百分比来定义边角的坐标,我使用的是百分比。

这段代码就是显示出图片的效果,你可以看到,Shape函数无法影响形状外的图片。事实上,一个形状除了影响内容的浮动之外无法对元素造成其他任何影响,不管这个元素是图片还是容器或者其他的什么。

为了让我们创建的多边形更有存在感,我们需要把形状之外的图片抠掉。这就需要[CSS Masking模块][19]的clip-path属性来帮忙了。

clip-path属性接受同样的Shape函数和参数座位形状属性。如果我们把传递给shape-outside的多边形传递给clip-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%);
}

看效果:

![][20]

目前,使用clip-path还需要使用前缀,这个例子clip-path使用了-webkit-前缀,因此可以在Chrome中工作,你点击查看[demo][21]。

clip-path属性确实是Shape属性的好伙伴,因为它可以帮助凸显被创建的形状,抠掉元素上所有不再形状内部的部分。你自然会经常发现把clip-path个Shape属性结合使用。

polygon()函数还接受一个可以可选的参数fill,有两个值,nonzero和even odd。指明如何对待多边形自己内部的交错区域。更多信息可以查看[SVG fill-rule][22]。

## 使用图片定义Shape

使用图片来确定一个形状,需要用到这张图片的alpha通道,浏览器可以据此提取出图形。

像素的alpha通道的值是否超过某个临界值,这是定义形状的依据。默认的临界值是0.0(完全透明),你也可以通过shape-image-threshold属性来定义。因此,所有不透明的像素点都是形状的一部分。

有可能,新版的CSS Shape不但可以使用alpha通道,还可以使用亮度。果真如此的话,shape-image-threhold将被扩展,支持亮度或者alpha通道,基于不同状态间的切换。

我们将使用下面这张图,定义元素的形状,让文本环绕之:

![][23]

使用shape-outside属性,传递一个url()值,指向我们想要的图片。

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

当然,如果元素有背景图片的话,需要把形状之外的部分去掉。不过clip-path无法接受一张带透明度的图片座位参数,我们 可以使用Masking Module的mask-image(需要对应的前缀)属性来实现。看看效果:

![][24]

如果你需要创建一个复杂的形状,推荐你使用图片来定义。你可以通过Photoshop来定义alpha通道,比起手动指定定点方便多了。

还有,如果你元素上又多个浮动或者多个被排除的区域,你更愿意使用图片而不是形状。因为,至少是现在,你无法在一个元素上定义多个形状。但是如果图片包含多个区域,浏览器可以把这些区域提取出来并使用之。

## 响应式设计中的CSS Shape

CSS Shape可以适应响应式布局么?在目前的规范中,shape-outside已经可以满足了。因为它允许你使用百分比或者其他长度单位来指定元素的尺寸,而且形状也可以使用百分比(即形状函数的参数接收百分比)来定义。这意味着带着shape-outside的元素可以是响应式的,与其他使用百分比尺寸实现伸缩的方式没什么区别。

不过shape-inside还不是响应式的,原因是它被推迟到了Module Level 2中。当前版本中不尽人意的地方将在下一版本中解决。

## Shape工具

使用Shape函数创建复杂形状令人生畏,尤其是使用ploygon()使用很多点很多左边来创建形状。这要感谢Adobe的Web平台开发组正在开发一个可交互的工具简化这个工作。Bear Travis已经创建了[一组Shape工具][25],帮助我们可视化地创建形状,并帮助我们生成Shape函数,这很有用,但是它也有局限,在你想基于一张图来创建形状时,因为目前你没法往工具中插入一张图,然后为它创建一个形状。

Adobe Web平台开发组开发出了一个更高级,交互式的Shape工具。这个工具最近作为[Brackets编辑器][26]的一个插件[公布出来][27],Brackets编辑器是Adobe团队打造的一个免费编辑器。它允许你直接在浏览器中可视化地编辑图形,还包含一个预览版的功能——在你在页面上编辑图形的同时,更新编辑器中的样式表。这给你提供了直接视觉反馈,可以让你看到你的形状是如何与页面上的其他元素交互的。

![][28]

_使用Brackets的预览模式,在右边的浏览器中编辑多边形。截图由Razvan Caliman提供。_

这个工具不可或缺,因为它大大简化了形状的创建、编辑和调试。 Razvan Caliman再Brackets的博客上发布了[一篇文章][29],说明如何再Brackets中使用Shape编辑器。

## 未来:CSS Exclusion

CSS Shape规范实际上包括CSS Shape和Exclusion两个草案,不过这两个草案是分开的。CSS Shape定义shape-inside和shape-outside属性,而CSS Exclusion则定义那些允许文本环绕在非浮动元素周围的属性。这些元素可能是绝对定位的元素。这使得内容从四面八方环绕真个形状成为可能,就如下面这张图所示:

![][30]

_将来,CSS Exclusion允许我们像引文一样让文本环绕着形状,如这张杂志的布局所示。引文甚至可以是圆形的,文本也可以很好的环绕在它周围。图片来自[Justin Thomas Kay][31]。_

类似的布局,具有形状的元素绝对定位在文本在中间——四面都有文本环绕——将来也没什么不可能。

## 将来的CSS Shape

目前的CSS Shape规范只是第一步,很快,会有新的选项,我们有更多的控制,创建形状,让文本填充在形状里面,或者环绕在其四周。让模型到活的设计更加方便,只需要简单的几行代码就行。目前,草案编辑把注意力放在发布shape-outside上,到2014年底,你将会看到有更多的浏览器支持CSS Shape。

现在你就可以使用CSS Shape,作为渐进增强的一部分,确保在不支持的浏览器中可以优雅的降级。我最近开始把它们用在[我自己的网站][32]上,降级很”正常”。对于更加复杂的设计,你可以使用脚本来检测浏览器是否支持Shape,提供降级方案。你也可以使用[这段脚本][33]扩展[Modernizr][34]的测试集,来测试浏览器是否支持shape-outside,也可以直接下载一份自定义的包含了这个测试的版本。

CSS Shape填平了印刷排版和Web设计之间的沟壑。本文中的示例都很简单,不过你应该学到的这些基础,有助于你实现像杂志或者海报一样复杂的设计——无需担心你还需要针对屏幕重新设计。无论你在寻找什么——从[非矩形布局][35]到[Shape动画][36]——马上开始实验吧。

原文:[CSS Shapes 101 · An A List Apart Article][37]

[0]: http://pic3.zhimg.com/895a614b62dfbb2a2101bcab24c08b10_b.jpg
[1]: https://css-tricks.com/examples/ShapesOfCSS/
[2]: http://blogs.adobe.com/webplatform/category/features/css-shapes/
[3]: http://pic2.zhimg.com/5bb12df822f453362cdefbb48fae7aae_b.jpg
[4]: http://www.w3.org/TR/css-masking/
[5]: http://www.w3.org/TR/filter-effects-1/
[6]: http://dev.w3.org/fxtf/compositing-1/
[7]: http://pic3.zhimg.com/70145dc18fc9fca6b8bb33a7189c846b_b.jpg
[8]: http://html.adobe.com/webplatform/enable/
[9]: http://pic4.zhimg.com/411547cc5393d17b351ec8893df1da66_b.jpg
[10]: http://caniuse.com/cors
[11]: http://pic3.zhimg.com/4b263612e95c644d8a417cd4d1ddef49_b.jpg
[12]: http://pic1.zhimg.com/33f0ebe9e78f6587c942c32a1c7d6671_b.jpg
[13]: http://pic1.zhimg.com/c9652d4e72b5e818039044815410812d_b.jpg
[14]: http://codepen.io/SaraSoueidan/pen/af3d2ae9fbe4205035822e4878fb1f54/
[15]: http://pic2.zhimg.com/ea29d229cdfed51cd41596362cd6c6ec_b.jpg
[16]: http://pic2.zhimg.com/629f91dfa28905afb71c0cce04a8cd1b_b.jpg
[17]: http://codepen.io/SaraSoueidan/debug/05e7894a0a7dbffed0a1c9f5e0840ec9/
[18]: http://pic4.zhimg.com/50ca2ff3f6f8da17698a16625b51c482_b.jpg
[19]: http://www.w3.org/TR/2014/WD-css-masking-1-20140213/
[20]: http://pic3.zhimg.com/46b725cdce3d8a109d3628458527f5ea_b.jpg
[21]: http://codepen.io/SaraSoueidan/pen/04a4c8380e4aa5a8e6a2b0014b2db198/
[22]: http://www.w3.org/TR/SVG/painting.html#FillRuleProperty
[23]: http://pic3.zhimg.com/13f2d487c4b1708afeef1ff0ef2e4189_b.jpg
[24]: http://pic1.zhimg.com/dfa2dd43a5ba4732a66fc0e3068575ed_b.jpg
[25]: http://betravis.github.io/shape-tools/
[26]: http://brackets.io
[27]: http://blogs.adobe.com/webplatform/2014/04/17/css-shapes-editor-in-brackets/
[28]: http://pic1.zhimg.com/85f8ae468efbbd3eba5942bb3282bd6d_b.jpg
[29]: http://blog.brackets.io/2014/04/17/css-shapes-editor/
[30]: http://pic4.zhimg.com/b2aa811b7aa1ce98e46eb2ce300fadf0_b.jpg
[31]: http://cargocollective.com/justinthomaskay
[32]: http://sarasoueidan.com/about.php
[33]: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/css/shapes.js
[34]: http://modernizr.com
[35]: http://sarasoueidan.com/blog/css-shapes/
[36]: http://sarasoueidan.com/blog/animating-css-shapes/
[37]: http://alistapart.com/article/css-shapes-101