虽然浏览器厂商齐心协力想要实现一致的接口,但事实上仍然是每家浏览器都有自己的长处与不 足。跨平台的浏览器尽管版本相同,但总会存在不同的问题。这些差异迫使 Web 开发者要么面向最大 公约数而设计,要么(更常见地)使用各种方法来检测客户端,以克服或避免这些缺陷。

客户端检测一直是 Web 开发中饱受争议的话题,这些话题普遍围绕所有浏览器应支持一系列公共 特性,理想情况下是这样的。而现实当中,浏览器之间的差异和莫名其妙的行为,让客户端检测变成一 种补救措施,而且也成为了开发策略的重要一环。如今,浏览器之间的差异相对 IE 大溃败以前已经好 很多了,但浏览器间的不一致性依旧是 Web 开发中的常见主题。

要检测当前的浏览器有很多方法,每一种都有各自的长处和不足。问题的关键在于知道客户端检测 应该是解决问题的最后一个举措。任何时候,只要有更普适的方案可选,都应该毫不犹豫地选择。首先 要设计最常用的方案,然后再考虑为特定的浏览器进行补救。

能力检测

能力检测(又称特性检测)即在 JavaScript 运行时中使用一套简单的检测逻辑,测试浏览器是否支 持某种特性。这种方式不要求事先知道特定浏览器的信息,只需检测自己关心的能力是否存在即可。能 力检测的基本模式如下:

if (object.propertyInQuestion) { // 使用object.propertyInQuestion
}

比如,IE5 之前的版本中没有 document.getElementById()这个 DOM 方法,但可以通过 document.all 属性实现同样的功能。为此,可以进行如下能力检测:

   function getElement(id) {
      if (document.getElementById) {
        return document.getElementById(id);
      } else if (document.all) {
        return document.all[id];
      } else {
        throw new Error("No way to retrieve element!");
      }
     }

这个 getElement()函数的目的是根据给定的 ID 获取元素。因为标准的方式是使用 document. getElementById(),所以首先测试它。如果这个函数存在(不是 undefined),那就使用这个方法; 否则检测 document.all 是否存在,如果存在则使用。如果这两个能力都不存在(基本上不可能),则 抛出错误说明功能无法实现。

能力检测的关键是理解两个重要概念。首先,如前所述,应该先检测最常用的方式。在前面的例子 中就是先检测 document.getElementById()再检测 document.all。测试最常用的方案可以优化代 码执行,这是因为在多数情况下都可以避免无谓检测。
其次是必须检测切实需要的特性。某个能力存在并不代表别的能力也存在。比如下面的例子:

  function getWindowWidth() {
if (document.all) { // 假设IE
return document.documentElement.clientWidth; // 不正确的用法! } else {
    return window.innerWidth;
  }
}

这个例子展示了不正确的能力检测方式。getWindowWidth()函数首先检测 document.all 是否 存在,如果存在则返回 document.documentElement.clientWidth,理由是 IE8 及更低版本不支持 6 window.innerWidth。这个例子的问题在于检测到 document.all 存在并不意味着浏览器是 IE。事实, 也可能是某个早期版本的 Opera,既支持 document.all 也支持 windown.innerWidth。

更多推荐