其中jQuery.browser已經提供了根據UserAgent檢測的瀏覽器資訊。而jQuery.support 使用特性檢測來檢查瀏覽器的功能以及Bug。
和文檔一樣,首先說明一下,這個模組是很底層的代碼,基本不需要在日常開發中使用,但是外掛程式的開發人員更需要。因為外掛程式需要相容各個瀏覽器。首先看一下 support模組提供了哪些瀏覽器特性的檢測,以下結果是在Chrome 13 Dev下看到的結果。根據瀏覽器的不同,這裡的成員可能會有變化。(PS:再次吐槽IE,大部分屬性都是IE比較特別)
- ajax: true。是否支援XMLHttpRequest對象。老版本的IE不支援,必須用ActiveX。 * appendChecked: true。 * boxModel: true。是否根據W3C CSS盒模式渲染。IE6和7的Quirks模式為False。 * changeBubbles: true。change事件是否沿著DOM樹冒泡。這是W3C DOM事件模型的要求,但是IE目前為止是False。jQuery類比了這個冒泡特性。 * checkClone: undefined。在複製Radio Button或者CheckBox時是否保留選中狀態。以前說createFragment緩衝的時候提到過,WebKit核心是不保留的。 * checkOn: false。CheckBox在沒有指定時是否預設為On。 * cors: true。XMLHttpRequest對象是否帶有withCredentials屬性。可以執行跨域請求。或者沒有這個屬性,但是有其他途徑可以實現跨域XHR請求的,也是True(比如通過Windows Gadget)。 * cssFloat: true。支援cssFloat的CSS屬性。IE是False,它使用了styleFloat。 * deleteExpando: true。 * focusinBubbles: false。 * getSetAttribute: true。 * hrefNormalized: true。對一個a元素調用getAttribute("href")時,是否返回原始指定的URL。IE會返回完整路徑。比如對於href="1.html"的連結,IE會得到http://..../1.html。 * htmlSerialize: true。是否可以用innerHTML插入link元素。IE為false。 * inlineBlockNeedsLayout: false。為了讓block元素表現inline-block,是否需要為inline並且hasLayout(IE下的概念,大部分布局問題的根源)。IE8以下有問題。 * leadingWhitespace: true。innerHTML 屬性是否嚴格按照代碼渲染。IE6-8中會去掉前置的空白。(所以使用Markdown寫的這篇文章在IE下有格式問題,因為換行不見了) * noCloneChecked: true。1.5.1新屬性。檢測瀏覽器是否複製checked擴充屬性。IE為false。 * noCloneEvent: true。拷貝的元素是否會帶有事件處理函數(即Event handler是否被拷貝過去)。IE為false。 * opacity: true。是否支援opacity CSS屬性(透明度)。IE為false,它使用alpha filter。 * optDisabled: true。已經disabled的select元素中的option元素是否預設為disabled。 * optSelected: true。一個預設被選中的option元素的selected屬性是否正常。 * radioValue: true。 * reliableHiddenOffsets: true。在table的cells被設定為display:none的時候,仍然有offsetWidth/Height。即hidden靠不住。只有IE8有這個問題。參見4512號bug * reliableMarginRight: true。div有顯式的寬度,但是沒有margin-right。此時基於容器計算margin-right不正確。舊版本WebKit有問題。參見3333號bug * scriptEval(): 1.5.1版本前,這是一個屬性,而現在變成函數了。檢測一個inline的指令碼在使用標準的DOM操作函數被添加時是否會自動執行。比如appendChild和createTextNode。IE是false,它使用text來插入指令碼。 * shrinkWrapBlocks: false。元素在hasLayout的情況下是否會撐大父節點。只有IE6是true。 * style: true。一個元素的inline的style屬性是否可以用DOM屬性訪問。比如getAttribute("style")。IE是false,它使用cssText屬性。 * submitBubbles: true。submit事件是否沿著DOM樹冒泡。IE為false,jQuery類比了這個冒泡過程。 * tbody: true。一個空的table元素是否可以沒有tbody元素。根據HTML規範,子項目是可選的。但是IE是false,所以會自動插入一個tbody元素。
jQuery建立了幾個元素用來判斷瀏覽器特性。如下:
複製代碼 代碼如下:
var div = document.createElement("div");
div.setAttribute("className", "t");
div.innerHTML = " <LINK><TABLE><TBODY></TBODY></TABLE><A style="FLOAT: left; TOP: 1px; opacity: .55" href="http://www.jb51.net/a">a</A><INPUT type=checkbox>";
all = div.getElementsByTagName("*");
a = div.getElementsByTagName("a")[0];
var select = document.createElement("select");
opt = select.appendChild(document.createElement("option"));
input = div.getElementsByTagName("input")[0];
其中div元素相當有內涵。包括了空白開頭,空Table元素,inline style,opacity等等。除了一行行看代碼和注釋也沒啥其他筆記了:
複製代碼 代碼如下:
support = {
// IE會把開頭的空格去掉,所以nodeType不是3(文本)
leadingWhitespace: (div.firstChild.nodeType === 3),
// IE會自動插入tbody,所以length不同
tbody: !div.getElementsByName("tbody").length,
// IE不允許用這種方式插入link元素
htmlSerialize: !!div.getElementsByTagName("link").length,
// 如果正常獲得style的話,這個Regex應該會正常通過
style: /top/.test(a.getAttribute("style")),
// href屬性應該是原始指定的字串,IE會修改為http開頭的絕對URL
hrefNormalized: (a.getAttribute("href") === "/a"),
// 能得到opacity屬性。這裡使用了Regex,是為了繞過WebKit[5145號bug](http://dev.jquery.com/ticket/5145)
// 但是這應該是一個早期版本的問題。起碼在Chrome 13中,不用正則也是對的。
opacity: /^0.55$/.test(a.style.opacity),
// IE使用styleFloat
cssFloat: !!a.style.cssFloat,
// div中的checkbox沒有指定值,看預設值是否是on。WebKit是""。所以我的結果是false
checkOn: (input.value === "on"),
// 這個select只有一個option元素,所以渲染時,這個option是預設選中的。此時selected應該是true。
optSelected: opt.selected,
submitBubbles: true,
changeBubbles: true,
focusinBubbles: false,
deleteExpando: true,
noCloneEvent: true,
inlineBlockNeedsLayout: false,
shrinkWrapBlocks: false,
reliableMarginRight: true
};
下面的大部分都是按部就班的測試。其中BoxModel的測試比較有趣:
複製代碼 代碼如下:
div.innerHTML = ""; // 從頭來
div.style.width = div.style.paddingLeft = "1px";
body = document.createElement("body");
body.style.width = 0;
body.style.height = 0;
body.style.border = 0;
body.style.margin = 0; // 全部設定為0
body.appendChild(div);
document.documentElement.insertBefore(body, document.documentElement.firstChild);
support.boxModel = div.offsetWidth === 2;
// 這個時候div嵌套在body下。而body長寬高,邊框和margin都是0。所以div的位移應該就是它自己的paddingLeft+width。如果不對,就說明盒模式不對。
然後值得注意的是事件的冒泡,注釋中提到的技術參考文章連結已經失效。請自己搜尋"Detecting event support without browser sniffing"
複製代碼 代碼如下:
// attachEvent是IE的,所以這裡實際上只檢查了IE,其他瀏覽器都是前面設定的預設值。
if(div.attachEvent) {
for(i = {
submit: 1,
change: 1
focusin: 1
}) {
eventName = "on" + i;
isSupported = (eventName in div);
if(!isSupported) {
div.setAttribute(eventName, "return;");
isSupported = (typeof div[eventName] === "function");
}
support[i + "Bubbles"] = isSupported;
}
}
PS: 瀏覽器檢測是一個很糾結,很細節的任務。這個筆記慢慢完善中……
18:30補充:經過IE9的測試,以上大部分IE相關問題都已經不存在。以下是IE9+Win7的測試結果:
複製代碼 代碼如下:
$.support
{
boxModel: true,
changeBubbles: true,
checkClone: true,
checkOn: true,
cssFloat: true,
deleteExpando: true,
hrefNormalized: true,
htmlSerialize: true,
leadingWhitespace: true,
noCloneEvent: false,
opacity: true,
optSelected: false,
parentNode: true,
scriptEval: true,
style: true,
submitBubbles: true,
tbody: true
}