注册
登录

您现在的位置是:首页 > 学无止境

浏览器的特征探测

木木彡82 2011-01-14 10:58:00 621人围观
浏览器的特征探测

转载自:http://www.quchao.com/entry/detect-browser-by-features/

作者:屈超(Chappell.Wat)

【2010.12.08 更新】
抱歉,
用原生 IE9 测试后发现 IE9 的判断代码已失效,
研究将继续……

【2010.11.29 更新】
之前的 IE8 检测方式容易被“伪造”,
改为检查 Image 对象是否存在 prototype 的方式。
另外有朋友说 IE8 的探测在 IE7 模式下也通过,
我想说这是我有意为之:
目的就是要探测浏览器本身的真实版本,
具体运行于哪种模式可以通过 doc.documentMode 来获得。

【2010.11.17 更新】
IE9 不知从哪个 Pre 版开始,
又恢复了之前更新时所提到的
非空数组字面量的最后一个元素缺失的问题,
也就是说这个 Bug 又得以“重现”了。
我个人推断是太多线上应用依靠这个 Bug 来识别 IE ,
因此开发团队不得已而为之。
但不管怎样,
本文还得继续。
目前利用了 IE9- 里 toFixed 方法在特定情况不会四舍五入的 Bug 来判定,
具体代码请见正文。

【2010.08.13 更新】
增强了 IE6 的区分能力。
当然更可以使用 IE 自己的条件编译,
只是有的压缩器支持度有限,
不便于日常开发。

【2010.04.18 更新】
更加严格地区分出了 IE 9,
增强了 Opera 的区分能力,
并将 Chrome 的判别特征换成了引擎特性,
这样你就能看出国内哪些浏览器是从 Chrome 的内核改过来的了,
大家可以动手试试。 :)

【2010.04.17 更新】
IE 9 在我看来改进非常大:
有我所关心的对 Mutation Events 的支持,
还有事件模型的 W3C 化 等等……
本文中我就不多冗述,
有机会再另文探讨。
由于在项目中大量使用特征判断,
IE 9 在这方面最显著的变化是:
之前那则“最短的 IE 判断法”已经失效,
一起被修复的还有一直伴随 IE 的数组 Bug:
非空数组字面量的最后一个元素缺失的问题(即:[null,]),
因此现如今的最短记录保持者(6字节的 !-[1,])也已然失效。(而且不支持 CC 压缩)
你也不要尝试使用 addEventListener 方法来判别,
因为 IE 9 已经支持了。(事件的改进非常大,这很好)
所以说 IE 已经越来越靠近标准,
如果在项目中有对 IE 进行特殊处理的代码,
你可能需要在 IE9下重新检查一下了。

由于我个人依旧是 XP 的忠实拥趸,
而 XP 又很悲剧地无法安装 IE 9,
所以一些测试是在 Haitao Jia 同学的协助下完成,
在此表示感谢。
也正因为如此,
我没有进行覆盖面太广的测试。
不过目前所发现的唯一“幸存”下来的 IE 系列 Bug 依旧与刚提到的数组 Bug 有关,
微软修复了字面量里的 Bug 却忘了当字符串被 split 成数组后却涛声依旧啊。
虽然判断起来稍微麻烦了点,
但不管怎样这是我目前发现的仅剩不多地可以用来判断 IE 全系列的代码:

具体的代码请拖至文末。

