1. 引子:腾讯视频首页的条件注释

做前端的,见到优秀的网站就会去查看源代码,这是一种病,更是一种职业素养。腾讯作为中国最财大气粗的互联网公司,自是让前端开发者们趋之若鹜(我也不例外)。腾讯前端团队里高手云集自是不必说了,查看、学习腾讯各大网站源代码也是表达膜拜之意、向大神看齐的一种方式。

前两天浏览腾讯视频,顺手看了一下首页的源代码,发现下面几行:

<!--[if (IE 9)|(IE 10) ]>
<meta name="application-name" content="腾讯视频" />
<meta name="msapplication-tooltip" content="腾讯视频" />
<meta name="msapplication-task" content="name=首页;action-uri=/;icon-uri=/favicon.ico"/>
<meta name="msapplication-task" content="name=电影;action-uri=/movie/;icon-uri=/favicon.ico"/>
<meta name="msapplication-task" content="name=电视剧;action-uri=/tv/;icon-uri=/favicon.ico"/>
<meta name="msapplication-task" content="name=综艺;action-uri=/variety/;icon-uri=/favicon.ico"/>
<meta name="msapplication-task" content="name=动漫;action-uri=/cartoon/;icon-uri=/favicon.ico"/>
<meta name="msapplication-starturl" content="/" />
<![endif]-->

做前端的应该都知道条件注释里的元数据是用来实现 IE9+ 的固定网站功能的,不过我们现在要讨论的是条件注释。

<!--[if (IE 9)|(IE 10) ]> 的意思是如果是 IE9 或者 IE10 则渲染注释里面的代码。这在 IE 9 里完全没问题,因为 IE9 支持条件注释,用户将网站固定到任务栏后,在图标上点击右键就能看到几个频道的链接,点击可以直接打开 IE 进入相应链接。那 IE10 呢?

pin-to-taskbar

没有类似右图的链接,因为 IE10 已经删除条件注释支持(IE 被埋怨了那么多年,也想拜托前端开发恶梦的称号,做符合 Web 标准的现代浏览器),条件注释被当作普通注释处理,而且指定使用可用的最新模式解析文档(IE10里当然是IE10模式最新):

<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" />

所以在 IE9 中工作正常的固定网站功能,到 IE10 里就失效了。解决的一种方式是指定使用 IE9 模式——捡了芝麻丢了西瓜,所以还是干脆删除条件注释吧。

[caption id="attachment_416" align="alignnone" width="730"]condition-comments-on-ie10 IE10 中,条件注释被当作普通注释处理,忽略注释里的内容[/caption]

[caption id="attachment_417" align="alignnone" width="660"]IE9 模式下,可以正确处理条件注释 IE9 模式下,可以正确处理条件注释[/caption]

2. 条件注释详解

只有 IE5 - 9 支持条件注释。考虑到 IE 特别是 IE9 以前的版本在国内巨大的市场份额,详细了解一下条件注释还是很有必要的。

使用条件注释的好处

比起脚本探测浏览器,条件注释有以下好处:
  • 对客户端影响小。不支持条件注释的浏览器会忽略条件注释里内容,节省客户端资源。
  • 不需要额外的脚本。可以和其他浏览器探测技术结合。
  • 使用探测逻辑分离代码。使用条件注释可以将代码分离成更小、更简单的片段,易于理解和维护;可以根据浏览器版本按需载入代码。
  • 跨浏览器。(跨毛?连自家的IE10都不支持了)

条件注释语法

注释类型 语法
标准 HTML 注释 <!-- Comment content  -->
downlevel-hidden 不支持条件注释的浏览器隐藏, 支持的根据表达式判断 <!--[if expression]> HTML <![endif]-->
downlevel-revealed 不支持条件注释的浏览器显示, 支持的根据表达式判断 <![if expression]> HTML <![endif]>
条件注释里可以包含任何HTML内容,条件注释根据条件表达式判断是否解析注释里的内容。

条件表达式由以下项目组合而成:

