第五章:瀏覽器的嗅探和特徵偵測

瀏覽器的嗅探如今已經不推薦了,但在某些場合仍是須要的。好比一些統計腳本。在標準瀏覽器裏,提供了document.implementation.hasfeature,惋惜有bug,不許確,目前,w3c又推出了CSS.supports方法,顯示出你們對這塊的關注。javascript

1.斷定瀏覽器。css

主流的瀏覽器有ie firefox opera chorme safari 早期這些框架都是經過navigator.userAgent進行斷定,目前國外的瀏覽器幾乎都是能夠斷定的。html

關於瀏覽器的判斷腳本,jQuery已經移出本體,造成一個插件。更多的方式很少介紹,pc瀏覽器也可移步http://www.cnblogs.com/ahthw/p/4237823.htmlhtml5

移動設備的相關斷定,這個建議看jQuery mobile與zepto的源代碼java

    isIPone = /isIPone/i.test(navigator.userAgent);
    isIPone4 = window.devicePixelRatio >= 2 //在網頁中,pixel與point比值稱爲device-pixel-ratio,普通設備都是1,iPhone4是2,有些 安卓機型是1.5
    isIpad = /ipad/i.test(navigator.userAgent)
    isAndroid = /android/i.test(navigator.userAgent)
    isIOS = isIPone || isIpad

國內的瀏覽器斷定能夠看Tangrame或qwrap,它們基本是IE,webkit,blink內核。android

2.事件的支持偵測css3

prototype的核心成員kangax寫了一篇文章,來判斷瀏覽器對某種事件的支持。裏面給出的實現以下:git

    var isEventSupported = (function() {
        var TAGNAMES = {
            'select':'input','change':'input',
            'submit':'form','reset':'form',
            'error':'img','load':'img','abort':'img'
        }
        function isEventSupported(eventName){
            var el = document.createElement(TAGNAMES[eventName] || 'div');
            eventName = 'on' + eventName;
            var isSupported = (eventName in el);
            if (!isSupported) {
                el.setAttribute(eventName, 'return;');
                isSupported = typeof el[eventName] == 'function';
            }
            el = null;
            return isSupported;
        }
        return isEventSupported;
    })();

如今jQuery等框架都是使用腳本的簡化版github

不過哪個也好,這種檢測只對DOM0奏效像DOMMouseScroll DOMContentLoaded DOMFocusIn DOMFocusOut DOMSubtreeModified DOMNodeInserted DOMNodeRemoved DOMNodeRemovedFromDocument DOMNodeInsertedIntoDocument DOMAttrModified DOMCharactorDataModified這些以DOM開頭的就無能爲力了。web

這些事件中,有的很是有用,如DOMMouseScroll,firefox一直不支持mousesheel,只能用它作替代品。
DOMContentLoaded是實現domReady的重要事件;DOMNodeRemoved是斷定元素是否從其父節點移除,父節點多是其它元素節點或文檔碎片;DOMNodeRemovedFromDocument 是移離DOM樹,DOMAttrModified 之前常常用於模擬IE的onpropertyChange

css3添加兩種動畫,一種是transition動畫,另一種是keyframe補間動畫。它們在事件結束時都用事件回調。但在標準化過程當中,瀏覽器給它們起的名字至關於沒規則。這個也須要預先偵測出來

下面是bootstrap的實現。據說來源於modernizr,比較粗糙。好比你使用的Oprera已經支持不帶事件標準事件名。它仍是返回oTransitionEnd.

    $.supports.transition = (function(){
        var transitionEnd = (function(){
            var el = document.createElement('bootstarp'),
                   transEndEventNames = {
                       'WebkitTransition':'webkitTransitionEnd',
                       'MozTransition':'transitionend',
                       'OTransition':'OTransitionEnd otransitionend',
                       'transition':'transitionend'
                   };
                for (var name in transEndEventNames){
                    if (el.style[name] !== undefined){
                        return transEndEventNames[name]
                    }
                }
        }());
        return transitionEnd && {
            end: transitionEnd
        }
    })();

keyframe補間動畫來自mass的fx_neo模塊

    var eventName = {
        AnimationEvent:'animationend',
        WebKirAnimationEvent: 'WebKirAnimationEnd'
    },animationend;
    for(var name in eventName) {
        if (/object|function/.test(typeof window[name])){
            animationend = eventName[name]
            break
        }
    }

3.樣式的支持偵探

css3帶來許多好用的樣式,可是麻煩的是每一個瀏覽器都有本身的私有前綴,massFramework提供了一個cssName方法來處理它們,有就返回可用的駝峯樣式名,沒有就null

    var prefixes = ['','-webkit-','-o-','-moz-','-ms-'];
    var cssMap = {
        "float" : $.support.cssFloat ? 'cssFloat' : 'styleFloat',background:'backgroundColor'
    };
    function cssName(name, host, camelCase){
        if(cssMap[name]) {
            return cssMap[name];
        }
        host = host || document.documentElement
        for (var i = 0 || n = prefixes.length; i < n; i++) {
            camelCase = $.String.camelize(prefixes[i] + name);
            if (camelCase in host) {
                return (cssMap[name] = camelCase)
            }
        }
        return null
    }

