深入理解瀏覽器兼容性模式

想必你一定知道瀏覽器有個標準(Standards)模式和一個怪異(Quirks)模式,或許你還聽說過有個“準標準(Almost Standards)”模式。而當你打開Internet Explorer的時候,又看到了什麼瀏覽器模式、文檔模式,還有什麼兼容性視圖等等...

這些都是什麼?啥是瀏覽器模式,啥是文檔模式?標準模式和準標準的模式有什麼區別?IE9兼容性視圖和真正的IE9有什麼區別?什麼情況下會觸發這些模式,又該怎樣才能檢測到瀏覽器當前處於哪種模式中呢?本文將詳細爲你解答這些疑問。

三種模式

首先我們要知道,爲什麼會有這麼多模式。其實這是個歷史遺留問題,在瀏覽器大戰時期,網景瀏覽器(Netscape Navigator)和微軟的IE瀏覽器(Microsoft Internet Explorer)對網頁分別有不同的實現方式,那個時候的網頁要針對這兩種瀏覽器分別開發不同的版本。而到了W3C制定標準之後,這些瀏覽器就不能繼續使用這種頁面了,因而會導致大部分現有站點都不能使用。基於這個原因,瀏覽器才引入兩種模式來處理一些遺留的站點。

現在的瀏覽器排版引擎支持三種模式:怪異(Quirks)模式、準標準(Almost Standards)和標準(Standards)模式。在怪異模式中,排版引擎會模擬 網景4和Windows中的IE5的行爲;在完全標準的模式中,會盡量執行HTML和CSS規範所指定的行爲;而在準標準模式中,則只包含很少的一部分怪異模式中的行爲。

那麼所謂標準模式,就一定都“標準”嗎?答案當然是否定的,因爲各個瀏覽器廠商實現標準的階段不同,所以各個瀏覽器的“標準模式”之間也會有很大的不同。

Firefox、Safari、Chrome、Opera (自 7.5 以後)、 IE8 和 IE9 都有一個準標準模式。那麼既然標準模式都不那麼標準,準標準的模式肯定就更不標準了。最初的準標準模式只會影響表格中的圖像,而後來各個瀏覽器又或多或少地進行了修改。那麼什麼情況下會觸發準標準模式呢?是的,正如你所想到的,某些DOCTYPE會觸發準標準模式,例如:

  1. "-//W3C//DTD XHTML 1.0 Transitional//EN"  
  2. "-//W3C//DTD XHTML 1.0 Frameset//EN"  
  3. "-//W3C//DTD HTML 4.01 Transitional//EN"  
  4. "-//W3C//DTD HTML 4.01 Frameset//EN"  
  5. "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd" 

一個完整的 DOCTYPE 例子如下:

  1. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"  
  2.                       "http://www.w3.org/TR/html4/loose.dtd"> 

如果在Firefox中插入這種DOCTYPE,並在頁面中插入一個空的span標籤,那麼在Firebug中查看元素的佈局就會發現不同:

準標準模式中元素的line-height被忽略了,元素既沒有寬度也沒有高度:

Almost Standards

標準模式中元素仍然保留了line-height,擁有18px的高度:

Standards

在Firefox瀏覽器中,使用鼠標右鍵->查看頁面信息 可以看到當前瀏覽器運行在何種模式(只能看到“混雜模式”和“標準規範模式”兩種表示):

mozilla-standard-mode

有位大神Henri Sivonen曾寫過一篇文章叫做Activating Browser Modes with Doctype,裏面包含了一個完整的表格,展示了各種DOCTYPE設置將會使瀏覽器以何種方式渲染。這裏還有一篇秦歌的譯文《用doctype激活瀏覽器模式》

鑑於目前一些最新版本的瀏覽器已經放棄了準標準模式,所以關於準標準模式的細節這裏就不再贅述了,感興趣的同學可以詳細閱讀以下資料:

那麼,既然這麼多的DOCTYPE都會觸發非標準的模式,那麼如何才能觸發標準模式呢?對了!要使用HTML5 DOCTYPE,即:

  1. <!DOCTYPE html> 

注意:如果文檔中沒有包含DOCTYPE或者包含了一個無法識別的DOCTYPE,則瀏覽器就會進入怪異模式。

下面簡單說一下怪異模式。怪異模式有許多“怪異”的行爲,主要是爲了兼容那些遺留的古老頁面而保留的模式。不同瀏覽器的怪異模式也不盡相同,它們都有自己的實現方式。怪異模式與標準模式的差異主要體現在 盒模型(box model)、表格單元格高度的處理等。例如IE的怪異模式中,元素的width包含了padding和border,而標準模式中padding和border 並不屬於寬度的一部分。

若想詳細瞭解瀏覽器在怪異模式下的行爲,可以參看下面兩篇文章。不過不建議在這上面花太多的精力,這是個歷史遺留問題,而且我們也儘量保證新開發的頁面不要進入到怪異模式:

小結:至此我們需要了解,瀏覽器有三種運行模式,即標準模式、準標準模式和怪異模式,要使用 <!DOCTYPE html> 來正確地觸發標準模式。千萬不要丟掉DOCTYPE聲明,因爲這會導致瀏覽器進入怪異模式。

