原文:Progressive Enhancement with CSS
作者: Aaron Gustafson
有多種方式可以將漸進增強融入到層疊樣式表(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;
現在我們不僅擁有了組織得很漂亮的樣式表,我們還擁有了一套逐步增強站點設計的有效方法。
(圖示:多個樣式表間的相互關系以及將它們應用到文檔的方法)
對很多伙計來說,Internet Explorer 6 是一個新的 Netscape 4 ——所有人都想讓它滾蛋。
我們略過對IE6問題的喋喋不休。IE6的問題已經有了很好的文檔總結,並且,老實說,解決起來也並不是那麼困難。而且,IE7的采納相當快速(特別是在消費市場),同時IE8也已經在公測了。這意味著某一天,我們可以真正地對老態龍鐘的IE6說拜拜。
不管是有意還是無意,微軟在推出IE5時,為漸進增強提供了一個好工具:條件注釋。這些巧妙的邏輯片段(在所有其它浏覽器中都降級為HTML注釋(譯注:其它浏覽器把IE的條件注釋理解為純粹的Html注釋,不起任何作用))不僅允許某些標記代碼片段只作用於IE,還允許這些代碼片段只作用於IE的特定版本。
作為有Web標准意識的開發者,我們始終應該首先在大部分現有的兼容標准的浏覽器上測試我們的設計,然後再為那些稍作細微修改就能回到正軌的浏覽器提供補丁。每個人的工作流程都不同,但我發現最好用一套標准的文件來開始每個項目。我的基本套件包括以下文件:
然後,根據項目的需求,添加針對特定浏覽器的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中的呈現對比)
他是怎樣做到的?下面是略加修改的示例代碼:
body { margin: 0; text-align: center; background: #600 none; } 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 { filter: gray; }
盡管上面這兩個例子可能包含了過多日常工作中的運用不到的技巧,但它們非常棒地用事實說明了一個概念:如何在實踐中應用CSS漸進增強。
正如我們討論過的,有多種方式可以將CSS漸進增強應用到站點上。最簡單也可能是最好的一種方式是,組織好樣式表並認真考慮如何將樣式表鏈入文檔。一旦理解了條件注釋,處理IE的特定問題也將是輕而易舉的事。如果對如何選用選擇符以及使用它們的場景了然於胸,還能在CSS中完成更多小粒度的調整。