打造超完美CSS圆角框
CSS圆角框的出现已经不是一天两天了,它出现的直接目的就是为了替换原有的以四个角上安放图片为主的圆角框,它的优势在于不需要用图片,对于统一主题中出现不同颜色样式的需求,不需要用作图工具重复制作多套圆角图片,而可以直接从css抽取颜色信息,方便做成独立的配色方案,其次,它对于圆角框长宽等位置信息的设置具有比图片圆角更为高明的自适应能力,真正可以把程序员的注意力集中到内容的排布而不是陷入对页面布局应对的泥藻中(这也可以作为一个简单的分离关注点的有效例子)。
CSS圆角框有如此优秀,那么为什么不用呢,最近,在我和一位好兄弟合作的项目中出现了上述需求(这位兄才在web开发领域拥有多年的经验,曾经自己写过ajax框架,他做的东西精巧别致,思维独特,始终是我心目中强悍的高手),于是决定在其中使用CSS圆角框替换传统的图片圆角,我把设想告诉他,但是他的第一反应是让我不要用CSS圆角,原因如下:
  1. CSS圆角从所周知会出现锯齿,难以处理
  2. CSS圆角内部一般都无法放置复杂的页面元素,放置其中的元素要么会出现大小难以调节,要么会使得整个圆角框发生严重的元素构图混乱(也就是整个页面不听我们的话,发生破裂)
  3. CSS圆角很难跨浏览器,兼容性差
(人们常说 提出一个问题往往比解决一个问题更为难能可贵,更何况我的这位兄弟能在第一反应给CSS圆角框的缺陷做出如此精辟的概括,更显示出他在web开发领域扎实的基本功和对事物针砭时弊的观察力,这一点始终让我望尘莫及。)
上述CSS圆角框的缺陷都如我这位兄弟所说,的确都存在,而且没有一个问题能够轻易解决,但是有句话怎么说来着,“ 车到山前未必有路,与其绕过这座山,还不如踏踏实实一步一个脚印的踏出一条路来”,一来方便自己行走,二来荫庇后人。
那么让我们一个一个的仔细分析上述问题,慢慢解决他们
问题一 首先看锯齿,我们知道锯齿的实质是肉眼无法接受眼前所看到的现实的状况,计算机在处理曲线图形时,若是没有专门的解决方案,锯齿可以说无处不在,那么这个解决方案究竟在那里呢?聪明的你一定会在第一时间联想到,我们的图形处理利器photoshop(以下简称ps),ps在图形处理领域可谓一直是领军羊,它不仅处理速度极快,而且在技术上拥有大量的积累。我们这里只看它是如何处理锯齿的
下图为锯齿和抗锯齿后图形的对比
anti.jpg
我们看到在使用了抗锯齿的圆角边缘呈现出一种渐进的半透明状态,没错,它其实就是一个半透明,这也就是ps中抗锯齿算法的本质
假设前景图层上某A点,背景图层上某B点,目标半透明C点,那么我们可以用如下公式来获取目标点C的RGB值:
XML/HTML代码
  1. R(C)=(R(A)*alpha+R(B)*(256-alpha))/256      
  2. G(C)=(G(A)*alpha+R(B)*(256-alpha))/256      
  3. B(C)=(B(A)*alpha+R(B)*(256-alpha))/256      
  4. alpha取值范围    [0,256]      
  5. (R Red, G Green, B Blue)  
