一、前言
從IE8開始引入了文檔兼容模式的概念,作為開發人員的我們可以在開發人員工具中通過“瀏覽器模式”和“文檔模式”(IE11開始改為“瀏覽器模式”改成更貼切的“用戶代理字符串”)品味一番,它的出現極大地方便了苦逼的前端攻城獅們適配各版本的IE,但jser們也不能完全信任它,因為它只是提供盡可能的文檔模式模擬而已。
本篇大部分內容來源於官方解說:http://msdn.microsoft.com/library/cc288325(v=vs.85).aspx,並盡量融入個人平常工作中踩過的坑加以闡述。
注意:本文內容僅針對HTTP頭Content-Type字段為text/html的html文檔作說明,而XML文檔不在本文的討論范圍之內。
二、什么是瀏覽器模式?
初看“瀏覽器模式”確實不明白啥意思,也許IE的工程師們也了解這詞的蹩腳,於是IE11索性就改名為“用戶代理字符串”。現在大伙應該清楚這貨就是用來設置navigator.userAgent和navigator.appVersion的。
它唯一需要注意的是,在不同的IE版本中,它與文檔模式的關系可不相同。
IE89中,倘若瀏覽器模式被設置為Internet Explorer7,那么文檔模式的只能設置為7,6,5;
IE11中,用戶代理字符串設置和文檔模式可謂是沒有半毛錢關系。
三、什么是文檔模式?
對於以Webkit、Molliza等作為內核的瀏覽器來說,DOM樹的解析、渲染,JS的API等主要與內核版本掛鈎;而對於IE瀏覽器而言,這些從IE6開始就跟文檔模式掛鈎了。為了更好的理解文檔模式,我們以時間為線從IE5.5開始學習吧!
3.1. 從“久遠”的IE5.5說起
現在雖然沒什么用使用IE5.5了,但它卻從未離開過我們,因為IE5.5一直以怪異模式(Quirks,IE5的文檔模式)的形式存活在我們的身邊。不過在那個只有IE5.5的年代,並沒有Quirks這一說法,只是后來IE6面世后逐漸向W3C標准靠攏,而IE5.5下DOM樹的解析、渲染等都與W3C標准有很大差別,於是命其名為Quirks。
3.2. 兼容模式——IE6的新發明
由於IE6和IE5.5下DOM樹的解析等都有很大差異,導致那些適配IE5.5的老網站無法在IE6上正常顯示,於是出現了一個新功能——“兼容模式”,用於解決老網站的顯示問題。IE6的兼容模式就兩種,怪異模式(Quirks)和IE6標准模式。(IE7也只有怪異模式和IE7標准模式)
IE6默認使用怪異模式(Quirks),僅當以<!DOCTYPE>作為文檔第一行聲明文檔類型時,才采用IE6的標准模式,即使IE無法識別所聲明的文檔類型。(IE7也是這樣)
注意:這時的兼容模式主要是解決顯示問題,要知道那時的JS只是小配角而已。
3.3. 文檔兼容性模式——IE8的新寵
“文檔兼容性模式”是對“兼容模式”的擴展,就IE8而言,除了提供怪異模式(Quirks)和IE8標准模式外,還提供了IE7標准模式、模擬IE7模式,而且設置的方式也豐富得多。
四、文檔模式的種類
1. 怪異模式
IE6789的是IE5.5的文檔模式,IE10+和Chrome等瀏覽器是W3C規范的怪異模式。
2. 標准模式(非怪異模式)
W3C標准的文檔模式,但各瀏覽器的實現階段不盡相同。
3. 准標准模式(有限怪異模式)
由於該模式離W3C標准仍然有一段距離,因此被稱作准標准模式(或有限怪異模式)。IE6、7的標准模式實際上就是准標准模式,而IE8+才有實質上的標准模式。但到底兩者的不同點體驗在哪里,本人暫時不了解,請各位指導!
五、IE8+設置文檔模式的方式
開發者常用的方式:
1. 開發者工具中的“文檔模式”;
2. 通過在head標簽內加入如<meta http-equiv="X-UA-Compatible" content="IE=7">的元數據標簽(該例子將文檔模式設置為IE7標准模式);
3. 通過<!DOCTYPE>的增刪,在標准模式和怪異模式(Quirks)間切換;
4. 通過Web服務器配置(讓http response header 帶上 X-UA-Compatible: IE=edge)
IIS的web.config配置信息:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.webServer> <httpProtocol> <customHeaders> <clear /> <add name="X-UA-Compatible" value="IE=EmulateIE7" /> </customHeaders> </httpProtocol> </system.webServer> </configuration>
用戶常用的方式:
1. 點擊地址欄的兼容性視圖切換按鈕(僅當HTTP、HTTPS協議時才出現該按鈕);
2. 若網頁是在Intranet區域中加載,配置使用兼容性視圖顯示Intranet區域中的網頁;
3. 配置瀏覽器使用兼容視圖瀏覽所有網頁;
4. 將網站加入到兼容性視圖名單中;
5. 內網管理員將該網站加入到兼容性視圖瀏覽名單中;
微軟的方式:
1. IE會定期向微軟官網拉數據,假如某網站被列入微軟的兼容性視圖瀏覽名單中,那么就會IE就會以兼容性視圖模式來處理該網站。
因此我們可以明白到文檔模式不是完全掌控在我們手中的,哎。。。。。。
2017/03/29,由於<meta http-equiv="X-UA-Compatible" content="IE=edge">不一定很生效,因為當端口不是80時,IE默認設置是將其視為內網應用(intranet site),並采用兼容模式來顯示(display intranet site in compatibility view)。因此最好采用HTTP Response Header的方式。
六、<meta http-equiv="X-UA-Compatible">與<!DOCTYPE>結伴影響文檔模式
所有IE瀏覽器在默認情況下(<meta http-equiv="X-UA-Compatible">與<!DOCTYPE>均沒有),是采用怪異模式(Quirks);當有<!DOCTYPE>時,均采用瀏覽器版本對應的標准模式(如IE8就采用IE8標准模式,IE11就采用IE11標准模式)。
現在要注意的是,當出現<meta http-equiv="X-UA-Compatible">時,文檔模式將會如何呢?我們首先了解一下IE11下它的content屬性值范圍吧,具體范圍如下:
IE=5、IE=7、IE=EmulateIE7、IE=8、IE=EmulateIE8、IE=9、IE=10、 IE=11、 IE=Edge
1. IE=5:表示采用怪異模式;
2. IE=7等純數字的值:表示采用對應IE版本的標准模式,即使不是以<!DOCTYPE>作為文檔第一行,文檔模式依舊使用標准模式;
3. IE=EmulateIE7等含EmulateIE字符串的值:表示采用模擬對應IE版本的模式,就是以<!DOCTYPE>作為文檔第一行則采用標准模式,否則采用怪異模式。
4. IE=Edge:表示采用瀏覽器自身版本的文檔模式,如IE11,以<!DOCTYPE html>作為文檔第一行則采用IE11標准模式,否則采用怪異模式。
注意:
1. 在IE11中,IE=10和IE=EmulateIE10是一樣的,IE=11、IE=EmulateIE11和IE=Edge是一樣的;
2017/03/29,由於document compatibility mode僅在IE8/9/10生效,因此在IE11時設置<meta http-equiv="X-UA-Compatible">是無效的,只有在開發工具中設置才有效果。
若要在IE11下采用舊版本的文檔模式,則要采用Enterprise Mode(https://blogs.msdn.microsoft.com/ie/2014/04/02/stay-up-to-date-with-enterprise-mode-for-internet-explorer-11/)
2. 10及以上的文檔模式,若文檔第一行不是有效的<!DOCTYPE>(怎樣才是有效的<!DOCTYPE>,請期待《JS魔法堂:doctype我們應該了解的基礎知識》),則document.compatMode返回BackCompat,但document.documentMode卻返回正確的文檔模式;
3. 9及以下的文檔模式,只要文檔第一行出現<!DOCTYPE>,不管是否有效,document.compatMode均返回CSS1Compat。當文檔第一行沒有<!DOCTYPE>且沒有指定標准模式時,document.compatMode才返回BackCompat,且document.documentMode必定返回5。
七、對<meta http-equiv="X-UA-Compatible">了解多一點
6.1. 有效位置
必須放在head標簽內才有效。
6.2. 多個標簽時只認第一個
<html> <head> <meta http-equiv="X-UA-Compatible" content="IE=7"> <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7"> </head> <body></body> <script type="text/javascript"> console.log(document.documentMode); // 輸出 7 </script> </html>
6.3. 無效content值,就設置為最接近的文檔模式
IE=a:文檔模式為5
IE=7.5:文檔模式7
6.4. 一個標簽設置多個文檔模式,瀏覽器會自動選擇可用的最高的文檔模式
<html> <head> <meta http-equiv="X-UA-Compatible" content="IE=7;IE=9;IE=8"> </head> <body></body> <script type="text/javascript"> console.log(document.documentMode); // IE11中,輸出 9 </script> </html>
八、不一樣的標准模式
雖然說IE6、7、8、9、10、11均有標准模式,但由於W3C標准規范內容隨時間的增改,而且瀏覽器對標准的實現是階段性的,因此個版本的標准模式不盡相同。
九、不一樣的怪異模式
IE6789的怪異模式其實就是IE5.5的文檔模式,但從IE10開始它的遵守了W3C規范的怪異模式。所以大家不要被名字而蒙騙咯!
舉個栗子:
<html>
<head>
<style type="text/css">
#target{
width: 100px;
height: 20px;
border: solid 1px red;
margin: 0 auto; } </style> </head> <body> <div id="target"><div> </body> </html>
上面的代碼在是運行在怪異模式下,在IE6789下若要div#target自動水平居中,必須加上<!DOCTYPE html>轉成用標准模式渲染才行。但在IE10+、Webkit和Molliza中即使在怪異模式下div#target也會自動水平居中。
十、文檔模式影響到哪些方面
1. 布局
表格、單元格的樣式等都受到文檔模式的影響,尤其是盒子模型。
2. 解析
css和html的解析也會受到文檔模式的影響,就像在IE678標准模式時,HTML解析時會將嵌套form下的子節點挪到上一節;而IE9標准模式時不會。
3. 腳本
這個我想不用多說大家也深有體驗了。
十一、Jser別太開心
初次發現IE8+提供文檔兼容性模式時真的欣喜若狂,終於不用找機器來IE678逐個測試了,終於不用那個經常掛死的IETester了。但后來才發現文檔兼容性模式僅僅是方便我們開發調試而已,並不能完全替代IETester,更不能替代在真實的IE67上測試。因為除了瀏覽器版本對應的文檔模式外,其他文檔模式均是跑在瀏覽器內核虛擬機上,而這些虛擬機僅僅能模擬真實瀏覽器內核的大部分DOM樹解析、渲染和JS API而已。例如在IE8上設定文檔模式為怪異模式,但XMLHttpRequest依舊可用(XMLHttpRequest是從IE7開始才有的),因此在檢測瀏覽器特性的時候,特征嗅探比判斷瀏覽器的文檔模式更為准確、好用。
另外,從第六大點的注意事項中我們可以看到,從IE10開始IE要脫離IE56789的風格,真正靠近W3C標准。
1. 沒有有效的doctype時盒子模型的渲染模式就是怪異模式,否則就使用標准模式;
2. 盒子模型的渲染模式和文檔模式分離,也就是渲染模式為怪異模式時,文檔模式不是5。這樣Jser還是使用IE10+的JS API,不用忍受IE5之苦;
3. 雖然在document.compatMode為BackCompat時,渲染模式都叫怪異模式,但IE56789的怪異模式和IE10+的怪異模式所顯示的效果和通過JS獲取的樣式數據都不同,IE10+的與Webkit、Molliza的效果相近。
十二、總結
從“瀏覽器模式”與“文檔模式”關聯,“文檔模式”與“盒子模型的渲染模式”掛鈎,到IE10+一下子將三者關聯切斷,轉向W3C標准。一直覺得IE9是IE非標准與標准間的過渡帶,現在就更加認定是這樣了。
也許大家看到這里會更加疑惑,似乎了解上述內容會加重開發的負擔(考慮的點更多了)。
其實我們只要再次明確一下“文檔兼容性模式”的目的就好了,對終端用戶來講它是為了在新版IE中盡量正確地顯示老網站;對開發者來講它是為了方便調試新網站在舊版IE上的顯示效果和JS的有效性,極端情況下會通過鎖定文檔模式來啟用舊技術(如ie67下的vml)。
所以作為普通開發者的我們只需做三件事:
1. 以有效的doctype作為文檔的第一行,保證渲染模式為標准模式;
2. 開發前設定網站的最佳運行環境范圍,就是需適配的IE版本號,是否適配Webkit等;
3. 開發並使用各種hacks為兼容性付出不懈的努力。
另外我曾參與一個項目需要運用VML來畫圖,客戶大部分使用IE678,少部分使用IE910,其他瀏覽器的可忽略不計,於是就可以通過鎖定文檔模式為模擬IE7標准模式來啟用VML支持了。(官方聲IE9+不支持VML,但實際上IE8已經不支持了。)
若作為庫或框架開發者,由於文檔模式影響大部分JS API,而渲染模式影響各項樣式值和獲取方式等等,情況會復雜得多。因此綜合文檔模式判斷、特征嗅探、渲染模式判斷是必須的,上述內容只是挖坑而已。
尊重原創,轉載請注明轉自:http://www.cnblogs.com/fsjohnhuang/p/3817418.html ^_^肥仔John