1. User-Agent 检测
网景浏览器的 user-agent 字符串如下:
Mozilla/2.0 (Win95; I)
Internet Explorer 浏览器的 user-agent 字符串如下:
Mozilla/2.0 (cmopatible; MSIE 3.0; windows 95)
这使得新生浏览器部分复制现有浏览器用户代理字符串成了一种趋势。
服务器可以获取到浏览器的 user-agent 字符串,客户端通过 JavaScript 的 navigator.userAgent 也可以获取。
// 不好的做法
if (navigator.userAgent.indexOf("MSIE") > -1) {
// 是 IE
} else {
// 不是 IE
}
解析 user-agent 字符串并非易事,由于浏览器为了确保其兼容性,都会复制另一个浏览器的用户代理字符串,因此随着每一个新浏览器的出现,用于用户代理检测的代码都需要更新。整个方法长期而言并不具备很好的可维护性。
选择使用用户代理检测,最安全的方法是只检测旧的浏览器。
if (isInternetExplorer8OrEarlier) {
// 处理 IE8 及更早版本
} else {
// 处理其他浏览器
}
几乎所有的浏览器的 user-agent 都可以被工具修改,因此要尽可能避免检测 user-agent。
2. 特性检测
特性检测的原理是为特定浏览器的特性进行测试,并仅当特性存在时即可应用特性检测。
// 不好的写法
if (navigator.userAgent.indexOf("MSIE 7") > -1) {
// 做些什么
}
// 好的写法
if (document.getElementById) {
// 做些什么
}
// 好的写法
function getById(id) {
var element = null;
if (document.getElementById) { // DOM
element = document.getElementById(id);
} else if (document.all) { // IE
element = document.all[id];
} else if (document.layers) { // Netscape <= 4
element = document.layers[id];
}
return element;
}
这么使用特性检测是正确和恰当的,因为代码对特性做检测,当特性存在时才使用。
正确检测的顺序:
探测标准的方法
探测不同浏览器的特定方法
均不存在时提供一个合乎逻辑的备用方法
3. 避免特性推断
特性推断尝试使用多个特性但仅验证了其中之一。根据一个特性的存在推断另一个特性是否存在。问题是,推断是假设并非事实,而且可能会导致维护性的问题。
// 不好的写法 - 特性推断
function getById(id) {
var element = null;
if (document.getElementByTagName) { // DOM
element = document.getElementById(id);
} else if (window.ActiveXObject) { // IE
element = document.all[id];
} else { // Netscape <= 4
element = document.layers[id];
}
return element;
}
该函数是最糟糕的特性推断。
4. 避免浏览器推断
// 不好的写法
if (document.all) { // IE
id = document.uniqueID;
} else {
id = Math.random();
}
所做的所有探测仅仅说明 document.all 是否存在,而并不能用于判断浏览器是否是 IE。document.all 的存在并不意味着 document.uniqueID 也是可用的。因此这是一个错误的隐式推断,可能会导致代码不能正常运行。
通过特性检测而推断出是某个浏览器同样是很糟糕的做法,这叫做浏览器推断,是一种错误的实践。
5. 应当如何取舍
特性推断和浏览器推断都是糟糕的做法,应当不惜一切代价避免使用。纯粹的特性检测是一种很好的做法。不要试图推断特性间的关系,否则最终得到的结果也是不可靠的。
如果想要使用用户代理嗅探,记住这一点:这么做唯一安全的方式是针对旧的或特定版本的浏览器。而绝不应当针对最新版本或者未来的浏览器。