前面的話
瀏覽器提供商雖然在實現公共接口方面投入了很多精力,但結果仍然是每一種瀏覽器都有各自的長處,也都有各自的缺點。迄今為止,客戶端檢測仍然是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; } }