節標題:相容性地獄:CSS Hack 與怪異模式#
如果要在 2003 年找一位前端工程師聊天,最可能聽到的詞不是「設計」,而是「hack」——不是駭客的光榮義涵,而是被迫對著 IE6 的渲染引擎說謊的求生技巧。這段黑暗的相容性地獄,是 Web 開發史上最苦澀、也最富生產力的時代之一。
地獄的核心,是 IE 的盒模型 bug。CSS 規範說,width 指的是「內容」的寬度,padding 與 border 疊加在外。但 IE5(以及 IE6 的怪異模式)認為 width 應該包含 padding 和 border——你設定寬 200px、padding 10px,IE5 給你的內容只有 180px,而標準瀏覽器給你 220px 的總寬。這不是小事:所有網格排版、所有對齊,都會在兩種瀏覽器之間錯位。工程師的解法是層層套疊的欺敵術:盒模型 hack,寫出只有 IE 會誤讀、標準瀏覽器會忽略的 CSS 語法。
同類的黑魔法很快形成了目錄:星號 hack(* html #foo——IE6 會匹配一個不存在的祖先元素,其他瀏覽器不會);底線 hack(_width: 200px——IE 把底線開頭的屬性當有效屬性讀,標準瀏覽器直接丟棄);浮動元素導致父容器塌陷,得靠「clearfix」這套儀式咒語;透明 PNG 的 alpha 通道 IE6 不支援,要用微軟私有的 AlphaImageLoader 濾鏡,效能還極差。CSS 檔案開始像考古地層:底層是標準語法,中層是給 Firefox/Opera 的修正,表層是給 IE 的補丁——而且是補丁上面再補丁。
更底層的化石,是怪異模式(Quirks Mode)。瀏覽器為了不弄壞舊網頁,做出了一個影響深遠的決定:偵測文件的 DOCTYPE 宣告——有完整 DOCTYPE 的頁面走「標準模式」,沒有的頁面就退化到 IE5 時代的錯誤渲染規則。這是「瀏覽器考古學的化石層」:一個 1998 年的老頁面在 2005 年的瀏覽器裡依然要以 1998 年的方式渲染,哪怕那個方式是錯的。技術債的處理方式,是把錯誤永久化為相容性契約。每個新前端工程師的第一課,就是「永遠記得寫 DOCTYPE」。
腳本的世界同樣撕裂。存取頁面元素,標準方法是 document.getElementById(),但 IE 支援古老的 document.all(而且兩者的行為細節不同);事件處理,W3C 標準是 addEventListener,微軟的是 attachEvent,事件物件裡觸發源的名稱一個叫 target、一個叫 srcElement,事件冒泡的終止方式也是兩套。於是每個稍有規模的網站,都長出自己的「跨瀏覽器工具函式庫」——addEvent()、getElementsByClassName() 這些函式在各工程師的部落格間流傳、重寫、互相抄。這些零散的求生智慧,日後匯聚成一個改名世界的函式庫:jQuery(2006,John Resig),它的核心價值主張「write less, do more」本質上就是一層抹平瀏覽器差異的膠水。相容性地獄,就是 jQuery 的誕生動機。
但這段歷史也有光亮的一面——草根的標準化運動。1998 年,Jeffrey Zeldman 等人創立 Web Standards Project(WaSP),主張:瀏覽器應該正確實作 W3C 標準,開發者應該拋棄 table 排版與瀏覽器偵測,回歸語意化 HTML 與 CSS。Zeldman 2003 年的《Designing with Web Standards》成為運動聖經,說服了無數設計師與企業:遵循標準不是理想主義,而是省錢(不用維護多份頁面)、是未來(新版瀏覽器自動相容)。同年,Dave Shea 推出 CSS Zen Garden:一份固定的 HTML,全世界設計師各自提交一套 CSS,就呈現出上百種截然不同、驚豔的設計。它用最直觀的方式證明了標準的力量——內容與呈現分離,同一份 HTML 可以換上無數皮膚。
從思想史的角度看,這段地獄歲月淬鍊出兩條延續至今的工程哲學:漸進增強(progressive enhancement:以所有瀏覽器都能用的基礎功能為底,再為強大瀏覽器層層加料)與優雅降級(graceful degradation:新功能在舊環境中要不影響運作地消失)。以及一種文化:標準先行——先寫符合規範的程式碼,再為特定瀏覽器修正,而非反過來。2000 年代末,隨著 Firefox、Safari、Chrome 相繼崛起,瀏覽器再度多元競爭,IE 的份額崩落,「IE-only」的網頁成為歷史。地獄結束了,但地獄的教訓被寫進了之後二十年的規範、框架與工程師的直覺裡。
而那十年中,另有一種技術乘虛而入,在標準的真空地帶建立了自己的帝國——Flash。