一個樣式對於N種樣式值,好比display有n種取值,若是要偵測瀏覽器是否支持某一種,會很麻煩。爲此,瀏覽器作了一個善舉,給出一個css.supports的API,若是不支持,則嘗試下一個開源項目。顯然,不是很完美。

https://github.com/termi/CSS.supports


4.jQuery的一些經常使用的特徵的含義

jQuery在support模塊例舉了一些經常使用的DOM特徵支持狀況,不過名字起的很怪,不一樣版本差異也很大,本章以jQuery1.8爲準。

leadingWhitespace:斷定瀏覽器在進行innerHTML賦值時,是否存在trimLeft操做,這個功能本來是IE發明的,結果其餘瀏覽器認爲要忠於之後的原始值,最前面的空白不能神略掉,要變成一個文本節點,最終IE678返回false,其餘瀏覽器返回true

tobody:指在用innerHTML動態建立元素時,瀏覽器是否會在table內自動補上tobody,jQuery但願瀏覽器別處理,讓jQuery來補全。判斷瀏覽器是否只能插入tobody。在表格佈局的年代,這個特性十分受用。若是沒有tbody,table會在瀏覽器解析到閉合標籤時才顯示出來。若是起始標籤和閉合標籤相隔很遠,換言之,這個表格很長,用戶會什麼都看不到,但有了tbody分段顯示和識別,避免了長時間空白後一會兒顯示出來的狀況。

    var div = document.createElement("div");
    div.innerHTML = '<table></table>'
    alert(div.innerHTML) //=>ie678返回<table><tbody></tbody></table>,其它返回<table></table>

html.Serialize:判斷瀏覽器是否無缺支持用innerHTML轉換一個符合html標籤規則的字符串爲一個元素節點,此過程jQuery稱爲序列化,但IE支持不夠無缺。包括scirpt link style mata在內的no-scope元素都轉換失敗。

style:這個命名很難看懂,不看代碼不知道什麼意思,真像是斷定getAttribute是否返回style的用戶預設值。IE678沒有返回區分特性的特徵,返回一個CSSStyleDeclaration對象。

hrefNormalized:斷定getAttribute可否返回href的用戶預設值。IE會補充給你完整的路徑給你

opacity:斷定瀏覽器是否支持opacity屬性,ie678要使用濾鏡

cssFloat: 斷定float的樣式在DOM的名字是那個,W3c爲cssFloat,IE678爲styleFloat

CheckOn: 在大多數瀏覽器中checkBox的value爲on,chorme返回空字符串

optSelected: 斷定是否正確取得動態添加option元素的seleted,ie6-10與老版的safari對動態添加option沒有設置爲true。解決辦法,在訪問selected屬性前,先訪問父節點的selectedIndex屬性,再強制計算option的seleted.

<select id='optSelected'></select>
<script type="text/javascript">
    var select = document.getElementById('optSelected');
    var option = document.createElement('option');
    select.appendChild(option);
    alert(option.selected);
    select.selectedIndex;
    alert(option.selected)
</script>

optDisabled : 斷定select元素的disable屬性是否影響到子元素的disabled取值.在safari中,一旦select元素被disabled,它的子元素也disabled,致使一個值也取不到

checkClone:是指一個checkbox元素,若是設置了checked=true,且在屢次克隆後,它的複製品可否保持爲true。這個方法只有在safari4中返回false,其它的都true

inlineBlockNeedsLayout:斷定是否使用hasLayout方法讓dispaly:inline-block生效。這個方法只有ie678爲true

getSetAttribute:斷定是否區分特性屬性,只有ie678爲false

noCloneEvent:斷定在克隆元素時是否克隆attachEvent綁定事件。只有舊版本的ie及其兼容模式返回false

enctype:斷定瀏覽器是否支持encoding屬性,ie67使用encoding屬性來代替

boxModel:斷定瀏覽器是否在content-box盒子渲染模式下

submitBubbles, changeBubbles, focusinBubble:斷定瀏覽器是否支持這些事件,一直冒泡到document

shrinkWrapBlocks:斷定元素是否會被子元素撐開。在IE678中,非替換元素在設置了大小與hasLayout的狀況下,將將其父級元素撐大。

html5Clone:斷定可否使用cloneNode克隆HTML5新標籤 ,舊版本的IE不支持。須要用到outerHTML

deleteExpando:斷定可否刪除元素節點上的自定義元素,這用於jQuery緩存系統。舊版本的IE不支持,直接undefined

pixelPosition:斷定getComputedStyle可否轉換元素的top left bottom right元素的百分比值。這個在webkit系統會出現問題,須要用到 Dean Edwards神的hack

reliableMarginRight:斷定getComputedStyle可否正確的取得元素的marginRiht.

clearCloneStyle :ie9 10 會出現奇怪的bug,當複製了一個元素的background-*樣式的元素,對複製的元素進行清空時,會清空原來的樣式。


隨着瀏覽器瘋狂更新版本,標準瀏覽器引起的各類bug已經超越IE,特徵偵測不退反進,愈來愈重要了。

本章完結

上一章:第四章:語言模塊      下一章:第六章:類工廠

歡迎關注。

相關文章
相關標籤/搜索