关于浏览器模式和文本模式的困惑

て烟熏妆下的殇ゞ 提交于 2019-12-02 23:01:12

什么是浏览器模式和文本模式?

经常使用IE开发者工具的同学,肯定见过浏览器模式和文本模式,对于这两个名词,综合相关文档解释如下:

浏览器模式(Browser Mode),用于切换IE针对该网页的默认文本模式、对不同版本浏览器的条件注释解析、决定请求头里userAgent的值。它在浏览器发出请求之前就已经确定,网站没有办法修改这个值。它代表的是用户以何种浏览器访问网站。IE9支持下列浏览器模式:

  userAgent 默认文本模式
IE7 MSIE 7.0 IE7标准
IE8 MSIE 8.0 && Trident/4.0 IE8标准
IE9 MSIE 9.0 && Trident/5.0 IE9标准
IE9兼容性 MSIE 7.0 && Trident/5.0 IE7标准

IE9兼容性模式与IE7模式的区别是:前者在UA里加上了Trident版本,后者和IE7完全一致无Trident标识;IE8中,IE9兼容性模式对应为IE8兼容性模式,UA里Trident版本为4.0,其他没变化。另,IE8中没有IE9模式

文本模式(Document Mode),其实就是经常说的文档模式。不同的文本模式对应不同的排版引擎,不同的JS引擎。上面提到,每一种浏览器模式对应一种默认的文本模式,网站还可以通过一些手段来更改文本模式,它代表的是浏览器以何种模式呈现页面。IE9有下列文本模式:

  documentMode
IE7标准 7
IE8标准 8
IE9标准 9
怪异(Quirks) 5

(需要说明的是,IE8开始支持的渲染机制有:怪异模式(quirks mode)、完全标准模式(standards mode)和近似标准模式(almost standards mode),但开发者工具是无法选择近似标准模式的,实际上我们一般都选择触发完全标准模式)

浏览器模式和文本模式有什么用?

用来解决IE各版本带来的兼容性问题。根据微软描述的IE兼容性策略,在IE8+访问一个页面要经过这样的流程:

一、首先,浏览器要确定浏览器模式。上面说过,浏览器模式是在请求发送之前就必须确定,默认取最新(IE9为IE9标准,IE8为IE8标准),有两种方式可以更改它:

  • 通过开发者工具选择(可选项见上表);
  • 通过点击兼容性视图按钮;
  • 命中兼容性视图列表(微软维护的需要采用兼容性视图的列表。IE8+默认对这个列表和局域网的网址都会采用相应的兼容性模式);

二、浏览器通过请求头里userAgent的值,告诉服务器当前是何种浏览器模式;

三、服务器可以通过下面方式改变浏览器文本模式:

  • doctype;
  • X-UA-Compatible Meta或对应的响应头;

四、浏览器综合考虑开发者工具设置、第三步服务器返回的设置、兼容性列表设置等等情况,决定页面使用何种文本模式。这个过程有点复杂,放一张Qwrap群里灰大提供的流程图,可以自己点开看大图。

(上图是IE9选取文本模式的流程图,这里还有IE8版本,有一些区别)

问题终于来了!

回顾下前面的介绍,浏览器模式决定:1)发送给服务端的UA;2)默认的文本模式;3)如何解析条件注释。它在请求发送前就已经确定,且不受服务端控制。文本模式决定:1)排版引擎;2)JS引擎。它在浏览器得到响应后最终确定,服务端可通过doctype或X-UA-Compatible来控制。

测试一、根据前文,如果用户浏览器没有激活兼容性视图;没有开启IE开发者工具。那么IE9的浏览器模式默认为IE9,默认对应的文本模式应该是IE9标准(对于IE8来说,是类似的),我们通过下列代码将它改到IE7标准

<meta http-equiv="X-UA-Compatible" content="IE=7">

下面,我们分别用原生IE8、IE9测试这个页面

  请求头UA navigator.userAgent 条件注释 documentMode JS引擎
