这些天一直在忙于TGuide(腾讯互娱重构编码规范)的编写,博客也因此停止更新了一段时间。当然在TGuide的编写过程中也会遇到各种各样的问题,就比如今天要讲的“元素嵌套”,这个问题在WEB标准群里得以和大家讨论,同时受到10胸(@顾轶灵)的指点,此问题才得以清晰地被解决。今天与大家一起来分享。后续将会推出web标准系列的文章,今天以“元素嵌套”来抛砖引玉。
先来看这样一段代码:
当然,我是不会告诉你这段代码来自于FACEBOOK的 ,各位认为以上元素的嵌套有没有问题呢?我们会在后面讨论这个。
在我们的印象中会有这样的嵌套规则:
内联元素不能嵌套块元素
元素和
元素不能嵌套块元素
详见 Jukka Korpela 的 Allowed nesting of elements in HTML 4 Strict (and XHTML 1.0 Strict) 。
那么到底什么是块元素,什么是内联元素?
以下是W3C CSS2.1规范中对块元素和内联元素的定义:
Block-level elements are those elements of the source document that are formatted visually as blocks (e.g., paragraphs). The following values of the ‘display’ property make an element block-level: ‘block’, ‘list-item’, and ‘table’.
Inline-level elements are those elements of the source document that do not form new blocks of content; the content is distributed in lines (e.g., emphasized pieces of text within a paragraph, inline images, etc.). The following values of the ‘display’ property make an element inline-level: ‘inline’, ‘inline-table’, and ‘inline-block’. Inline-level elements generate inline-level boxes, which are boxes that participate in an inline formatting context.
我们可以这样理解:块元素一般都从新行开始,内联元素在一行内显示,我们也可以通过CSS属性display的’inline’ 或 ‘ block’ 来改变元素为内联元素或块元素,当然这是CSS中对元素的分类,显然用 ‘display’ 的属性值来对html元素进行分类是不严谨的。
如果按照上述规则来讲,那么FACEBOOK的做法就是一种错误的做法,因为他在内联元素元素中嵌套了块元素元素
元素的嵌套规则和页面头部申明的DTD有着千丝万缕的关系,DTD基础请查看我之前写的文章《DTD详解》,那么在最新的HTML5规范中是否对元素嵌套有着新的规范呢?
让我们先了解下W3C在最新的HTML5规范中对元素的分类方式:
如上图,元素的分类不再是块元素或内联元素这样来分类(其实从来就没有这样分),而是按照如下分类来分:Flow(流式元素)、Heading(标题元素)、Sectioning(章节元素)、Phrasing(段落元素)、Embedded(嵌入元素)、Interactive(交互元素)、Metadata(元数据元素)。
在应用程序和文档的主体部分中使用的大部分元素都被分类为流式元素。
a, abbr, address, area(如果它是map元素的后裔), article, aside, audio, b, bdi, bdo, blockquote, br, button, canvas, cite, code, command, datalist, del, details, dfn, div, dl,em, embed, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup, hr, i, iframe, img, input, ins, kbd, keygen, label, map, mark, math, menu, meter,nav, noscript, object, ol, output, p, pre, progress, q, ruby, s, samp, script, section, select, small, span, strong, style(如果该元素设置了scoped属性), sub, sup, svg, table,textarea, time, u, ul, var, video, wbr, text
标题式元素定义一个区块/章节(section)(无论是明确的使用章节式内容的元素标记,或者标题式内容自身所隐含的)的标题。
h1, h2, h3, h4, h5, h6, hgroup
章节式元素是用于定义标题及页脚范围的元素。
article, aside, nav, section
段落式元素是文档中的文本、标记段落级文本的元素。
a(如果其只包含段落式元素), abbr, area(如果它是map元素的后裔), audio, b, bdi, bdo, br, button, canvas, cite, code, command, datalist, del(如果其只包含段落式元素), dfn, em, embed, i,iframe, img, input, ins(如果其只包含段落式元素), kbd, keygen, label, map(如果其只包含段落式元素), mark, math, meter, noscript, object, output, progress, q, ruby, s, samp, script,select, small, span, strong, sub, sup, svg, textarea, time, u, var, video, wbr, text
嵌入式元素是引用或插入到文档中其他资源的元素。
audio, canvas, embed, iframe, img, math, object, svg, video
交互式元素是专门用于与用户交互的元素。
a, audio(如果设置了controls属性), button, details, embed, iframe, img(如果设置了usemap属性), input(如果type属性不为hidden状态), keygen, label, menu(如果type属性为toolbar状态),object(如果设置了usemap属性), select, textarea, video(如果设置了controls属性)
元数据元素是可以被用于说明其他内容的表现或行为,或者在当前文档和其他文档之间建立联系的元素
base,command,link,meta,noscript,script,style,title
各分类会有交叉或重叠的现象,这说明在html5中,元素可能属于上述所有分类中的一个或多个。
其中的「Categories」说明该元素的类别,「Contexts in which this element can be used」说明该元素能在何种场景下被使用,也就是它的父元素是什么,「Content model」说明该元素可以包含的内容是什么,由于页面中的元素是层层嵌套的,一个元素有可能既是父元素同时也是子元素的角色,所以下面我们以「Content model」也就是可包含的子元素做讨论。
那么对于h1~h6元素:
对于
但对于
、
、
对于元素:
这样看元素还是挺有意思的,允许的子元素要看它的父元素所能包含的子元素。
这时的父元素为,对于
让我们来把代码做一下修改:
这时的父元素为
上面讲了HTML5对元素新的分类方式和以
内容
测试结果:
元素嵌套
内容
测试结果:
测试结果:
内容
测试结果:
内容
测试结果:
通过上述栗子,我们总结如下:
元素内嵌入
其实,这里说解析错误并不是很合理,应该是说浏览器解析出来的结果和我们期望的结果不一致,但任何的嵌套错误都不会导致页面呈现有很大的出错。
我们知道JS代码如果写的有语法错误,浏览器的JS解释器就会拒绝执行并且报错,而浏览器在遇到不符合语法规定的HTML代码时则会千方百计将其呈现出来。
通过上面的示例我们发现在
元素里嵌套
严格嵌套约束规则:
里面不可以嵌套
、
语义嵌套约束:
每个元素基本都有自己的嵌套规则(即父元素可以是什么,子元素可以是什么),除了严格嵌套约束之外的一些规则就是语义嵌套约束,对于语义嵌套约束,如果不遵守,页面可能正常,但也可能解析错误,这和下面要讲的容错机制有关。
并不是每位同学在写完页面后去做合法性检查,因此浏览器厂商不得不让它们的浏览器以尽可能宽松的方式去处理网页,每个浏览器内核中都有相当一部分代码专门用来处理那些含糊不清的html标记及嵌套,并且会去猜测前端们到底想如何呈现网页,这是浏览器的容错机制。
这其实在告诉我们,我们写出来的HTML代码不符合W3C规范可能最终呈现出来没有异样,但那其实是浏览器的一种容错机制,我们没有理由让自己以一个随性的态度去coding,对待自己的代码应该一丝不苟,即使HTML5的胸襟很宽广。
原本我们认为从HTML4到XHTML是一个时代,现在又从XHTML跨到了HTML5,新时代新标准的诞生,我们应该敞开胸怀去拥抱,而不是排斥。
你关注或不关注,标准就在那里,只增不减。我们应该感谢W3C这样一个组织,让各个浏览器厂商抛开彼此的敌意共同制定新的标准。不然,也许你会像90年代那样,JS引用一个元素都需要为某个浏览器写一套自己的代码。
WEB标准只会使我们吃饭变得更香,睡眠变得更好,新的技术或标准会推动我们去富有热情的coding,而不是每天在重复劳动。
补充一些标准的常用链接:
W3C国际站:http://www.w3.org/
W3C中国:http://www.chinaw3c.org/
W3C HTML5:http://www.w3.org/TR/html5/
W3C CSS21:http://www.w3.org/TR/CSS21/
W3C标准聚合:http://www.w3.org/TR/
whatwg: http://www.whatwg.org/specs/web-apps/current-work/multipage/
csswg:http://dev.w3.org/csswg/