What is conditional comment?

・5min

作為一位近期才開始接觸前端的開發者而言,看 Javascript Patterns1 這本書是很有趣的事情。在這本書出版那個年代,還沒有 ES6,還在 ES5 的時期,而 IE 還是個無法逃避的巨嬰。開發者們想盡了各種方式來面對(例如還能再戰 20 年的 JQuery),而同時, IE 也想盡各種方式讓自己生存下去。

Javascript Patterns 在 2010 年出版,介紹了很多當時在開發中常見的問題以及處理方式:也就是所謂的 Pattern。雖然裡面範例的語法每個都是目前 EcmaScript 支援的標準,但看起來卻格外陌生,尤其是已經比較少接觸的 prototype,還有不使用 import/export 來做到的 module 實現(import/export 是 ES6 語法)。

Conditional comment 就是在那個時代下出現的功能,這個標準從 IE5 (1995) 的時候開始出現,而最後從 IE10 開始不再被支援。這篇文章就讓我們看看這時代的眼淚:Conditional comment

#語法

Conditional comment 有兩種形式:downlevel-hidden 以及 downlevel-revealed。簡單來說:

除了兩種形式之外,conditional comment 會包含一段 assertion,只有 assertion 為 true,才會解析其中的內容,下面是 wiki2 中,downlevel-hidden 的範例

<!--[if IE 8]>
<link href="ie8only.css" rel="stylesheet">
<![endif]-->

顯然這在 HTML 的中是一段註解(可以看到上面的 syntax highlight 是灰色的,代表註解),但如果是在 IE5~IE9,上面的程式碼在 Conditional comment 中能被識別,而且當符合 assertion,也就是如果瀏覽器為 IE8 時,comment 中的內容就會被解析,因此會載入 ie8only.css

範例中的的功能其實很類似 <link>media 屬性,但 media query 並不能識別瀏覽器,所以如果要使用 media 屬性來判斷瀏覽器,只能透過獨有的屬性來識別是不是 IE (可以參考How to target only IE (any version) within a stylesheet?)。

而另外一種形式: downlevel-revealed 的邏輯比較繞(改寫了一下 wiki 2上面的例子):

<![if !(IE 8)]>
<link href="non-ie8.css" rel="stylesheet">
<![endif]>

如果不是 IE,因為 <![if !IE]> 以及 <![endif]> 並不是合法的 HTML tag,所以會被忽略,自然就會載入 non-ie8.css,可以看成下面這樣的形式

<link href="non-ie8.css" rel="stylesheet">

但如果在 IE 中,assertion 就會被解析,如果不是 IE8 的瀏覽器同樣會載入 non-ie8.css,是的話,conditional comment 的內容將不會被解析。

有趣的地方是,因為上面的形式有非法的 HTML tag,如果要變成合法的 HTML tag,但又有 conditional comment 的效果,可以用下面的語法:

<!--[if IE 6]><!-->
This code displays on non-IE browsers and on IE 6.
<!--<![endif]-->

這樣的語法可以分兩個層面來看:

如果是非 IE 的瀏覽器:因為 <!--[if gt IE 6]><!--><!--<![endif]--> 都是合法的註解,所以會被忽略,html 的內容自然會顯現

只要是在 <!--, --> 內部就會被視為註解

參考自:whatwg - htmlcomments

但如果是 IE 的瀏覽器:一樣包含  [if !(IE 8)][endif](這裡可能有問題3),所以會被解析為 conditional comment 的語法

<!-->
This code displays on non-IE browsers and on IE 6.
&lt;!--[if IE 6]&gt;
&lt;!--&lt;![endif]--&gt;

另外,assertion 的內容也相當的多樣化,除了單一版本以外,還有各種 operator 可以使用,而且還支援嵌套。下面是 MSDN 4上的範例

<!--[if IE]><p>You are using Internet Explorer.</p><![endif]-->
<![if !IE]><p>You are not using Internet Explorer.</p><![endif]>

<!--[if IE 7]><p>Welcome to Internet Explorer 7!</p><![endif]-->
<!--[if !(IE 7)]><p>You are not using version 7.</p><![endif]-->

<!--[if gte IE 7]><p>You are using IE 7 or greater.</p><![endif]-->
<!--[if (IE 5)]><p>You are using IE 5 (any version).</p><![endif]-->
<!--[if (gte IE 5.5)&(lt IE 7)]><p>You are using IE 5.5 or IE 6.</p><![endif]-->
<!--[if lt IE 5.5]><p>Please upgrade your version of Internet Explorer.</p><![endif]-->

<!--[if true]>You are using an <em>uplevel</em> browser.<![endif]-->
<![if false]>You are using a <em>downlevel</em> browser.<![endif]>

<!--[if true]><![if IE 7]><p>This nested comment is displayed in IE 7.</p><![endif]><![endif]-->

除此之外,甚至可以指定 Windows 的版本,十分難以想像當時的使用情境。

#Conditional Compilation Statements

但其實我在書上看到的並不是這種形式,而是像下面這樣寫在 JS 裡面的 comment

<script>
  /*@cc_on
  document.write("You are using IE4 or higher");
@*/
</script>

這樣的語法在 Javascript 中,就只是單純的註解而已,但在 JScript 中不是單純的註解,而是可以被解析的內容,這樣的語法稱作 Conditional Compilation Statements5

而 JScript 也正是利用這樣的特性,讓內容只在 IE 上被執行,和 conditional comment 相似的是,Conditional Compilation Statements 也能夠指定 JScript 的版本,甚至還可以指定只在 statement 內作用的變數。不過這部份就不多提,有興趣的可以看參考資料

ECMAscript 是標準,我們現在提的 Javascript 這種語言通常說的是符合 ECMAscript 的實現(implementation),例如當初 Netscope 的 Javascript 以及 chrome V8 engine 的 Javascript 實現。而其他非 Javascript 的 ECMAscript 實現包含 ActionScript, JScript

#現狀

2012.9.4 開始,IE10 開始支援 HTML5,而 conditional comment 本身與 HTML5 的標準不相容6,所以 conditional comment 這個標準也被拔掉了。

當然,在十年後的今天,IE 也已經在 2022.6.15 開始不再被支援,相信這東西未來也不會在遇到了 🙃。

RIP IE
RIP IE

#Footnotes

  1. Javascript Patterns

  2. wiki - Conditional comment 2

  3. 不太確定 parser 是解析 <![if !(IE 8)]> 為 conditional comment 的語法,還是單單 [if !(IE 8)] 就有效果,只是為了要符合 xml 標準。找不到 IE5 HTML parser 的文件

  4. MSDN - About conditional comments

  5. archive: JScript 8.0: Conditional Compilation Statements

  6. archive: MSDN blog - HTML5 Parsing in IE10

# Comments