IE8 MSIE 8.0 && Trident/4.0
MSIE 8.0 && Trident/4.0 IE7 7 IE7
IE9 MSIE 9.0 && Trident/5.0 MSIE 7.0 && Trident/5.0 IE7 7 IE7

上表说明,浏览器发送请求时的浏览器模式符合预期(根据请求头UA),X-UA-Compatible确实会将浏览器文本模式改到了IE7标准(根据documentMode和JS引擎)。奇怪的是,文本模式的改变导致了浏览器模式的改变,因为条件注释是由浏览器模式决定的。本例中,文本模式改到IE7标准,条件注释也跟着变成IE7,意味着浏览器模式变到IE9/IE8兼容性(从IE9的测试来看,不能是IE7,因为UA里包含Trident)。至于IE8中JS取到的UA为什么没有变化,可能是bug或者理解不一致。

测试二、那如果把测试地址加到兼容性列表呢?根据前文,这种情况浏览器模式应该是IE9/IE8兼容性,对应的文本模式依然是IE7标准。测试结果如下:

  请求头UA navigator.userAgent 条件注释 documentMode JS引擎
IE8 MSIE 7.0 && Trident/4.0 MSIE 7.0 && Trident/4.0 IE7 7 IE7
IE9 MSIE 7.0 && Trident/5.0 MSIE 7.0 && Trident/5.0 IE7 7 IE7

上表是完全符合预期的。

测试三、如果把X-UA-Compatible改成IE=edge,继续使用兼容性模式测试呢?结论如下:

  请求头UA navigator.userAgent 条件注释 documentMode JS引擎
IE8 MSIE 7.0 && Trident/4.0
MSIE 7.0 && Trident/4.0 IE8 8
IE8
IE9 MSIE 7.0 && Trident/5.0 MSIE 9.0 && Trident/5.0
IE9 9
IE9

这个结论其实跟测试一是一致的:X-UA-Compatible为IE=edge,意味着文本模式会使用最新可用的版本,然而文本模式的更改,又把浏览器模式从IE9/IE8兼容性变成IE9/IE8。IE9会按照新的浏览器模式来设置JS的navigator.userAgent,IE8下JS的UA不变。

测试四、那如果通过开发者工具人为设置浏览器模式和文本模式呢?经过测试,这样测试都是符合预期的。例如IE9下,设置浏览器模式为IE8,文本模式为IE7标准,请求头UA、JS的UA、条件注释都表明浏览器模式是IE8,documentMode和JS引擎都表明文本模式是IE7标准。因为,IE开发者工具的优先级最高,设置了这个,其他条件统统无视!

结论

IE8/9中X-UA-Compatible对文本模式的改变会导致浏览器模式的改变,也就是说服务端可以间接控制浏览器模式。这与微软文档里这一段描述有出入:

An important detail to remember is that Browser Mode is chosen before IE requests web content. This means that sites cannot choose a Browser Mode.

对于IE8,如果网站通过X-UA-Compatible meta/header更改文本模式为当前浏览器模式默认文本模式之外的值,那么页面将按照新的文本模式来呈现,条件注释也按照新的文本模式对应的浏览器模式来解析,但是JS获取的UA是浏览器模式初始状态。这样会导致用JS获取UA得到的浏览器版本,与实际渲染的浏览器版本不符,这会对基于UA的浏览器检测造成干扰。

对于IE9,只有一点与IE8不同:JS获取到的是新文本模式对应的浏览器模式的UA。这会导致用JS获取UA得到的浏览器版本,与请求头发送给服务器UA里标识的浏览器版本不符,这可能对统计有影响。

对于IE这种兼容性方案,几乎不可能做到理论上的完美。个人感觉还是IE9的策略影响面较小,更好一些。

PS,上述结论都是我用Windows XP的原生IE8,Windows 7的原生IE9亲自测试得出来的。对于国内那些IE Shell们,实在过于奇葩,不在本文范围内。

参考:

  1. Testing sites with Browser Mode vs. Doc Mode
  2. X-UA-Compatible header/meta tag is NOT the same as the Internet Explorer 8+ Compatibility View button
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!