浏览器的特征探测
作者:屈超(Chappell.Wat) 发布时间:January 21, 2010 分类:程式::五代
【2010.01.21 更新】
Google 的 Closure Compile 会将 IE 的判断代码“压缩”成:
"\u000b"==="v"
要么压缩后替换回 "\v" ,
要么换其它方法判断 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() ,
而且经测试在最新的 Firefox 3.7a1pre nightly 也得到支持。
因此经过整理汇总,
我个人比较赞同的特征探测方法如下:
(function (win, doc) {
var isIE = '\v' === 'v',
isIE6 = isIE && !win.XMLHttpRequest,
isIE8 = !!win.XDomainRequest,
isIE7 = isIE && !!win.XMLHttpRequest && !isIE8,
isFF = !!doc.getBoxObjectFor || !!win.DataTransfer, // gecko
isOP = !!win.opera,
isWK = !!win.devicePixelRatio, // web-kit
isSF = /a/.__proto__ == '//', // safari
isCR = !isFF && !!win.MessageEvent; // chrome
})(window, document);
其中值得一提的是 web-kit 内核,
window.devicePixelRatio() 能区分出所有的 web-kit based 浏览器,
其中包括 Maxthon 3 的极速模式和其它尚未发布的类似浏览器。
最后呢,
我还整理了 Firefox 重大里程碑版本的特征判断法,
不建议被纳入通用的判断方法里,
但是如果你刚好被这些版本的差异所困扰时,
它们应该能有用:
(function (win) {
var upperFF36 = !!win.DataTransfer, // 3.6 以上,下同
upperFF35 = !!Object.getPrototypeOf,
upperFF2 = !!win.globalStorage;
upperFF3 = upperFF2 && !!win.MessageEvent,
upperFF15 = !!Array.some;
})(window);
其中 3.0 和 3.6 是我个人觉得变化最大的两个里程碑版本,
指不定什么时候你就能用到。
另外,
Firefox 的重大版本变化几乎总跟随着 Javascript 的版本升级,
因此对于 3.0 版本你还可以用 !!Array.reduce 来判断,
当然前提是你没有对 Array 原型进行扩展。
Ref:
《Javascript浏览器判断终极技巧》
《JavaScript 判断浏览器类型及版本》
(以上两文总结得都很不错,
只是 Firefox 和 Safari 的部分需要更新)
写得很乱很杂,
这次就不照例上图了……
已有 9 条评论 »
空哥威武!
研究的比较透彻,虽然我不明白,但写了那么多,肯定研究的深
[...]这篇文章的原地址:http://www.quchao.com/entry/detect-browser-by-features/[...]
看不懂的观众围观···
博主大~~你的feed貌似有誤誒- -
@P
感谢提醒,
已经重新绑定域名。
:)
研究的好透彻,,膜拜一下.
看不明白膜拜一下
@火头坨工
很惭愧,
所有汉化工作已经中止一年有余。
由于工作关系也几乎不可能再开,
能够转手的项目也都已经转手给其它人。