IE的瀏覽器模式

IE8有4種模式:IE5.5怪異模式、IE7標準模式、IE8準標準模式和IE8標準模式,而IE9有7種模式: IE5.5怪異模式、IE7標準模式、IE8準標準模式、IE8標準模式、IE9準標準模式、IE9標準模式、XML模式。

其中XML模式是針對XML文檔的,這裏不打算闡述,細節可以看這篇文章[Defining Document Compatibility](http://msdn.microsoft.com/en-us/library/cc288325(v=vs.85).aspx) 中有詳細闡述。

在IE8及以後的的IE瀏覽器中,支持X-UA-Compatible頭,可以通過在服務器端設置HTTP頭,或者在頁面中插入<meta>標籤來實現:

  1. HTTP:  
  2. Header set X-UA-Compatible "IE=8"  
  3.  
  4. Meta:  
  5. <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" /> 

這種方法主要是防止老的頁面在較新的瀏覽器中顯示不正常的情況的, 比如上面的代碼可以強制IE8以上版本的瀏覽器以IE7的模式進行渲染。

注意,不要在新開發的網頁中使用這種技術,這種技術只應該作爲新老網頁更替過程中的過渡方案。由於目前新開發的網頁都是儘量支持最新版本的瀏覽器的,所以這種技術也會慢慢被淘汰,感興趣的同學可以詳細閱讀 微軟的這篇文檔。

小結:這裏我們需要知道有這種方式可以強制瀏覽器以某種模式運行,但只應作爲過渡方案,不應在新開發的網頁中使用。

IE9兼容性視圖與IE9標準視圖

如果你使用的是IE9,那麼按下F12鍵就會出現開發者工具,上面有兩個下拉菜單:瀏覽器模式和文檔模式。那麼什麼是瀏覽器模式?什麼又是文檔模式?二者有何區別?

瀏覽器模式用於切換IE針對該網頁的默認文檔模式、對不同版本瀏覽器的條件註釋解析、以及發送給網站服務器的用戶代理(User-Agent)字符串的值。網站可以根據瀏覽器返回的不同用戶代理字符串判斷瀏覽器的版本和及安裝的功能,這樣就可以根據不同的瀏覽器返回不同的頁面內容了。

文檔模式用於指定IE的頁面排版引擎(Trident)以哪個版本的方式來解析並渲染網頁代碼。切換文檔模式會導致網頁被刷新,但不會更改用戶代理字符串中的版本號,也不會從服務器重新下載網頁。切換瀏覽器模式的同時,瀏覽器也會自動切換到相應的文檔模式。

一言以蔽之,瀏覽器模式會影響服務器端對客戶端瀏覽器版本的判斷,對條件註釋也有影響;而文檔模式會影響IE的排版引擎,對網頁渲染會有影響,對CSS hack也會產生影響。因此,通過條件註釋可以判斷瀏覽器模式,而使用CSS hack可以判斷文檔模式。

如果我們使用一句簡單的JavaScript語句來查看用戶代理(User-Agent)字符串的值,則可以看到IE9兼容性視圖與IE9的區別:

  1. <script type="text/javascript"> 
  2. alert('UA:'+navigator.userAgent);  
  3. </script> 

輸出結果如下所示,注意其中的MSIE版本號已經不同。判斷瀏覽器模式就是判斷User-Agent中的版本號,即MSIE後面的數值:

  1. // IE9  
  2. UA:Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Tablet PC 2.0)  
  3.  
  4. // IE9 兼容性視圖  
  5. UA:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Trident/5.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Tablet PC 2.0) 

話說IE9兼容性視圖是模擬IE7的行爲,那麼IE9兼容性視圖與IE7有沒有區別呢?肯定是有區別的,即使是IE9中的IE7標準模式,與原生的IE7在渲染上也是有區別的,具體我們暫不去深究。

那麼既然IE9兼容性視圖的版本號跟IE7相同,如何才能判斷當前是IE9兼容性視圖,還是純正的IE7呢?其實很簡單,只需要判斷瀏覽器的用戶代理(User-Agent)字符串中是否包含Trident即可。首先檢測MSIE的版本號是否爲7.0,然後再判斷是否含有Trident字串,若包含則爲IE9兼容性視圖,否則則爲純正的IE7。

小結:至此,你應該瞭解了什麼是瀏覽器模式、什麼是文檔模式以及它們之間的區別了,另外還了解了IE9兼容性視圖與IE9以及IE7的區別。

控制默認的渲染方式

當Internet Explorer 9遇到未包含X-UA-Compatible標頭的網頁時,它將使用<!DOCTYPE>指令來確定如何顯示該網頁。 如果該指令丟失或未指定基於標準的文檔類型,則Internet Explorer 9將以IE5模式(怪異模式)來顯示該網頁。