这就是一个半透明的算法(其实是一个着差运算),这个算法是方形(box)抗锯齿算法的基础(当然,抗锯齿本身就是一个高级话题,算法也有很多种,比如方形(box),三角(triangle),高斯(gauss),米西尔(mitchell),其中大多是动态图形抗锯齿,有兴趣的朋友可以自己研究一下,这里只讨论最简单的静态图形抗锯齿),方形抗锯齿算法是在过滤区域内使用均等的权重把采样叠加在一起实现的,也就是说离边缘越近,alpha值越高,离边缘越远,alpha值越低,你可以在边缘的各像素平均分布alpha值来达到抗锯齿的目的
对于锯齿和抗锯齿有了基本的概念,那么解决方法也有了
1) 最简单的解决方法是在ps中做一个圆角矩形,放大后把边缘的各像素点依葫芦画瓢照搬到页面上去(用css控制border-color和background-color两个属相实现)
2) 更为稳妥的解决方法应该是做一个专门的程序来解决抗锯齿,这样一通百通,原本想自己写,可是得益于别人已经做了这样的工作
spiffy.jpg
这是一个php的实现版本,用的就是方形抗锯齿算法,有了这么方便的工具,相信你可以最快速的做出没有任何锯齿的CSS圆角框来
问题二,三 在web2.0如火如荼的今天,圆角成为一种首推的web2.0标志性设计元素和风格,webstandard由于其强大的控制能力和便于修改的特性得到大面积推广,这直接促使div(span)+css的设计模式越来越得到大家的认可,于是CSS圆角框就有了它存在的最大理由,可惜的是,大多数圆角框的设计意图仅仅是为了要在其中放置一些简单的页面元素,诸如文本和图片,由于需求的局限,设计者无法考虑到日后圆角框还有更大的活动空间(不要去责怪设计者,CSS圆角框作为一种设计手段上的革新,本身就是一种伟大的颠覆和创造,我们又怎么忍心对设计者要求的如此十全十美,如此苛刻呢)
下图为在Firefox(以下简称ff)中页面出现混乱的情况
wrongthing.jpg
正确的显示效果
rightthing.jpg
由于圆角框内放置了复杂的页面元素(包括了float属性,margin属性等),ff下混乱的页面元素大家也看到了,可以用惨不忍睹来形容,而同样的错误在ie6, ie7中也会发生,那么究竟是什么导致了元素混乱不堪呢?
下面以spiffycorners生成的代码为例
CSS代码
  1. .spiffy{display:block}   
  2. .spiffy *{   
  3.   display:block;   
  4.   height:1px;   
  5.   overflow:hidden;   
  6.   font-size:.01em;   
  7.   background:#CC0000}   
  8. .spiffy1{   
  9.   margin-left:3px;   
  10.   margin-right:3px;   
  11.   padding-left:1px;   
  12.   padding-right:1px;   
  13.   border-left:1px solid #e99191;   
  14.   border-right:1px solid #e99191;   
  15.   background:#d83f3f}   
  16. .spiffy2{   
  17.   margin-left:1px;   
  18.   margin-right:1px;   
  19.   padding-right:1px;   
  20.   padding-left:1px;   
  21.   border-left:1px solid #f9e5e5;   
  22.   border-right:1px solid #f9e5e5;   
  23.   background:#d53030}   
  24. .spiffy3{   
  25.   margin-left:1px;   
  26.   margin-right:1px;   
  27.   border-left:1px solid #d53030;   
  28.   border-right:1px solid #d53030;}   
  29. .spiffy4{   
  30.   border-left:1px solid #e99191;   
  31.   border-right:1px solid #e99191}   
  32. .spiffy5{   
  33.   border-left:1px solid #d83f3f;   
  34.   border-right:1px solid #d83f3f}   
  35. .spiffyfg{   
  36.   background:#CC0000}  
XML/HTML代码
  1. <div>  
  2.   <b class="spiffy">  
  3.   <b class="spiffy1"><b></b></b>  
  4.   <b class="spiffy2"><b></b></b>  
  5.   <b class="spiffy3"></b>  
  6.   <b class="spiffy4"></b>  
  7.   <b class="spiffy5"></b></b>  
  8.   
  9.   <div class="spiffyfg">  
  10.     <!– content goes here –>  
  11.   </div>  
  12.   
  13.   <b class="spiffy">  
  14.   <b class="spiffy5"></b>  
  15.   <b class="spiffy4"></b>  
  16.   <b class="spiffy3"></b>  
  17.   <b class="spiffy2"><b></b></b>  
  18.   <b class="spiffy1"><b></b></b></b>  
  19. </div>  
在仔细观察了代码之后我们发觉一个问题,在其中的容器元素spiffyfg的css中没有出现float属性,float是用于控制页面元素浮动的工具,它是负责页面布局的强有力的手段,我们在页面设计中会用到大量的float控制代码,但是,对于float而言,微软的IE和Firefox有着不同的理解,在W3C对于webstandard的标准中,严格的规定了属性的继承法则,子元素必须以明文声明某个属性是从它的父元素继承而来,若是该属性缺失,则认为继承终止,Firefox就严格的贯彻了这一标准, 而微软的产品一向以实用主义和尊重用户体验闻名,这势必导致他更遵从于产品的价值标准,在IE中,浏览器对属性的解释会采取就近原则,如果子元素属性缺失,就会从它的父元素获取属性。这种做法粗看上去方便了设计者,但已不适应走向标准化的今天。
没错,我们已经找到了问题的症结,于是我们在这里可以把第二个和第三个问题归结为由于ie和ff在float属性上的不同解释所引发的冲突和不兼容。
我们找到了问题的本质原因,但又带来了新的问题,如何编写代码适应两个不同的浏览器,出于同一属性的不同解释,也就意味着这是一个原子性问题,擅自改动代码,造成的结果只能是拆东墙补西墙,这时候,我们想,是否有一个工具,IE认可,FF不认可,那不就解决问题了,那么这样的工具存在吗,这个时候我的这位兄弟提醒了我,应该说,上帝在关闭一扇门的时候总会为其打开另一扇门(不要把上帝认为是比尔盖茨^_^),微软擅做决定改变了标准,让我们无法设计统一的代码,但在其css的设计中也提供了一个他独有的工具:表达式(expression),表达式的最初设计意图是为了在css中插入可执行的javascript代码,方便对群组元素方便的赋值,而在实践中我们发现,这一工具不为ff认可,于是问题就出现了转机。
针对属性继承的问题,我们可以在容器元素spiffyfg的属性中插入如下代码
CSS代码
  1. .spiffyfg{   
  2.   background:#CC0000  
  3.   float:left;       /*for Firefox*/  
  4.   float:expression("none"); /*for IE      */  
  5. }  
还有一个小问题,两款浏览器正对圆角边框的显示方法也会有不同,同样的解决方法,在.spiffy *元素中插入
CSS代码
  1. .spiffy *{   
  2.   display:expression("block");   
  3.   display:-moz-box;   
  4.   height:1px;   
  5.   overflow:hidden;   
  6.   font-size:.01em;   
  7.   background:#CC0000  
  8. }  
OK,到现在为止,借助与各种工具,我们成功的打造了一款没有任何锯齿,可以容纳任意复杂元素而又没有任何兼容性问题的圆角框
本文在思考实践和写作过程中均受到了我的这位好兄弟的积极的启发和引导,可以说没有他的经验和智慧,我们无法解决这些问题,文章的大量篇幅也不仅局限于解释原理和解决问题,而是希望能通过这样一个在常人看来不起眼的圆角框的改良过程,给大家以问题解决思路和攻克难关的精神上的启发
问题虽小,我们或许也能找到迂回的道路,可人生中总会碰到绝境,如何逢生不在于工具,而在于你有没有绝境逢生的信念。
(完)