# 網站建置不是件簡單的事 @ 跨瀏覽器網頁設計密技 (2)

設計跨瀏覽器網頁經常要在不同瀏覽器版本之間進行微調，調整的地方不一定只有 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 語法，國外還有些人會寫許多[測試案例](http://mathiasbynens.be/demo/css-hacks)設法找出各種可能的 CSS Hacks，真讓人佩服。

CSS Hack 主要分成兩種類型，分別描述如下：

-   樣式屬性的密技 ( Attribute Hacks )
-   選取器的密技 ( Selector Hacks )

**樣式屬性的密技 ( Attribute Hacks )**

顧名思義，這種類型的 Hacks 可以用在樣式屬性上，以下是相關 Hacks 語法的整理：

-   只有 IE6 才能解析的屬性，在屬性名稱之前加上一個底線 ( \_ )

```
#style1 { _color: blue }
```

-   只有 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 進行相容性網頁設計，你大可要求客戶升級到最新版，不然還真做不下去了。 ^\_^

相關連結：

-   [IE CSS hacks](https://gist.github.com/983116)
-   [Browser CSS hacks](http://paulirish.com/2009/browser-specific-css-hacks/)
-   [CSS Browser Hacks](http://ajaxian.com/archives/css-browser-hacks)
-   [CSS hacks](http://www.webdevout.net/css-hacks)
-   [Downlevel Hidden / Downlevel Revealed](http://css-tricks.com/downlevel-hidden-downlevel-revealed/)
-   [Personal CSS Hacks for IE6, IE7, IE8, IE9](http://dimox.net/personal-css-hacks-for-ie6-ie7-ie8/)
-   [In defense of CSS hacks — introducing “safe CSS hacks”](http://mathiasbynens.be/notes/safe-css-hacks)
-   [CSS hacks, CSS filters-CSS 區隔各類不同瀏覽器 \[5-\] @ 網頁藝術思考](http://boohover.pixnet.net/blog/post/8947951-css-hacks,-css-filters)
-   [4 Types of CSS Hacks for Web Designers and Developers](https://web.archive.org/web/20160402104216/http://www.tutorialfeed.org/2011/06/4-types-of-css-hacks-for-web-designers.html)
-   [CSS Hacks for IE6, IE7, IE8 and IE9, CSS 分別支持 ie6 ie7 ie8 ie9](http://blog.sina.com.cn/s/blog_51047ef701011ksf.html)

**(2) IE** **條件式註解**

由於 CSS Hack 技巧是運用許多「非標準」的寫法來達到開發相容性網頁的手段，如果你採用 [W3C 提供的 CSS 驗證服務](http://jigsaw.w3.org/css-validator/)來驗證這些含有 CSS Hacks 的樣式表，將會得到許多格式的錯誤，不過即便如此，這些 CSS Hacks 目前還是能夠正常的運作，只能說它有點**不安全**而已。

所謂「不安全」是因為這類語法是透過各瀏覽器解析 CSS 規則的瑕疵來達成目的的，例如只有 IE6 才能解析的屬性是在屬性名稱之前加上一個底線 ( \_ ) 即可達到，這樣的語法「目前」在 IE7, IE8, IE9 以及其他瀏覽器都看不懂，但如果哪天 IE11 或 Chrome 20 又不小心可以解析這類特殊的 CSS Hacks 怎麼辦？這就是一個對未來不確定的風險，所以也有人提到應該盡量減少使用 CSS Hacks 的語法，但如果不用 CSS Hacks 語法，那我們要如何做到跨瀏覽器版本的相容性呢？

沒錯，這就是這一節的重點：使用 IE 條件式註解。

**IE 條件式註解** ([Conditional Comments](http://msdn.microsoft.com/en-us/library/ms537512\(VS.85\).aspx)) 是 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 內容來輸出：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/d40756d02d7a472e885f-image_1485.png)

真正輸出的時候只會輸出判斷條件為「真」的內容，如下圖示：

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/1aa1995e4538852cb216-image_1486.png)

同樣的網頁，若用非 IE 瀏覽器開啟（在此我用 Google Chrome 開啟）其畫面如下，所有內容都被瀏覽器視為註解了！

![](https://stwillblogassets.blob.core.windows.net/files/images/external/stwillblogassets.blob.core.windows.net/5a5ced9df04f2f85eed0-image_1487.png)

這時你可能會想說，如果條件式註解內的內容也想讓其他非 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](http://www.initializr.com/) 與 [HTML5 Boilerplate](http://html5boilerplate.com/) 這些 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](http://msdn.microsoft.com/en-us/library/ie/hh801218\(v=vs.85\).aspx)

相關連結：

-   [10 Common CSS Browser Compatibility Issues/Bugs You Must Know](https://web.archive.org/web/20100612022730/http://www.tutorialfeed.org/2010/01/10-common-css-browser-compatibility.html)
-   [Detecting Windows Internet Explorer More Effectively](http://msdn.microsoft.com/en-us/library/ms537509\(VS.85\).aspx) \[MSDN\]
-   [About Conditional Comments](http://msdn.microsoft.com/en-us/library/ms537512\(VS.85\).aspx) \[MSDN\]
-   [Detecting Windows Internet Explorer More Effectively](http://msdn.microsoft.com/en-us/library/ms537509\(VS.85\).aspx)
-   [HTML5 Parsing in IE10](https://learn.microsoft.com/en-us/archive/blogs/ie/html5-parsing-in-ie10)
-   [Obsolete features in Internet Explorer 10](http://msdn.microsoft.com/en-us/library/ie/hh801218\(v=vs.85\).aspx)
-   [Conditional Compilation (JavaScript)](http://msdn.microsoft.com/en-us/library/121hztk3\(VS.94\).aspx)

**總結**

為了達到同一份 HTML 可以精準的呈現在不同的瀏覽器與版本之間的確不是件簡單的事，這次講的 CSS Hacks 與 IE 條件式註解都是在網頁設計的領域中非常實用的技巧，若能夠對這兩種開發技巧多加熟悉，相信能對日常網頁設計工作帶來許多幫助。