【2010.03.18 更新】
IE 8 也支持 window.DataTransfer 这个拖拽时方法,
因此判断 gecko 内核的条件有所改动,
你可以在原有判断条件上排除 IE8 ,
或者选择 window.mozInnerScreenX 这类由 FF3.6 开始提供的 gecko 特有属性,
(相对应的获取纵坐标属性 window.mozInnerScreenX
还有用以检测某个节点是否满足某个选择器规则的方法 node.mozMatchesSelector (很实用)

【2010.01.21 更新】
Google 的 Closure Compile 会将 IE 的判断代码“压缩”成:

要么压缩后替换回 !+"/v1",
要么换其它更安全的方法来判断 IE 。

【2010.01.03 发表】
在撰写此文之前,陈成 告诉我 Nicholas C. Zakas 大师几天前刚好写了一篇名为
特征探测并非浏览器探测 (Feature detection is not browser detection)
的文章。
文章里“深刻”批判了MooTools所使用的特征探测法,
但真正令人信服的理由似乎在文中也并无体现,
只是说 MooTools 因 Firefox 3.6 的变化而被迫发布了一次升级,
然后说:

“当浏览器(功能)愈发地接近彼此,想从“特征”去区别它们将变得越来越困难和危险。
(As browsers grow closer together, looking at “features” to separate them will become more difficult and risky.)”

当然啦,
不仅是 Javascript ,
服务端想要统计客户端也必须依靠 User-Agent  (以下简称 UA),
而对于 UA Spoofs ,
尼古拉斯的看法是:

“你必须永远尊重浏览器所告知你的 UA 。
(You should always honor exactly what the browser is reporting as a user-agent.)”

因此从前后端统一的角度,
我个人还是赞同这一观点的。

但从另一方面看,
现在浏览器内核虽稍显得固定,
但集成多种内核出来闯荡江湖的浏览器也不少,
而且它们在中国的占有率都不是一般的高,
(但它们对 UA 的管理则不是一般的糟糕)
我想这是尼大师所没有料到的。
(值得一提的是马桶3的 web-kit 模式这次提供了 UA 特征符)

因此我觉得对于特征探测不可一棒子敲死,
而对于 UA 嗅探法也不能一味地捧上天,
能够准确判断出浏览器继而进行正确的 Hack 来确保完整体验才是王道。

呃……
写了这么多,
完全是针对尼大师的新文有感而发,
我预想中的正文从这里开始——

由于 Firefox 3.6 产生了巨大的变化
(当然不仅是 Javascript 这个层面,
也比如旧的 chrome 注册文件 contents.rdf 也被废止等等)
我们理应将 3.6 版本作为 Firefox 的一个里程碑版本来对待。
对于本文而言,
也就是传说中用来区别 Firefox 的诸多特征已经消失:
比如最令人熟知的 window.getBoxObjectFor() ,
再比如 /a/[-1] == 'a' 这个 trick 。
因此我们必须找一个新的特征来填上这个漏洞,
(想从 Firefox 1.0 找一个延续至今的特征极为困难)
查阅文档后你刚好可以找到一个从 3.6 开始
被 Firefox 用来保存拖拽时数据的方法 window.DataTransfer() , (经查 IE8 同样支持)
被 Firefox 提供用以获取可视区域相对窗口横/纵坐标的属性 window.mozInnerScreenX/Y ,
而且经测试在最新的 Firefox 3.7a1pre nightly 也得到支持。

因此经过整理汇总,
我个人比较赞同的特征探测方法如下:

其中值得一提的是 web-kit 内核,
window.devicePixelRatio() 能区分出所有的 web-kit based 浏览器,
其中包括 Maxthon 3 的极速模式和其它尚未发布的类似浏览器。
Chrome 比 Safari 多一个 window.MessageEvent,
但要注意排除 Firefox。

最后呢,
我还整理了 Firefox 重大里程碑版本的特征判断法,
不建议被纳入通用的判断方法里,
但是如果你刚好被这些版本的差异所困扰时,
它们应该能有用:

其中 3.0 和 3.6 是我个人觉得变化最大的两个里程碑版本,
指不定什么时候你就能用到。
另外,
Firefox 的重大版本变化几乎总跟随着 Javascript 的版本升级,
因此对于 3.0 版本你还可以用 'reduce' in Array 来判断,
当然前提是你没有对 Array 进行扩展。

Ref:
Javascript浏览器判断终极技巧
JavaScript 判断浏览器类型及版本
(以上两文总结得都很不错,
只是 Firefox 和 Safari 的部分需要更新)
Detecting browsers javascript hacks 》 (推荐)

文章评论

  • 登录后评论

点击排行