项目 示例 注释
IE [if IE] 如果浏览器为IE则匹配
value [if IE 7] 浏览器版本,整数或浮点数
WindowsEdition [if WindowsEdition] Windows 7 上的 IE8 通过 "WindowsEdition" 匹配用户Windows版本
value [if WindowsEdition 1] 匹配Windows 版本(指专业版、旗舰版、服务器版等信息,而不是Vista、Win7这些信息,具体可参考 GetProductInfo function
true [if true] true值,支持条件注释的浏览器
false [if false] false值,不支持条件注释的浏览器
下表是条件表达式可以使用的运算符:
条目 示例 说明
! [if !IE] NOT 运算符,放在表达式前取表达式相反的值
lt [if lt IE 5.5] 小于运算符,如果低于指定参数则返回 ture
lte [if lte IE 6] 小于等于运算符(lte = less-than or equal)
gt [if gt IE 5] 大于运算符 (gt = greater-than)
gte [if gte IE 7] 大于等于运算符 (gte = greater-than or equal)
( ) [if !(IE 7)] 子表达式运算符,和布尔值运算符结合创建更复杂的表达式
& [if (gt IE 5)&(lt IE 7)]  AND 运算符,所有表达式为真时返回真
| [if (IE 6)|(IE 7)]  OR 运算符,任何一个子表达式为真时返回真

Downlevel-hidden 条件注释

<!--[if IE 8]>
<p>Welcome to Internet Explorer 8.</p>
<![endif]-->
不支持条件注释的浏览器作普通注释处理忽略,IE5 - 9 根据值来判断是否显示注释内容。

Downlevel-revealed 条件注释

<![if lt IE 8]>
<p>Please upgrade to Internet Explorer version 8.</p>
<![endif]>
不支持条件注释的浏览器及 IE5 - 7 显示注释内容。但是这样不符合 Web 标准,无法通过验证,改进一下:
<!--[if lt IE 8]><!-->
<p>Please upgrade to Internet Explorer version 8.</p>
<!--<![endif]-->

条件注释示例

<!--[if IE]><p>你在使用IE5 - 9</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]>你的浏览器支持条件注释<![endif]-->
<![if false]>你的浏览器不支持条件注释<![endif]>

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

<!--[if WindowsEdition 1]>
<p>你在使用旗舰版的Windows(蛋疼?)</p>
<![endif]-->


via About conditional comments - MSDN

3. 条件注释的一些应用

IE Mobile

<!--[if IEMobile]> 
   Displayed only on Internet Explorer Mobile on Windows Phone 7
<![endif]--> 

<!--[if !IEMobile]>-->
Not IEMobile
<!--<![endif]-->


测试了一下,貌似 Windows Phone 7.8 上的 IE9 已经不支持条件注释了,而市场使用 Windows Phone 7.0 的用户基本可以忽略,所以针对 IEMobile 的条件注释基本没用了(via )。

条件类名

以前条件注释结合 CSS 使用时,一种是以内嵌的方式把特定样式写进条件注释里,这样不太符合表现和内容分离的原则;另一种是使用条件注释引入特定的样式表,这样又会增加 http 请求。近几年,条件类名开始流行。
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
这是 html5-boilerplate 中条件类名,使用时可以根据实际情况修改类名。这样的好处可以把所有样式都写到一个样式表,使用类名为特定浏览器定义样式,无需再使用那些晦涩难辨、无法通过验证的 hack 了。

关于条件类名的发展过程,可以参考 Conditional Stylesheets vs CSS Hacks? Answer: Neither!;对于是不是每个版本的 IE 都应该添加相应的类名,也有争议,可以看一下 Don’t Use Conditional Comments to Create Classes for IE7+。个人觉得还是根据项目需要吧,一堆没用的类名加在上面也蛮恶心的。

条件类名一些其他资源:

 IE6 背景图缓存

<!--[if lte IE 6]>
<script type="text/javascript">
document.execCommand("BackgroundImageCache",false,true);
</script>
<![endif]-->