为了处理根据web标准创作的网页和根据在20世纪90年代末流行的陈旧实践创作的网页,现代的web浏览器实现了各种不同的引擎模式。本文说明了那些模式是什么以及如何触发它们。
本文包括的模式转换(mode switching)适用于firefox和其他基于gecko的浏览器,safari、chrome和其他基于webkit的浏览器,opera、 konqueror、mac版internet explorer、windows版internet explorer和内嵌ie的浏览器。避免提及浏览器引擎的名字,取而代之的是使用该引擎最知名浏览器的名字。
本文着重介绍模式的选择机制,而不是记录每个模式的确切行为。
以下是各种不同的模式:
text/html内容的模式选择取决于doctype嗅探(doctype sniffing,本文后面有讨论)。在ie8中,模式也取决于其他因素。然而在ie8的默认情况下,那些不在微软提供黑名单上的非局域网(non- intranet)站点的模式取决于文档类型。
再怎么强调每个浏览器中模式精确行为的不同也是不过分的,即使本文中进行了统一的讨论。
firefox、safari、chrome和opera中,application/xhtml+xml http内容类型(不是meta元素也不是doctype!)会触发xml模式。在xml模式中,浏览器尝试给xml文档在规范上的正确处理达到在制定浏览器中的程度。
ie6、7和8不支持application/xhtml+xml,mac ie5也如此。
基于webkit的nokia s60 浏览器中,application/xhtml+xml http内容类型不能触发xml模式,因为在移动的围墙花园(mobile walled gardens)中关注点是对不规范内容的兼容性。(旧式的“移动浏览器”无法使用真正的xml解析器,因为不规范内容已被标记为xml。)
由于没有充分地测试konqueror,我无法确切说出在这个浏览器中会发生什么。
某些引擎拥有的模式与web内容无关。为了完整性,它们仅仅在这里被提到。opera有个wml2.0模式。leopard上的webkit有个用于旧式dashboard widgets的特定模式。
以下是这些模式的主要影响:
text/html的模式主要是影响css布局。例如,表格不继承样式是个怪癖。在某些浏览器的怪癖模式下,盒模型(box model)变成ie5.5的盒模型。本文档没有列举出所有的布局怪癖。
准标准模式(有这种模式的浏览器中)中,仅包含图片的表格单元格的高和标准模式中不同。
xml模式中,选择器有不同的区分大小写行为。此外,用于html body元素的特有规则不能应用在那些没有实现最新css2.1改变的较旧版本的浏览器。
也有一些怪癖影响html和css的解析且会导致符合标准的网页被错误解析。怪癖布局决定了这些怪癖是否开启。无论如何,了解怪癖模式和标准模式在css布局和解析(非html解析)上的主要异同是非常重要的。
一些人错误地把标准模式称为“严格解析模式(strict parsing mode)”,其让人误解了浏览器强制执行html语法规则和用浏览器评估标记的正确性。情况并非如此。即使当标准模式布局生效时,浏览器依旧会做标签杂烩汤(tag soup,http://en.wikipedia.org/wiki/tag_soup)修正工作。(在2000年netscape6发布前,mozilla的确有用于强制执行html语法规则的解析模式。这些模式和现有的web内容不兼容而被遗弃。)
另一个常见的误解是关于xhtml解析的。通常认为用xhtml doctype得到不同的解析。其实并非如此,内容类型是text/html的xhtml文档所用解析器和html文档的是同一个。目前浏览器在意的是文档类型为text/html的xhtml仅是“撒面包丁的标签杂烩汤(tag soup with croutons)”(到处是额外的斜线)。
仅当使用xml文档类型的文档(例如:application/xhtml+xml或xmapplication/)会触发xml模式来解析,这时的解析器完全不同于html解析器。
虽然怪癖模式主要是关于css的,但也有一些是关于脚本的。例如,firefox的怪癖模式中,html id 属性像在ie一样建立了全局脚本作用域的对象引用。ie8中关于脚本的影响比其他浏览器更值得关注。
xml模式中,某些dom api的行为彻底不同,因为xml的dom api行为被定义时不兼容html的行为。
现代浏览器使用doctype嗅探来决定text/html文档的引擎模式。这意味着模式的选择是基于html文档开始的文档类型声明(或缺少)。(这不适于使用xml文档类型的文档。)
文档类型声明(doctype)是sgml的语法伪造,sgml是个旧式的标记框架,html5之前的html就是依据其定义的。html4.01规范中,文档类型声明描述的是html的版本信息。尽管名字叫“文档类型声明”且html 4.01规范所描述的是关于“版本信息”,文档类型声明并不适用把sgml或xml文档分类为特定类型的文档,即使它看起来像是(因为名字)。(更多内容在附录中)
html4.01规范和iso 8879(sgml)都没有说关于使用文档类型声明作为引擎模式转换的任何事情。doctype嗅探是基于观察,在doctype嗅探被设计时,绝大部分的怪癖文档既没有文档类型声明也没有引用旧的dtd。html5接受这个事实,且定义了text/html中doctype作为唯一的模式转换。
典型的预html5(pre-html5)文档类型声明包含(被空白分开)“<!doctype”字符串,根元素(“html”)的通用标识符, “public”字符串,处于引号中的dtd公共标识符,同一dtd的可能系统标识符(url)和字符 “>”。文档类型声明位于文档的根元素开始标签之前。
下面是创建新的text/html文档时如何选择doctype的简单指南:
我不推荐任何的xhtml doctype,因为xhtml被用作text/html被认为是有害的。无论如何,如果你选择使用xhtml doctype,请注意xml声明会使ie6(但不是ie7!)触发怪癖模式。
对application/xhtml+xml的简单指南是绝不使用doctype。该方式下的网页不是“严格一致”的xhmtl1.0,但这并不重要。(请看后面的附录)
a list apart 曾介绍 ,ie8除doctype外会使用基于meta元素的模式转换作为模式选择的因素之一。(请看ian hickson、david baron、david baron again、robert o’callahan 和 maciej stachowiak的评论。)
ie8有4种模式:ie5.5怪癖模式、ie7标准模式、ie8 准标准模式 和ie8标准模式。模式的选择取决于来自几个方面的数据:doctype、meta元素、http头、来自微软的定期下载数据、局域网域、用户所做设置、局域网管理员所做设置、父框架的模式(如果有)和地址栏兼容视图按钮被用户触发。(对于嵌入该引擎的其他应用,模式也取决于嵌入的应用。)
幸运的是如果出现下列情况,ie8大体上会像其他浏览器一样使用doctype嗅探:
上述除两个关于x-ua-compatible的情况外,ie8像ie7一样执行doctype嗅探。ie7仿真( ie7 emulation)叫兼容视图。
在 x-ua-compatible 情况下,ie8的行为和其他浏览器完全不同。想看本页的附录或pdf和png格式的流程图。
不幸的是,没有 x-ua-compatible的http头或meta标签,即使使用了合适的doctype,ie8让用户无意间使页面从ie8的标准模式降到ie7模式,这是一种仿真的ie7标准模式。更糟糕的是,局域网管理员也可以这么做。微软也可以把你所用的所有域名到列入黑名单。
为了对付这些影响,doctype是不够的,你需要x-ua-compatible http头和meta标签。
下面的简单指南是针对已经有doctype在其他浏览器触发标准模式或者准标准模式的新的text/html文档如何选择x-ua-compatible http头或meta标签的:
请不要把doctype嗅探带到xml。
doctype嗅探是用签杂烩汤似的方法解决一个标签杂烩汤问题。doctype嗅探是在html4和css2规范发布后设计的一种试探方法,它从文档中区分出过时文档以符合其作者可能期望的行为。
偶尔有人建议在xml上使用doctype嗅探来调度不同的处理、识别正在使用的词汇表或激活特性。这是个坏主意。调度和词汇表识别应该是基于名字空间的,而特性激活应该是基于明确的处理指令或元素。
良构(well-formedness)的整个思想是介绍允许xml的无dtd解析,且推广无doctype文档。在正式情况下,两个xml文档有相同的规范形式且应用不同地处理它们(且不同之处并非因为没有选择处理外部实体),这个应用或许被破坏了。在实践情况下,如果两个xml文档导致同样的内容被报告(qnames忽略)给sax2内容处理器且应用不同地处理文档,这个应用或者被破坏了。考虑到作为 web作者无法相信每个人都会使用解决额外实体的xmlprocessor来解析其页面(即使一些浏览器看起来这样做,因为它们会映射一定公共的标识符到一个有删节的定义实体的dtd),插入doctype到xml中用于web是毫无意义的且通常会导致货运崇拜(cargo cultish)习惯。(您仍然使用w3c验证器的dtd覆盖功能来对一个dtd进行验证,虽然w3c验证器会说结果仅仅是暂时有效。或更好的是,你可以用放宽ng验证,它不会污染模式引用的文档。)为了嗅探而要求doctype是非常愚蠢的,即使那是在html实践中的解决方法。
此外,当低级别的规范定义两个相等的东西时,高级别的规范不应该尝试给它们不同的含义。请考虑<!doctype html public "-//w3c//dtd xhtml 1.0 strict//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd">。如果删除公共标识符,依旧指定了同样的dtd,因此doctype <!doctype html system "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd">表示和前面的doctype一样。应该不同地嗅探它们么?可以进一步理论。假设复制给example.com一个叫foobar.dtd的dtd:<!doctype html system "http://example.com/foobar.dtd">。这该如何嗅探?应该是同一个意思。甚至整个dtd可以贴在文档中。
换句话说,如果有#include “foo.h”,你不应该给名字foo.h绑定任何black magic,因为它应该允许复制foo.h的内容到文档中或复制foo.h到bar.h中且表示#include “bar.h”。
我不担心html和sgml构造相同的参数的原因是web浏览器不会使用真正的sgml解析器去解析html,所以我认为伪装成sgml进行处理是没有用的。无论如何,如果你还不相信,请看w. eliot kimber关于此事的文章 comp.text.sgml
下表中,怪癖模式、标准模式和准标准分别表示为q、s和a。当浏览器仅有两种模式时,如果表格单元格的行高和mozilla的标准模式表现一致时,标准模式标记为“s”,如果表格单元格的行高和mozilla的准标准模式表现一致时,则标记为“a”。
请注意使用xml内容模型提供服务的xhtml在xml模式下渲染。
本表的目的并不是说表中所有的doctype都是新建页面的合理选择。本表的目的是为了展示我的推荐是依据什么样的数据。
下列的简写符号是用于列标题:
doctype | ns6 | old moz | moz & safari & opera10 & html5 | opera9.0 | ie8 & opera9.5 | ie7 & opera7.10 | ie6 & opera7.0 | mac ie5 | konq3.2 |
---|---|---|---|---|---|---|---|---|---|
none | q | q | q | q | q | q | q | q | q |
<!doctype html public "-//w3c//dtd html 3.2 final//en"> | q | q | q | q | q | q | q | q | q |
<!doctype html public "-//w3c//dtd html 4.0//en"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd html 4.01//en"> | s | s | s | s | s | a | a | q | a |
<!doctype html public "-//w3c//dtd html 4.0//en" "http://www.w3.org/tr/html4/strict.dtd"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd html 4.01//en" "http://www.w3.org/tr/html4/strict.dtd"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd html 4.0 transitional//en"> | q | q | q | q | q | q | q | q | q |
<!doctype html public "-//w3c//dtd html 4.01 transitional//en"> | q | q | q | q | q | q | q | q | q |
<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/html4/loose.dtd"> | s | s | a | a | a | a | a | a | q |
<!doctype html public "-//w3c//dtd html 4.01 transitional//en" "http://www.w3.org/tr/1999/rec-html401-19991224/loose.dtd">
| q | s | a | a | a | a | a | a | q |
<!doctype html public "-//w3c//dtd html 4.0 transitional//en" "http://www.w3.org/tr/html4/loose.dtd"> | q | q | q | q | a | a | a | a | q |
<!doctype html public "-//w3c//dtd xhtml 1.1//en" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd xhtml basic 1.0//en" "http://www.w3.org/tr/xhtml-basic/xhtml-basic10.dtd"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd xhtml 1.0 strict//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> | s | s | s | s | s | a | a | a | a |
<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd"> | s | s | a | a | a | a | a | a | q |
<?xml version="1.0" encoding="utf-8"?> <!doctype html public "-//w3c//dtd xhtml 1.1//en" "http://www.w3.org/tr/xhtml11/dtd/xhtml11.dtd"> | s | s | s | s | s | a | q | a | q |
<?xml version="1.0" encoding="utf-8"?> <!doctype html public "-//w3c//dtd xhtml basic 1.0//en" "http://www.w3.org/tr/xhtml-basic/xhtml-basic10.dtd"> | s | s | s | s | s | a | q | a | q |
<?xml version="1.0" encoding="utf-8"?> <!doctype html public "-//w3c//dtd xhtml 1.0 strict//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-strict.dtd"> | s | s | s | s | s | a | q | a | q |
<?xml version="1.0" encoding="utf-8"?> <!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/xhtml1/dtd/xhtml1-transitional.dtd">
| s | s | a | a | a | a | q | a | q |
<!doctype html public "iso/iec 15445:2000//dtd html//en"> | q | s | s | q | q | q | q | q | q |
<!doctype html public "iso/iec 15445:2000//dtd hypertext markup language//en"> | q | s | s | s | s | a | a | a | q |
<!doctype html public "iso/iec 15445:1999//dtd html//en"> | s | s | s | q | q | q | q | q | q |
<!doctype html public "iso/iec 15445:1999//dtd hypertext markup language//en"> | s | s | s | s | s | a | a | a | q |
<!doctype html> | q | s | s | s | s | a | a | a |
moziila的doctype嗅探代码在2000年10月、2001年9月和2002年6月有大幅度的修改。本文档描述的mozilla(和 netscape 6.x)建立的状态可以自2000.10.19起在ftp.mozilla.org上看到。本文档未涉及mozilla m18(和netscape 6.0 pr3)中的doctype嗅探的工作方式。safari的doctype嗅探代码自第一个公开的测试版起也有大幅度的修改。本文档不包括比版本v73也叫0.9更早的行为。
konqueror3.5之前的doctype嗅探代码似乎来自于safari的很早的一个版本。konqueror现在和safari匹配,其doctype嗅探代码来自mozilla。
从表中可见,opera的doctype嗅探正由规律的从类似ie向类似mozilla转变,虽然opera9.5和9.6在倒退的路上。同时,opera怪癖模式的布局行为已从仿效ie6的怪癖模式转换到mozilla的怪癖模式。
这些步骤都可以通过pdf和png格式的流程图看到。
感谢simon pieters、simon pieters和anne van kesteren帮助我改正了各种opera版本的模式表和他们的评论。感谢simon pieters制作了另一份ie8的流程图。
新闻热点
疑难解答