客户端检测之能力检测
浏览器提供商虽然在实现公共接口方面投入了很多精力,但结果仍然是每一种浏览器都有各自的长处,也都有各自的缺点。迄今为止,客户端检测仍然是Web开发领域中一个饱受争议的话题。一谈到这个话题,人们总会不约而同地提到浏览器应该支持一组最常用的公共功能。但是,在现实当中,浏览器之间的差异以及不同浏览器的“怪癖”(quirk)多得简直不胜枚举
检测Web客户端的手段很多,而且各有利弊。但不到万不得已,就不要使用客户端检测。只要能找到更通用的方法,就应该优先采用更通用的方法。最常用也最为人们广泛接受的客户端检测形式是能力检测(又称特性检测)。本文将详细介绍客户端检测之能力检测
定义
能力检测的目标不是识别特定的浏览器,而是识别浏览器的能力。能力检测的基本模式如下:
if(Object.propertyInQuestion){ //使用Object.propertyInQuestion }
【注意事项】
使用能力检测时,要注意不应仅仅检测该特性是否存在。以检测sort排序为例
function isSortable(object){ return !!object.sort; }
上面这个函数通过检测对象是否存在sort()方法,来确定对象是否支持排序。但问题是任何包含sort属性的对象也会返回true
var result = isSortable({sort:true});
检测某个属性是否存在并不能确定对象是否支持排序,更好的方式是检测sort是不是一个函数
function isSortable(object){ return typeof object.sort == "function"; }
上面的typeof操作符用于确定sort的确是一个函数,因此可以调用它对数据进行排序
【BUG】
在IE中typeof xhr.open会返回"unknown"
if(window.ActiveXObject){ var xhr = new ActiveXObject("Microsoft.XMLHttp"); alert(typeof xhr.open) }
于是,在浏览器环境下测试任何对象的某个特性是否存在使用下面这个函数
function isHostMethod(object,property){ var t = typeof object[property]; return t == "function" || (!!(t == "object" && object[property])) || t== "unknown"; }
接下来,将针对不同浏览器的能力检测分别说明
单版本IE
如果要通过能力检测识别出单独的某一版本IE浏览器,document.documentMode属性无疑非常合适。该属性只有IE浏览器支持,表示当前的文档模式
//IE11返回11,IE10返回10,IE9返回9,IE8返回8,IE7返回7,IE6返回6 console.log(document.documentMode);
function isIE6(){ return document.documentMode == 6; }
同样地,也可以识别出低版本IE,如IE7-浏览器
function lteIE7(){ return document.documentMode <= 7; }
IE7-
除了使用document.documentMode属性外,还有其他方法
【1】IE7-浏览器中,获取特性节点将获得包括内置特性的所有特性,第0个特性节点是onmsanimationiteration,且其specified属性是false。而IE8+及其他浏览器仅仅可以获得经过设置的特性节点,且specified属性永远是true
function lteIE7(){ var div = document.createElement('div'); var temp = div.attributes[0]; return (Boolean(temp) && !temp.specified); }
【2】IE7-浏览器不支持querySelector()和querySelectorAll()
function lteIE7(){ var temp = typeof document.querySelector; if(temp == 'undefined'){ return true; } }
【3】IE7-浏览器不支持JSON对象
function lteIE7(){ try{ JSON; }catch(error){ return true; } }
IE8-
【1】IE8-浏览器不支持getComputedStyle()方法,该方法是一组在显示元素时实际使用的属性值,用一个 CSSStyleDeclaration对象来表示的
function lteIE8(){ var temp = typeof window.getComputedStyle; if(temp == 'undefined'){ return true; } }
【2】IE8-浏览器不支持文档类型节点的快捷写法document.doctype
function lteIE8(){ var temp = document.doctype; if(temp == null){ return true; } }
【3】IE8-的宿主对象是通过COM而非javascript实现的。因此,document.createElement()函数是一个COM对象,所以typeof才会返回"Object"
function lteIE8(){ var temp = typeof document.createElement if(temp == "object"){ return true; } }
IE9-
【1】IE9-浏览器不支持HTML5新增的定时器requestAnimationFrame
function lteIE9(){ try{ requestAnimationFrame; }catch(error){ return true; } }
【2】async属性是HTML5新增的属性,IE9-浏览器不支持
function lteIE9(){ var temp = document.createElement('script'); if(!temp.async){ return true; } }
【3】window.matchMedia()方法用来检查CSS的mediaQuery语句,IE9-浏览器不支持
function lteIE9(){ var temp = window.matchMedia; if(!temp){ return true; } }
IE10-
【1】IE10-浏览器不支持自定义属性dataset
function lteIE10(){ var temp = document.createElement('div').dataset; if(!temp){ return true; } }
【2】IE10-浏览器不支持navigator对象的language属性
function lteIE10(){ var temp = navigator.language; if(!temp){ return true; } }
【3】IE10-浏览器不支持navigator对象的product属性
function lteIE10(){ var temp = navigator.product; if(!temp){ return true; } }
chrome
chrome浏览器在window对象下有一个专有的chrome属性,返回一个对象
function isChrome(){ if(window.chrome){ return true; } }