設計跨瀏覽器網頁經常要在不同瀏覽器版本之間進行微調,調整的地方不一定只有 CSS 樣式,我們有時候會為了避開一些瀏覽器在特定版本下的 JavaScript 臭蟲,也會需要針對不同的瀏覽器版本撰寫不同的程式碼來因應,在這篇文章裡我會介紹各瀏覽器 CSS Hack 技巧以及 IE 條件式註解,幫助各位更輕易的設計出跨瀏覽器網頁。
(1) 各瀏覽器 CSS Hacks 技巧
撰寫 CSS 樣式時必須瞭解到樣式套用順序的觀念,也就是越晚定義的樣式,優先權越高!
舉個例子來說,如下 .page 這個樣式重複定義了 width 屬性,因此真正被套用的 width 屬性應該是 95% 這個值才對。
.page {
width: 90%;
width: 95%;
margin-left: auto;
margin-right: auto;
}
不只單一則樣式裡的屬性可以重複定義,連整條樣式也能夠重複定義,一樣也是比較晚定義的樣式會蓋掉先前定義的樣式,如下範例 .page 這個樣式最後生效的 width 屬性會是 100% 才對。
.page {
width: 90%;
margin-left: auto;
margin-right: auto;
}
.page {
width: 100%;
}
無論是 IE、Firefox、Safari、Opera 或 Chrome 瀏覽器,在解析一份 CSS 樣式表時多少都會有些不一樣的行為,但是都有一個共通的特性,那就是當瀏覽器無法解析其中一段 CSS 樣式或屬性時,就會自動忽略這一段的樣式,進而解析下一段樣式。所謂的 CSS Hack 技巧,講的就是找出不同瀏覽器版本之間不同的 CSS 解析規則,好讓網頁設計師所定義的 CSS 樣式可以讓該樣式在特定瀏覽器版本下無法辨識,但另一個版本的瀏覽器可以辨識的技巧,也是因為這類「小技巧」十分神奇,所以才被稱為 “Hack”。
備註:筆者倒覺得 CSS Hack 的神奇之處不是他的語法特別,而是為什麼有人可以找的到這麼多怪異 CSS 語法,國外還有些人會寫許多測試案例設法找出各種可能的 CSS Hacks,真讓人佩服。
CSS Hack 主要分成兩種類型,分別描述如下:
- 樣式屬性的密技 ( Attribute Hacks )
- 選取器的密技 ( Selector Hacks )
樣式屬性的密技 ( Attribute Hacks )
顧名思義,這種類型的 Hacks 可以用在樣式屬性上,以下是相關 Hacks 語法的整理:
- 只有 IE6 才能解析的屬性,在屬性名稱之前加上一個底線 ( _ )
- 只有 IE6, IE7 才能解析的屬性,在屬性名稱前面加上星號 ( * ) 或井號 ( # )
#style1 { *color: blue; }
#style1 { #color: blue; }
- 只有 IE7, IE8, IE9 才能解析的屬性,在屬性名稱後面加上一個空白與一個註解 ( /**/ )
#style1 { color /**/: blue }
- 只有 IE6, IE7, IE8, IE9 才能解析的屬性,在屬性值最後加上一個 \9 字串
#style1 { color: blue\9; }
- 只有 IE8, IE9 才能解析的屬性,在屬性值最後加上一個 \0/ 字串
#style1 {color: blue\0/;}
有了這些特殊的 CSS Hacks,網頁設計師便可以利用這些特性來設計針對特定瀏覽器的 CSS 問題來解決不同版本之前的相容性問題。舉個例子來說,如果你想針對不同的 IE 版本給與不同的顏色顯示文字,你就可以將 CSS 寫成以下這樣:
.page {
color: black; /* 所有瀏覽器 */
color /**/: green; /* IE7, IE8, IE9 */
*color: blue; /* IE6, IE7 */
_color: red; /* IE6 */
}
請注意:上述樣式的順序性非常重要,因為比較晚定義的樣式會取代較早定義的樣式,所以你必須把最多瀏覽器版本看的懂的樣式寫在比較上面,這樣才能達到 CSS Hack 的效果。
由於我們有 4 個不同的 color 屬性定義,不同瀏覽器版本套用這些屬性時就會有不同的結果出現:
- 所有非 IE 瀏覽器 (包括 IE10 瀏覽器)
會先套用正常的 color: black; 屬性,套用值為 black
剩下三行的定義非 IE 瀏覽器看不懂,所以會自動跳過
- IE8 , IE9
會先套用正常的 color: black; 屬性,套用值為 black
第 2 行的 color /**/: green; 它也看的懂,所以套用值會變成 green
剩下兩行 IE8, IE9 都看不懂,所以會自動跳過
- IE7
會先套用正常的 color: black; 屬性,套用值為 black
第 2 行的 color /**/: green; 它也看的懂,所以套用值會變成 green
第 3 行的 *color: blue; 它也看的懂,所以套用值會變成 blue
最後一行 IE7 看不懂,所以會自動跳過
- IE6
會先套用正常的 color: black; 屬性,套用值為 black
第 2 行的 color /**/: green; 它看不懂,所以跳過
第 3 行的 *color: blue; 它也看的懂,所以套用值會變成 blue
第 4 行的 _color: blue; 它也看的懂,所以套用值會變成 red
就是這樣的一個計算邏輯,可以讓樣式表在不同 IE 版本之間進行差異化設計。當然,除了這個範例之外,你還能依據上述各種 CSS Attribute Hacks 的語法與支援的 IE 版本自行變化組合。
※ 注意事項 ※
在網路上你會找到許多 Attribute Hacks 的文章,不過在我逐一驗證下發現,大部分描述 IE8 Hacks 語法都是錯誤的,我所查過所有號稱支援 IE8 and below 的 Attribute Hacks 其實都能被 IE9 正確讀取,也代表著你沒辦法透過 Attribute Hacks 區分 IE8 與 IE9,如果你的目的是要能設計出 IE8 與 IE9 有不同樣式的話,那麼你必須使用接下來討論的 Selector Hacks 或是本文最後會提到的 IE 條件式註解!
選取器類型的密技 ( Selector Hacks )
選取器類型的 Hacks 就是找出不同瀏覽器之間解析 選取器 (Selector) 的瑕疵來判別不同的瀏覽器或版本,這種類型的 Hacks 不止 IE 專屬,你還可以將這種類型的 Hacks 運用在其他的瀏覽器裡,而這裡的語法也比 CSS Attribute Hacks 的語法更奇怪。
- 只有 IE6 才能解析的選取器,在選取器名稱之前加上 * html
* html #style1 { color: red }
- 只有 IE7 才能解析的選取器,在選取器名稱之前加上 *+html 或 *:first-child+html
*+html #style1 { color: red }
*:first-child+html #style1 { color: red }
- 只有 IE8 才能解析的選取器,在整個 CSS 樣式規則前後用以下 @media \0screen 定義
@media \0screen {
.style1 {color: red;}
}
- 只有 IE9 才能解析的選取器搭配屬性 Hack,在選取器名稱之前加上 :root 與屬性值後面加上 \9
:root #style1 {color: #FF0000\9;}
- 只有 IE7, Firefox, Safari, Opera 才能解析的選取器,在選取器名稱之前加 html>body
html>body #style1 { color: red }
- 只有 IE8, IE9, Firefox, Safari, Opera 才能解析的選取器,在選取器名稱之前加 html>/**/body
html>/**/body #style1 { color: red }
- 只有 Opera 9.27 以下與 Safari 2 才能解析的選取器,在選取器名稱之前加 html:first-child
html:first-child #style1 { color: red }
- 只有 Safari 2 ~ 3 才能解析的選取器,在選取器名稱之前加 html[xmlns*=""] body:last-child
html[xmlns*=""] body:last-child #style1 { color: red }
- 只有 Safari 3+, Chrome 1+, Opera9+, Firefox 3.5+才能解析的選取器,在選取器名稱之前加 body:nth-of-type(1) 或 body:first-of-type
body:nth-of-type(1) #siete { color: red }
body:first-of-type #ocho { color: red }
- 只有 Safari 3+, Chrome 1+ 才能解析的選取器,在整個 CSS 樣式規則前後用以下 @media 定義
@media screen and (-webkit-min-device-pixel-ratio:0) {
#style1 { color: red }
}
- 只有 iPhone 與 Mobile Webkit 的瀏覽器才能解析的選取器
@media screen and (max-device-width: 480px) {
#style1 { color: red }
}
- 只有 Safari 2 ~ 3.1 才能解析的選取器,在選取器名稱之前加 html[xmlns*=""]:root
html[xmlns*=""]:root #style1 { color: red }
- 只有 IE6, IE7, IE8 才無法解析的選取器,在選取器名稱之前加 :root *>
:root *> #style1 { color: red }
- 只有 Firefox 1.0+ 才看的懂得選取器,在選取器名稱後面加上 , x:-moz-any-link
#veinticuatro, x:-moz-any-link { color: red }
- 只有 Firefox 3.0+ 才看的懂得選取器,在選取器名稱後面加上 , x:-moz-any-link, x:default
#veinticuatro, x:-moz-any-link, x:default { color: red }
- 只有 Firefox 3.5+ 才看的懂得選取器,在選取器名稱前面加 body:not(:-moz-handler-blocked)
body:not(:-moz-handler-blocked) #veinticuatro { color: red }
說實在的,這些 Hacks 語法真有點複雜,但當網頁設計師被客戶要求克服各種瀏覽器版本的樣式差異時,也不得不學會這些密技才能滿足客戶要求。但話說回來,一般客戶頂多就是要求網頁要能夠相容於 IE6 ~ IE9 這些瀏覽器而已,依照筆者多年來的網頁建置經驗,其他像是 Firefox, Safari, Opera, Chrome 根本不會有相容性的問題,如果有客戶要求你要針對 Firefox, Safari, Opera, Chrome 進行相容性網頁設計,你大可要求客戶升級到最新版,不然還真做不下去了。 ^_^
相關連結:
(2) IE 條件式註解
由於 CSS Hack 技巧是運用許多「非標準」的寫法來達到開發相容性網頁的手段,如果你採用 W3C 提供的 CSS 驗證服務來驗證這些含有 CSS Hacks 的樣式表,將會得到許多格式的錯誤,不過即便如此,這些 CSS Hacks 目前還是能夠正常的運作,只能說它有點不安全而已。
所謂「不安全」是因為這類語法是透過各瀏覽器解析 CSS 規則的瑕疵來達成目的的,例如只有 IE6 才能解析的屬性是在屬性名稱之前加上一個底線 ( _ ) 即可達到,這樣的語法「目前」在 IE7, IE8, IE9 以及其他瀏覽器都看不懂,但如果哪天 IE11 或 Chrome 20 又不小心可以解析這類特殊的 CSS Hacks 怎麼辦?這就是一個對未來不確定的風險,所以也有人提到應該盡量減少使用 CSS Hacks 的語法,但如果不用 CSS Hacks 語法,那我們要如何做到跨瀏覽器版本的相容性呢?
沒錯,這就是這一節的重點:使用 IE 條件式註解。
IE 條件式註解 (Conditional Comments) 是 Internet Explorer 獨有的相容性技術,在其他非 IE 的瀏覽器中並沒有類似的設計,條件式註解並非 W3C 標準,但這樣的技術的確非常實用,針對不同的 IE 版本可以非常安全的套用不同的網頁內容,又不會影響其他非 IE 瀏覽器的網頁呈現。
有別於 CSS Hack 技巧,IE 條件式註解是寫在 HTML 裡面的,接著我們來看一下條件式註解的語法,以下這段條件式註解寫著一個判斷條件式 [if IE 8] 所代表的意思是:當 IE 版本為 8 時,顯示在註解內的那段綠色文字,若使用者使用的 IE 版本為 9 或其他非 IE8 的版本,則會將這一整段視為註解文字。
<!--[if IE 8]>
<p>Welcome to Internet Explorer 8.</p>
<![endif]-->
請注意:上述紅字部分,你不能在這幾個字元之間加上空白字元,要完全一樣才可以生效。
我們再寫一個比較完整的例子,我們可以用條件式註解來選擇不同的 HTML 內容來輸出:
真正輸出的時候只會輸出判斷條件為「真」的內容,如下圖示:
同樣的網頁,若用非 IE 瀏覽器開啟(在此我用 Google Chrome 開啟)其畫面如下,所有內容都被瀏覽器視為註解了!
這時你可能會想說,如果條件式註解內的內容也想讓其他非 IE 瀏覽器顯示有辦法嗎?答案是肯定的!
條件式註解還有另一種特殊的表示法,就是把條件式註解變成條件式標籤,如下範例:
<![if IE 8]>
<p>此內容只會在 IE8 與其他非 IE 瀏覽器顯示</p>
<![endif]>
請注意:這段「條件式標籤」跟之前的版本差別僅在於把 -- 字元給刪除,這段條件式標籤在其他非 IE 瀏覽器下,由於看不懂這種表示法,這些瀏覽器會把他當成一個看不懂的標籤,因為上下兩段都是 < 開頭與 > 結尾,而瀏覽器只要看到不認識的 HTML 標籤就會自動忽略,也因此綠色的部分就會正常顯示在瀏覽器上,因此,條件式標籤也是可以用在跨瀏覽器的應用上。
在條件式註解的判斷式中還可以寫許多複雜的判斷條件,以下是判斷條件的語法:
- ! NOT 邏輯運算 [ 注意: 判斷 !IE 時應該要用條件式標籤才對 ]
<![if !IE]>
<p>任何非 Internet Explorer 瀏覽器</p>
<![endif]>
- lt 小於
<!--[if lt IE 9]>
<p>任何小於 IE9 的瀏覽器,例如: IE8, IE7, IE6 </p>
<![endif]-->
- lte 小於等於
<!--[if lte IE 8]>
<p>任何小於等於 IE8 的瀏覽器,例如: IE8, IE7, IE6 </p>
<![endif]-->
- gt 大於
<!--[if gt IE 7]>
<p>任何大於 IE7 的瀏覽器,例如: IE8, IE9 </p>
<![endif]-->
- gte 大於等於
<!--[if gte IE 7]>
<p>任何大於等於 IE7 的瀏覽器,例如: IE7, IE8, IE9 </p>
<![endif]-->
- ( ) 子條件式
<!--[if !(IE 8)]>
<p>任何非 IE8 的 IE 瀏覽器,例如: IE6, IE7, IE9 </p>
<![endif]-->
- & AND 邏輯運算
<!--[if (gt IE 6) & (lt IE 9)]>
<p>僅大於 IE6 以及小於 IE9 的瀏覽器,例如: IE7, IE8</p>
<![endif]—>
- | OR 邏輯運算
<!--[if (IE 7) | (IE 8)]>
<p>僅 IE7 與 IE8 瀏覽器</p>
<![endif]-->
- true 永遠為真的邏輯運算,等同於 [if IE] 判斷式
<!--[if true]>
<p>在 IE 瀏覽器中永遠顯示</p>
<![endif]—>
- false 永遠為假的邏輯運算,等同於 [if !IE] 判斷式
<!--[if false]>
<p>在 IE 瀏覽器中永不遠顯示</p>
<![endif]-->
活用條件式註解或條件式標籤的技巧有很多,你不只可能那來顯示不同的 HTML 內容,還可以用來載入不同的 CSS 檔,這種撰寫技巧又被稱為條件式樣式表 (Conditional stylesheets),如下範例所示,你可以透過條件式註解來完成條件式樣式表的載入,如此一來就可以避免在 CSS 樣式表內使用「不安全」的 CSS Hacks 語法:
<!--[if lte IE 8]><link rel="stylesheet" href="lte-ie-8.css"><![endif]-->
<!--[if lte IE 7]><link rel="stylesheet" href="lte-ie-7.css"><![endif]-->
<!--[if lte IE 6]><link rel="stylesheet" href="lte-ie-6.css"><![endif]-->
還有一種撰寫技巧被稱為條件式類別名稱 (Conditional classnames),這技巧經常用在 HTML5 的網頁裡,我們為了做到不支援 HTML5 的舊版瀏覽器也能讀取正確的樣式,有時會採用這種方式搭配 CSS 撰寫,達到不同 IE 版本也能套用不同樣式的目的。例如在 Initializr 與 HTML5 Boilerplate 這些 HTML5 範本產生器裡都能看到使用條件式類別名稱的技巧。
<!doctype html>
<!--[if lt IE 7 ]> <html lang="en" class="no-js ie6"> <![endif]-->
<!--[if IE 7 ]> <html lang="en" class="no-js ie7"> <![endif]-->
<!--[if IE 8 ]> <html lang="en" class="no-js ie8"> <![endif]-->
<!--[if IE 9 ]> <html lang="en" class="no-js ie9"> <![endif]-->
<!--[if (gt IE 9)|!(IE)]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
<head>
透過條件式類別名稱的技巧,你的 CSS 內容就可以寫成以下這樣,也可以有效避免使用 CSS Hacks:
.style1 { color: black; }
.ie8 .style1 { color: green; } /* IE8 */
.ie7 .style1 { color: blue; } /* IE7 */
.ie6 .style1 { color: red; } /* IE6 */
※ 注意事項 ※
微軟已經決定 Internet Explorer 10 之後的版本將移除條件式註解功能,因此下一代 IE 瀏覽器在解析條件式註解時將會與現有其他瀏覽器一樣,針對條件式註解或條件式標籤裡的條件式都會自動忽略,因此未來該功能只能用於 IE9 以下的瀏覽器裡。相關資訊請參考:Obsolete features in Internet Explorer 10
相關連結:
總結
為了達到同一份 HTML 可以精準的呈現在不同的瀏覽器與版本之間的確不是件簡單的事,這次講的 CSS Hacks 與 IE 條件式註解都是在網頁設計的領域中非常實用的技巧,若能夠對這兩種開發技巧多加熟悉,相信能對日常網頁設計工作帶來許多幫助。