如果<!DOCTYPE>指令指定了基於標準的文檔類型,則Internet Explorer 9將以IE9模式顯示該網頁,但出現以下情況時除外:

  • 爲該網頁啓用了兼容性視圖。
  • 該網頁是在Intranet區域中加載的,並且已將Internet Explorer 9配置爲使用兼容性視圖來顯示Intranet區域中的網頁。
  • 已將Internet Explorer 9配置爲使用兼容性視圖來顯示所有網站。
  • 已將Internet Explorer 9配置爲使用兼容性視圖列表(其實是個黑名單,其中指定了一組始終使用兼容性視圖顯示的網站)。
  • 已使用開發人員工具覆蓋在該網頁中指定的設置。
  • 該網頁遇到了頁面佈局錯誤,並且已將Internet Explorer 9配置爲,通過在兼容性視圖中重新打開網頁來自動從此類錯誤中恢復。

此外,可以使用下面的註冊表項來控制Internet Explorer對未包含X-UA-Compatible標頭的頁面的處理方式。

  1. HKEY_LOCAL_MACHINE (or HKEY_CURRENT_USER)  
  2. SOFTWARE  
  3. Microsoft  
  4. Internet Explorer  
  5. Main  
  6. FeatureControl  
  7. FEATURE_BROWSER_EMULATION  
  8. iexplore.exe = (DWORD) 

其中DWORD值必須等於下列值之一:

值    說明

7000 包含基於標準的 <!DOCTYPE> 指令的頁面將以 IE7 模式顯示。

8000 包含基於標準的 <!DOCTYPE> 指令的頁面以 IE8 模式顯示。

8888 頁面始終以 IE8 模式顯示,而不考慮 <!DOCTYPE> 指令。 (這可繞過前面列出的例外情況。)

關於IE瀏覽器確定文檔模式的整個流程,可以參看這篇文章How IE8 Determines Document Mode,文中詳細闡述了整個流程與內部機制。

小結:仍然堅持使用<!DOCTYPE html>,可最大程度減小發生錯誤的機率。

文檔模式的檢測

在JavaScript中可以通過documentMode來檢測文檔模式,在IE6和IE7中是使用compatMode來確定文檔模式的,這個屬性自IE8開始已經被documentMode所替代。

那麼,如果需要兼容IE6和IE7的話(必須的 ...),則相應的檢測代碼大致如下:

  1. engine = null;  
  2. if (window.navigator.appName == "Microsoft Internet Explorer")  
  3. {  
  4. // This is an IE browser. What mode is the engine in?  
  5. if (document.documentMode) // IE8 or later  
  6. engine = document.documentMode;  
  7. else // IE 5-7  
  8. {  
  9. engine = 5; // Assume quirks mode unless proven otherwise  
  10. if (document.compatMode)  
  11. {  
  12. if (document.compatMode == "CSS1Compat")  
  13. engine = 7; // standards mode  
  14. }  
  15. // There is no test for IE6 standards mode because that mode  
  16. // was replaced by IE7 standards mode; there is no emulation.  
  17. }  
  18. // the engine variable now contains the document compatibility mode.  

IE6和IE7中的compatMode有兩個可能的值“CSS1Compat”和“BackCompat ”,分別對應了IE6和IE7中的標準模式和怪異模式。上面的代碼首先假定是怪異模式,然後再試圖推翻假設。這裏沒有包含“IE6 標準模式”,因爲它已經被IE7標準模式所替代,沒有模擬的情況。

這裏要注意,不同的文檔模式對JavaScript也有一些影響,我們不必去深究不同文檔模式對JavaScript有何種不同影響,只需要在編碼時進行特定的特性檢測即可。

小結:一般情況下是沒必要進行文檔模式檢測的,對於樣式兼容我們可以寫CSS hack,而對於JavaScript來說,則更加推薦特性檢測,而不是檢測瀏覽器本身。

瀏覽器模式與文檔模式之間的關係

瀏覽器模式可以決定頁面默認的文檔模式,但文檔模式可能會受其他因素影響而改變,如上文所述。如果瀏覽器模式與文檔模式設置不同的話,會不會有什麼影響呢?

我們已經知道瀏覽器模式主要用於標識瀏覽器本身,原則上不會對頁面渲染產生影響。但是我們又知道,瀏覽器模式可以影響條件註釋,所以如果你的頁面中有條件註釋的話,那麼瀏覽器模式的變化就會影響到頁面渲染。

服務器端只能通過瀏覽器模式所標識的版本來確定客戶端瀏覽器的版本,如果你將瀏覽器模式標識爲IE9,但文檔模式選擇爲IE7標準的話,就可能會有問題。不過這還要看服務器端是否有針對不同瀏覽器的處理策略,如果服務器端並未對不同瀏覽器的輸出做差異化處理的話,那麼這兩個模式選項不同就不會有問題。

小結:如果服務器端對不同瀏覽器的輸出做了差異化處理,那麼瀏覽器模式和文檔模式不一致就可能產生問題。

結語

本文參考了大量現有文獻,詳細闡述了各種模式的區別以及它們之間的關係。相信通過上面的敘述,你已經能夠區分這些瀏覽器模式或者文檔模式以及它們之間的關係了,每節的結論在小結中已有闡述,希望能夠對你有所幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章