原文:Progressive Enhancement with CSS
作者: Aaron Gustafson
翻译:lifesinger
本系列上一篇涵盖了渐进增强的基本概念,现在我们来讨论如何应用。有多种方式可以将渐进增强融入到层叠样式表(Cascading Style Sheets, 简称CSS)的工作中,本文将讨论其中比较成功的一些,并考虑采用其它方式来逐步增强你的站点。
样式表的组织
如何在文档中引入样式表,很多Web设计者和开发者并没有想太多,但这其实是一门艺术。使用正确的方法,可以立即获得渐进增强的很多好处。
使用多个样式表
对样式进行稍许拆分可以带来很多好处。显而易见,超过1500行的样式表是有点难以维护的,将其拆分成多个样式表,可以改进工作流程(并节省你的精力)。还有一个好处很少提及:有助于在目标媒介类型(译注:指计算机、打印机、电视、手机等各种媒介类型)上获取更一致的呈现效果。
main.css
文件包含了站点的所有样式规则,考虑将其拆分成包含版式、布局和颜色的独立样式表,相应地命名为:type.css
, layout.css
, color.css
.
(图示:如何将单个样式表拆分成多个相关的样式表)
一旦完成了上面的分离,就可以使用一点神奇的小手段来给过时的浏览器(比如IE5/Mac)和很多对CSS布局缺乏有力支持的浏览器自动提供“低保真”的体验。怎么做呢?这完全取决你如何引入文件。假设通过link
元素来引入main.css
:
<link rel="stylesheet" type="text/css" href="main.css" />
首先,将上面一行引用拆分成三个相关的样式表:
<link rel="stylesheet" type="text/css" href="type.css" /> <link rel="stylesheet" type="text/css" href="layout.css" /> <link rel="stylesheet" type="text/css" href="color.css" />
在过去,很多开发者将media
的值设为”screen”或”projection”, 以使得布局样式在Netscape 4.x上彻底失效(译注:Netscape 4.x不支持浮动和定位等复杂布局)。然而,有更好的解决方法。在详细讲解这个方法前,我们先来看看可选媒介类型(Alternate Media Types)。
可选媒介类型
渐进增强主要关注内容,我们要将“增强”的体验带到所有支持内容显示的设备上。因此需要考虑浏览器之外的设备,比如打印和移动设备就很重要。
糟糕地是,移动设备市场依旧四分五裂而且不成熟(不要天真地认为所有手持浏览器都会渲染目标为“screen”的媒介类型样式)。结果,用渐进增强的方式来处理所有媒介的细节讨论,如果不写成一本书的话,也得用上好多篇幅。然而请别沮丧:在移动世界里,差异正开始统一起来,并且一些非常聪明的人正开始将资源放在一起以帮助我们开发。不过,为了节约时间和节省精力,我们将集中于打印设备上。
通常,我们需要使用另一个link
元素来添加打印样式:
<link rel="stylesheet" type="text/css" media="print" href="print.css" />
按照惯例,上面这个样式表包含所有打印相关的规则,包括版式和颜色规则。特别是版式,样式表中的规则大部分很可能拷贝自main.css
. 也就是说,这造成了很多重复代码。
可以看出从布局样式中拆分出版式和颜色样式的好处了:在打印样式表中,我们不再需要那些重复的规则了。除此之外,可以使用另一个组织上的小技巧来改进站点的适用性,以及针对有问题的浏览器隐藏某些布局样式。
回顾下我们的样式表,考虑以下代码:
<link rel="stylesheet" type="text/css" href="type.css" /> <link rel="stylesheet" type="text/css" href="layout.css" /> <link rel="stylesheet" type="text/css" href="color.css" />
我们没有声明媒介类型,因此 Netscape 4.x 会读取这三个文件中的所有样式。但是,Netscape浏览器能理解最基本的CSS, 我们可以利用这一点。通过将layout.css
包含的所有样式移动到新的样式表——适当的取名为screen.css
, 我们可以进一步组织样式。最后,将layout.css
中的内容更新为引入screen.css
, 这样,NS4.x和它的同族浏览器们就再也聪明不起来了(因为它们不理解 @import
指令)。(译注:作者这里说的是将所有layout.css
中的内容都移动到screen.css
中,然后在layout.css
中通过@import
引入screen.css
. 我觉得最好的做法应该是在layout.css
中保留最基本的NS4.x也可以理解的布局样式,而将其它高级布局样式移动到screen.css
中。)
@import 'screen.css';
还有一些改进的余地——应该声明样式表所针对的媒介,我们通过给@import
声明添加媒介类型来做到这点:
@import 'screen.css' screen;
问题是IE7及以下浏览器不理解这种语法从而忽略上面的样式表,如果想给这些浏览器提供上面的样式(这是经常期望的),可以很简单地使用条件注释来做到,这将在下文阐述。如果你拥有鹰一般利锐的眼睛,可能已经注意到在样式表名称的两边使用了单引号(’)来替代双引号(”),这个小技巧可以让IE5/Mac忽略样式表。IE5/Mac的CSS布局能力非常弱(特别是对浮动和定位的支持),对它们隐藏布局规则是完全可接受的。毕竟,它们依旧能获取颜色和版式信息,这在某些情况下已经够用了。
采用相同的技术,可以导入print.css
文件(和你猜想的一样,包含打印布局的特定规则)。
@import 'screen.css' screen; @import 'print.css' print;
现在我们不仅拥有了组织得很漂亮的样式表,我们还拥有了一套逐步增强站点设计的有效方法。
(图示:多个样式表间的相互关系以及将它们应用到文档的方法)
现在讨论值一千万美元的问题:如何处理IE6?
对很多伙计来说,Internet Explorer 6 是一个新的 Netscape 4 ——所有人都想让它滚蛋。
我们略过对IE6问题的喋喋不休。IE6的问题已经有了很好的文档总结,并且,老实说,解决起来也并不是那么困难。而且,IE7的采纳相当快速(特别是在消费市场),同时IE8也已经在公测了。这意味着某一天,我们可以真正地对老态龙钟的IE6说拜拜。
不管是有意还是无意,微软在推出IE5时,为渐进增强提供了一个好工具:条件注释。这些巧妙的逻辑片段(在所有其它浏览器中都降级为HTML注释(译注:其它浏览器把IE的条件注释理解为纯粹的HTML注释,不起任何作用))不仅允许某些标记代码片段只作用于IE,还允许这些代码片段只作用于IE的特定版本。
作为有Web标准意识的开发者,我们始终应该首先在大部分现有的兼容标准的浏览器上测试我们的设计,然后再为那些稍作细微修改就能回到正轨的浏览器提供补丁。每个人的工作流程都不同,但我发现最好用一套标准的文件来开始每个项目。我的基本套件包括以下文件:
- type.css
- layout.css
- screen.css
- print.css
- color.css
然后,根据项目的需求,添加针对特定浏览器的CSS文件来包含那些“细微修改”。在现在的大部分项目中,这些文件是ie7.css
和ie6.css
. 如果项目要求支持IE6之前的版本,我也会为其创建相应的文件(比如ie5.5.css
等等)。将这些文件放在恰当的位置后,我开始将样式规则添加到合适的样式表中。
我的CSS测试都是从Mozilla Firefox中开始,因为我的大部分CSS都是用Firefox的CSS编辑侧栏来编写的。一旦在Firefox中完成了页面设计,我立刻开启其它浏览器来测试查看。大部分表现很完美,因为他们遵守了Web标准。接着打开IE7来测试。大部分情况下也没多少问题,偶尔需要触发hasLayout或者修正另一些布局上的小错误。我没有将这些修正补丁写入到基本套件的样式表文件中,而是添加到ie7.css
中,并且在文档的HEAD
中通过条件注释来引入:
<!-- [if lte IE 7]> <link rel="stylesheet" type="text/css" href="ie7.css" /> <[endif]-->
上面的条件注释使得IE7及其以下版本(译注:lte是less than or equal的缩写)能识别引入的样式。因此,当用IE7浏览页面时,将获取这些补丁。但是如果用的是新版本的IE——可能已经修复这些问题,比如IE8抛弃了hasLayout
从而不再有这些问题——将忽略这些样式。另一方面,使用IE6可以获取到这些样式。这是很好的,因为在IE7中的渲染错误往往也存在于IE6中。上文中已经提及,IE7及其以下版本无法理解带媒介类型的@import
,通过这种方式引入screen.css
对IE7及其以下版本是无效的。因此,还需要在ie7.css
文件的顶部添加不带媒介类型的@import
语句来引入screen.css
.
一旦为IE7添加完补丁,我会打开IE6, 看看是否需要随手打些补丁。如果确实需要,我会给文档添加另一个条件注释,引入ie6.css
:
<!-- [if lte IE 7]> <link rel="stylesheet" type="text/css" href="ie7.css" /> <[endif]--> <!-- [if lte IE 6]> <link rel="stylesheet" type="text/css" href="ie6.css" /> <[endif]-->
接着,简单地将IE6需要的补丁添加到对应的样式表中,这些样式表将被IE7忽略,但是会依旧往下影响到IE5.5等版本。
通过这种方式使用条件注释,可以很轻松的管理项目中的目标浏览器,并使得CSS补丁文件保持独立自由。
其它考虑
CSS渐进增强并不局限于如何将样式表与文档关联起来,还可以应用在如何编写CSS上。
例如,考虑生成的内容(译注:比如用:after
伪类生成的内容)。并非所有浏览器都支持,但这是一个很好的方法:可以用来添加一些额外的设计或文本。对于页面的可用性来说,这不是必须的,但这能提供一些视觉或其它方面上的增强。
拿简单的联系表单来举个例子:
(图示:此例中使用的HTML表单(代码将在下面给出))
当编写上面的HTML代码时,很可能会自然地将冒号(:)写在label
元素里。为什么要这样做?真的给label
元素添加了内容吗?并没有。这样做的目的是给用户提供额外的视觉线索,对label
元素来说,这是多余的,应当去掉:
<form id="contact-form" action="#" method="post"> <fieldset> <legend>Contact Us</legend> <p>Send us a message. All fields are required.</p> <ol> <li> <label for="contact-name">Name</label> <input type="text" id="contact-name" name="name" /> </li> <li> <label for="contact-email">Email</label> <input type="text" id="contact-email" name="email" /> </li> <li> <label for="contact-message">Message</label> <textarea id="contact-message" name="message" rows="4" » cols="30"></textarea> </li> </ol> <button type="submit">Send It</button> </fieldset> </form>
通过生成内容来将冒号添加回文档,这是一种更完美合适的方式:
label:after { content: ":"; }
用这种方式来编写表单,给了我们灵活性:当需要从整个站点移除装饰字符时,只要简单的编辑CSS文件,而不需要去寻找每一个表单(虽然我们曾经知道在哪)。这个技巧也能够很好降级,因为没有冒号时,表单并不会被渲染得无法使用——这是渐进增强的一个绝佳例子。
也许你已经发现,使用高级CSS选择符(译注:selector, 也有译为选择器的,但我觉得选择符更能体现本意,比如operator翻译成运算符,而不是运算器),可以将特定的样式附加到更多高级浏览器上,这有助于逐步增强站点。一个很好的例子是属性选择符,在IE6及其同一时代以及更早的浏览器中不能被理解(因此也就被忽略了)。Egor Kloos很漂亮地运用了这个概念,在CSS禅意花园(CSS Zen Garden)上提交了名为”双双”(Gemination)的作品:
(图示:Egor Kloos的CSS禅意花园作品(“双双”)在标准浏览器和IE6中的呈现对比)
他是怎样做到的?下面是略加修改的示例代码:
/* <= IE 6 */ body { margin: 0; text-align: center; background: #600 none; } /* IE 7, Mozilla, Safari, Opera */ body[id=css-zen-garden] { margin: 100px 0 0; padding: 0; text-align: center; background: transparent url(squidback.gif); }
差异很明显,并且非常漂亮地说明了渐进增强如何应用在CSS中。
类似地,Andy Clarke的站点上也有些关于IE6的小玩意。通过使用IE的滤镜以及加入一些条件注释,Andy成功地去除了站点上的所有颜色,并提供了一些可替换的图片,这构成了一个真实的“低保真”体验。
(图示:Andy Clark的站点在标准浏览器和IE6上的对比)
上面的图片灰色技术是这样的:在条件注释添加的针对IE6(及其以下)的样式表中,添加以下声明:
/* =img for Internet Explorer < 6 */ img { filter: gray; }
尽管上面这两个例子可能包含了过多日常工作中的运用不到的技巧,但它们非常棒地用事实说明了一个概念:如何在实践中应用CSS渐进增强。
总结
正如我们讨论过的,有多种方式可以将CSS渐进增强应用到站点上。最简单也可能是最好的一种方式是,组织好样式表并认真考虑如何将样式表链入文档。一旦理解了条件注释,处理IE的特定问题也将是轻而易举的事。如果对如何选用选择符以及使用它们的场景了然于胸,还能在CSS中完成更多小粒度的调整。
用这些知识武装起来,在通往渐进增强专家的路上你将平坦前行。下一篇中我们再聚,讨论JavaScript渐进增强。