两年前发表的《The visual design of Web 2.0》中提到“Rounded everything”,圆角因使人感觉舒适的友好风格而变得无处不在。这个无处不在也让很多前端工程师累个半死,YAHOO Performance Research Engneer Team的Nicole在讲演《Designing Fast Websites》中用的副标题是don’t blame the rounded corners!,从侧面也说明了圆角给实现者带来的困扰:实现麻烦、兼容困难、性能不佳。而W3C早在2002年的CSS3草案中就加入了一个叫border-radius的属性,通过它可以直接来定义HTML元素的圆角。
CSS3的border-radius规范
最新草案中其主要信息如下:
- 属性:border-top-right-radius
border-bottom-right-radius
border-bottom-right-radius
border-bottom-right-radius
值:<length> <length>?。它们分别是定义角形状的四分之一椭圆的两个半径。如图:- 第一个值是水平半径。
- 如果第二个值省略,则它等于第一个值,这时这个角就是一个四分之一圆角。
- 如果任意一个值为0,则这个角是矩形,不会是圆的。
- 值不允许是负值。
- 属性:border-radius。它是上面四个属性值的简写。
值:<length>{1,4} [ / <length>{1,4} ]?- 如果斜线前后的值都存在,那么斜线前的值设置水平半径,且斜线后的值设置垂直半径。如果没有斜线,则水平半径和垂直半径相等。
- 四个值是按照top-left、top-right、 bottom-right、 bottom-left的顺序来设置的。如果bottom-left省略,那么它等于top-right。如果bottom-right省略,那么它等于 top-left。如果top-right省略,那么它等于top-left。
- 应用范围:所有的元素,除了table的样式属性border-collapse是collapse时
- 内边半径等于外边半径减去对应边的厚度。当这个结果是负值时,内边半径是0。所以内外边曲线的圆心并不一定是一致的。
- border-radius也会导致该元素的背景也是圆的,即使border是none。如果background-clip是padding-box,则背景(background)会被曲线的内边裁剪。如果是border-box则被外边裁剪。border和padding定义的区域也一样会被曲线裁剪。
- 所有的边框样式(solid、dotted、inset等)都遵照角的曲线。如果设置了border-image,则曲线以外的部分会被裁剪掉。
- 如果角的两个相邻边有不同的宽度,那么这个角将会从宽的边平滑过度到窄的边。其中一条边甚至可以是0。
- 两条相邻边颜色和样式转变的中心点是在一个和两边宽度成正比的角上。比如,两条边宽度相同,这个点就是一个45°的角上,如果一条边是另外一条边的两倍,那么这个点就在一个30°的角上。界定这个转变的线就是连接在内外曲线上的两个点的直线
- 角不允许相互重叠,所以当相邻两个角半径的和大于所在矩形区域的大小时,用户代理(浏览器)比如缩小一个或多个角半径。运算法则如下:f = min(Li/Si),i ∈ {top, right, bottom, left},Ltop = Lbottom = 所在矩形区域的宽,Lleft = Lright = 所在矩形区域的高。如果f < 1,那么所有角半径都乘以f。
浏览器支持
实际中,目前没有任何一款浏览器支持这个属性,只有部分浏览器利用其私有属性支持部分实现:
- Firefox对border-radius的支持:
-moz-border-radius: <length>{1,4} | inherit -moz-border-radius-bottomleft : <length> | inherit -moz-border-radius-bottomright : <length> | inherit -moz-border-radius-topleft : <length> | inherit -moz-border-radius-topright : <length> | inherit
- 只对每个角设置一个半径,只支持实现四分之一圆角,并不支持椭圆形圆角。
- 具体每个角的命名规则也和W3C不一致,这个比较讨厌。
- Firefox3圆角已经相当圆滑了,Firefox2比较糟糕,好在它即将终结了。
- Safari和Chrome对border-radius的支持:
-webkit-border-radius: <length>{1,2} | inherit -webkit-border-bottom-left-radius : <length>{1,2} | inherit -webkit-border-bottom-right-radius : <length>{1,2} | inherit -webkit-border-top-left-radius : <length>{1,2} | inherit -webkit-border-top-right-radius : <length>{1,2} | inherit
- 每个属性有1个或2个值,当有两个值时1个表示水平半径,一个表示垂直半径(当writing-mode改变也随之而变)。所以,Safari和Chrome中的圆角可以是椭圆角。
- webkit的实现方法和W3C的CSS3草案2005年版本非常一致,和当前的草案最大不同就是简写属性-webkit-border-radius的属性值也只有1个或2个值,意义和前面相同。
- Chrome中圆角锯齿比较严重,基本上和Firefox2是同一水平,或许是它的webkit版本较低造成的。
- 由于webkit出生于khtml,所以把 上面属性中的webkit换成khtml即会得到以khtml为核心的浏览器支持的属性了。
- 当相邻的角半径之和大于所在矩形区域的大小时,都会直接设置所有的角半径为0,即圆角失效,而不会像Firefox那样同比率缩小。
- Opera尚不支持border-radius,虽然Opera10 alpha拥有众多的CSS3改进,但是依旧看不到对其支持的希望。
- IE就不用说了,标准的不支持了。从MSDN的CSS Compatibility and Internet Explorer中可以看出IE8已经铁定不支持了。
实际应用
最简单的应用就是支持的用圆角,不支持的用方角。比如Wordpress2.7的后台、雅虎口碑UED的blog和今天你带伞了吗?。基础代码如下:
border-width: 1px;
border-style: solid;
-moz-border-radius: 11px;
-khtml-border-radius: 11px;
-webkit-border-radius: 11px;
border-radius: 11px;
实现请看演示实例。
利用VML可以实现从IE5-7的圆角,但是貌似IE8不支持VML了。组件DD_roundies就是综合以上解决方案的一个具体应用。说实话这样实现出来的圆角也比较粗糙了,我感觉还不如不要。
像VML一样,Canvas也能实现圆角,切除了IE外,所有的主流浏览器都支持。所以就有了两者结合实现的组件Cornerz。
如果上面的现实太痛苦,而又非要用圆角的话,要么一个像素一个像素去拼装,比如Chunky Borders;要么就老老实实用图片来实现吧,比如CSS Mojo的方式。
- 作者:Pixel Acres
- 翻译:随网之舞