过去的一年,围绕是否使用新的HTML5语义元素的争论已演变成如何使用新的HTML5语义元素。今年结束前(很多是在本季度结束前)所有主流浏览器都已正式声明支持这些元素,所以是时候开始使用这些元素了。当然,在浏览器的世界里并不是所有的浏览器都支持HTML5,所以如何写出向后兼容的代码就成了一个需要回答的主要问题。
问题
最大的问题就是当使用这些新的语义元素时,那些不支持的浏览器如何处理这些元素。在一个页面中使用HTML5元素主要有三种可能的结果。
- 标签被当做一个错误,并且被完全忽略。构建DOM结构时就像这些标签不存在一样。
- 标签被当做一个错误,并且生成一个作为占位符的DOM节点。就像代码所表示的那样构建DOM,但是标签上没有应用样式(被视为一个内联元素)。
- 标签被当做HTML5的标签,并且生成正确的DOM节点。就像代码所表示的那样构建DOM,并且标签上也应用了合适的样式(许多情况下,被视为一个块级元素)。
下面来看一个具体的例子,考虑下面的代码:
<div class="outer">
<section>
<h1>title</h1>
<p>text</p>
</section>
</div>
很多浏览器(比如Firefox3.6、Safari4)会这样解析这段代码:<div>
作为一个顶级元素,<div>
下有一个不认识的子元素(<section>
),虽然不认识但是<section>
被当做一个内联元素构建在DOM中。<h1>
和<p>
是<section>
的两个子元素。由于<section>
在DOM结构中,所以可以在节点上应用样式。这是第二种情况#2。
IE9以前的IE浏览器会这样解析这段代码:<div>
作为一个顶级元素,将<section>
元素看做一个错误。<section>
会被忽略,<h1>
和<p>
被解析时作为<div>
的子元素。关闭标签</section>
同样也被当做错误忽略。这样解析的效果就等同于下面的代码:
<div class="outer"> <h1>title</h1> <p>text</p> </div>
由此可见,旧的IE浏览器处理未知元素的策略确实能将页面“合理”的恢复,但是相比其他浏览器它构建了一个不同的DOM结构。由于在DOM结构上没有未知的元素,所以你也就不能在<section>
上应用样式。这是一个种情况#1。
当然,那些支持HTML5的浏览器中,比如IE 9、Firefox 4、Safari 5,就能像HTML5规范中规定的那样构建出正确的DOM结构并且能应用正确的默认样式。
因此,最大的问题不仅是浏览器从相同的代码中构建出了不同的DOM结构,同时还为相同的DOM结构应用了不同的样式规则。
解决方案
如今,很多人想出了很多不同的解决方案以使HTML5元素能用于页面上。每个方案都是解决某个或某几个已经提及的特定问题,以实现浏览器的兼容。
JavaScript 垫片(JavaScript shims)
JavaScript shims主要目的是解决HTML5元素在旧IE下的样式问题。在IE中有一个众所周知的怪异行为:IE会忽略掉它不认识的的元素,除非这些元素是通过document.createElement()
创建的。所以如果调用document.createElement("section")
,那么浏览器就会生成<section>
的DOM节点并且在其上应用样式。
像htmlshim[1]这样的shims就是利用这个特性使HTML5元素能在IE中生成DOM节点从而使你能在其上应用样式。Shims通常还会在HTML5块级元素上应用display:block
,从而使其能做到浏览器兼容。
我不喜欢这种方法,因为它违反了我构建web应用的主要原则之一:不应该依赖JavaScript进行布局。这样做不仅仅关系到会给那些禁用JavaScript的用户带来糟糕的体验,而且它还关系到构建可预见的、可维护的、有清晰分层的web app代码库。它确实能在所有浏览器中生成相同的DOM结构并且使你的JavaScript和CSS正确的工作,但在我看来还是弊大于利。
命名空间hack (NameSpace hack)
从来不缺少hacks,还有另一项技巧可以使IE认识那些未知元素。这项技巧第一次获得广泛关注是通过Elco Klingen的 文章,HTML5 elements in Internet Explorer without JavaScript[2]. 这项技巧包括声明一个XML风格的命名空间,然后使用这些元素时加上命名空间前缀,像这样:
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:html5="http://www.w3.org/html5/">
<body>
<html5:section>
<!-- content -->
</html5:section>
</body>
</html>
html5
前缀仅仅是个前缀名字而非官方要求,所以你把前缀设置为“foo”效果是一样的。这样使用前缀,Internet Explorer就会认识这些新元素,从而你就可以在它们上面应用样式了。这个方法在其他浏览器中同样能够工作,所以你就能在浏览器中获得相同的DOM和样式。
缺点同样鲜明:你必须在HTML文档中使用XML风格的命名空间,同时也要以相同的风格使用CSS,像下面这样:
html5\:section {
display: block;
}
这并不是我喜欢的编码风格。这是一个漂亮的解决方案,教会我一种不自然的元素应用方式。我不希望看到文件中满是带有命名空间的元素。
防弹技术 ("Bulletproof" technique)
我第一次接触这项技术是在YUIConf2010上,Tantek Celik做了一个主题演讲,HTML5: Right Here, Right Now[3]。在那个演讲中,Taktek建议在每个HTML5的块级元素中内嵌一个<div>
,在这个<div>
上设置一个CSS类用以表示它所代表的HTML5元素。例如:
<section>
<div class="section">
<!-- content -->
</div>
</section>
这种方法的目的是使内容能在所有浏览器中保持正确的文档流。在一个HTML5的块级元素中嵌入一个块级元素意味着会有三种情况:你要么有一个单独的块级元素(Internet Explorer < 9),要么是一个块级元素包含在一个内联元素中(Firefox3.,Safari,etc),或者是一个块级元素包含在一个块级元素中。无论哪种情况,默认的渲染都是一样的。
Tantek提出了这种方法的一个例外情况,就是<hgroup>
。<hgroup>
明确指出不允许非head元素作为其子元素。为此,他推荐将<div>
放在外边:
<div class="hgroup">
<hgroup>
<!-- content -->
</hgroup>
</div>
关于样式,Tantek推荐不要试图去给HTML5元素本身应用样式,而是要给作为代理的<div>
应用样式。所以不要这样做:
section {
color: blue;
}
而是这样做:
.section {
color: blue;
}
这样做的理由是,以后它会很容易的自动转换成一个参照这个模式的HTML5元素的标签。我并不热衷于他的这个建议,因为我通常不喜欢通过标签名称应用样式。
这个方法的缺点是会在不同的浏览器中生成不同的DOM结构,所以你在写JavaScript和CSS时就要小心了。例如,使用孩子选择器(>)时经过HTML5的元素时,就不能做到在所有的浏览器中工作正确。同时,直接访问parentNode
也会在不同的浏览器中获得不同的节点。这种情况在下面这样的代码中尤为明显:
<div class="outer">
<section>
<div class="section main">
<!-- content -->
</div>
</section>
</div>
比如你有个选择器section > .main
,它在Internet Expl 8和就早的版本中就不会工作。
反转防弹技术(Reverse bulletproof technique)
有另外一些文章,像Thierry Koblentz的HTML elements and surrogate DIVs[4]. 展示了反转Tantek的方法:将HTML5元素包含在<div>
中。例如:
<div class="section">
<section>
<!-- content -->
</section>
<div>
唯一的不同之处就是HTML5元素所在的位置——所有的元素都在相同的位置。支持者喜欢这项技术是因为他的一致性(对所有元素来说工作方式是一样的,包括<hgroup>
)。 值得指出的是,像Tantek的方法一样,它同样会有CSS选择器适用性和JavaScript DOM访问的问题。它的主要优点就是一致性。
我的方法(My approach)
在方法的选择上我的主要目标是:这个方法要使我仅仅改变页面上的HTML。这意味着对于CSS和JavaScript来说要0修改。为什么要做出这样的决定呢?对于web应用(或者其他应用)来说,你的变化所涉及的层越多,引入bug的风险就越高。将变化限制在一层那么就一定程度上限制了bug的引入,而且如果一旦出现bug,你就可以只在一个领域去寻找底层问题的所在。例如,如果布局被破坏了,我就知道这是因为我增加了<section>
元素,而不是其他的什么CSS和JavaScript问题。
在调研了这些技术后,我做了一些原型和测试,最终我还是回到了Tantek的方法上。在不需要修改CSS和JavaScript的前提下,这是使我现有的原型页面正常工作的唯一方法。不过,我并没有完全按照他的方法来做,而是做了些变化,我认为这些变化对这个方法有所改进。
第一点,我从不在代表HTML5元素的类上加任何样式(所以在我的选择器中没有.section
)。我保持页面中已有的<div>
元素,为它使用语义类名作为应用样式和JavaScript的钩子。例如,下面的代码:
<div class="content">
<!-- content -->
</div>
就变成了这样:
<section>
<div class="section content">
<!-- content -->
</div>
</section>
有了这点变化,我仍然使用.content
作为样式和脚本的钩子。这样,我已有的JavaScript和CSS就不需要修改了。
第二点,与其将<hgroup>
作为一种特殊情况,我选择不去使用它。事实是,我在我现有的页面中找不到使用这个元素的场景。
为了从中选出一个较优的方案,我花费了大量时间在防弹技术和反转防弹技术的比较上。对于我来说,做出选择的关键因素是反转防弹技术需要我增加CSS以使它能正常的工作。在那些为HTML5元素生成DOM节点但是没有应用默认样式的浏览器中,将HTML5块级元素嵌套在<div>
中不止一次的打乱了我的布局,因为在这些老浏览器中这些HTML5块级元素变成了内联元素。我必须显示的添加规则将它们变成块级元素以使我的布局能够工作,但是这样的话就不符合我的初衷了:不要修改CSS。
证明(The proof)
在讨论时我发现的一件令人无比沮丧的事就是人们太轻易就否定一种方法了,因为他们总能找出至少一个反例。我在本文中展示的每一种方法都不是完美的;每一种方法都不能适用于你遇到的所有情况。如果你提供给我一项技术,我敢保证肯定有人能找出一个它不能工作的情况。但是这并不能否定这项技术的价值,它仅仅是告诉你这项技术有它的局限性,你可以做出更好的选择。
在我的调研中,我使用一些已经存在的页面并使用“改进的防弹技术”修改它们。我将它们放入带有简单布局的页面、带有复杂布局的页面、带有JavaScript交互和不带有JavaScript交互的页面。每一种用例下,我唯一需要修改的就是HTML并且一切都能正确工作(不需要修改CSS和JavaScript)。那些关于子节点和父节点关系的警告呢?有意思的是我从来没有碰到那些问题。
对于我来说比较容易的原因可能是我代码写的比较严苛。我认真的复查:
- 不用标签名和IDs应用样式(只用类)
- CSS选择器尽可能一般化,选择器类型尽可能少
- JavaScript不依赖特定的DOM结构
- 不用标签名操作DOM
另一件有趣的事是我使用HTML5作为容器。这些元素其实仅仅是功能组(功能块)之间的界限。你在边界内使用样式和脚本,而不是穿越这些边界本身。由于在边界内使用那些元素的JavaScript和CSS能够良好的工作,所以我猜想那些编码良好的站点也能够很好的使用这个方法。
结论
我最后选择的这项技巧是修改Tantek的防弹技术得到的,同时我也将他推荐给其他人。很明显,这个名字有点用词不当,因为它对CSS和JavaScript有一些副作用,但是在我的经验中它确实是唯一允许我只修改页面中的HTML而其他部分能继续工作的方法。我肯定争论还会继续,不管是在各公司的内部还是互联网上。我希望本文能对你做出决定提供帮助。
引用(References)
- html5shim
- HTML5 elements in Internet Explorer without JavaScript , by Elco Klingen
- HTML5: Right Here, Right Now , by Tantek Çelik ( Video , Slides )
- HTML elements and surrogate DIVs , by Thierry Koblentz
相关推荐
在这个实例中,我们将会深入探讨HTML5的一些关键新增元素,以及它们如何通过CSS样式文件(如html5semanticmarkup.css、html5reset.css、html5simple.css、html5forms.css)进行美化和功能增强。 首先,HTML5的语义...
在 Visual Studio Code (VSCode) 中,语法高亮和语义高亮是两种增强代码可读性和美观性的关键功能。这两种高亮方式帮助开发者更好地理解代码结构和含义,从而提高编程效率。 1. **语法高亮 (Syntax Highlight)** ...
语义分割(Semantic Segmentation)是图像处理领域的一个任务,旨在将图像分割为不同的区域,并且每个区域都标记上它所属的类别,这与目标检测不同,目标检测仅标记出图像中的目标并给出边界框。 在Yolo的语义分割...
Semantic UI HTML5前端开发界面框架,这个框架可开发出一些移动设备浏览的网页、客户端界面等,兼容Ie9/火狐、Chrome、Opera和Safari等主流浏览器。Semantic UI完全语义化,跟 Bootstrap 和 Foundation 比起来,还是...
Semantic UI 是一套基于语义化 HTML 的 CSS 框架,它的核心理念是通过使用人类可读的类名来创建页面布局和元素样式。这使得代码更易理解和维护,同时也提高了团队之间的协作效率。 **2. 语义化 HTML** 在 Semantic ...
Semantic UI 是一款极其优秀的语义化前端框架,它以其简洁的语法和丰富的组件库而受到广大开发者喜爱。语义化意味着代码更易于理解和维护,就像我们用自然语言交流一样,使得非技术人员也能大致理解网页的结构。下面...
### 语义网(Semantic Web)概述 #### 一、语义网的定义与起源 语义网(Semantic Web)是万维网之父蒂姆·伯纳斯-李提出的一个概念,旨在创建一个更加智能化、自动化的网络环境,使得机器能够理解网页上的信息并...
1. ** semantic elements **:HTML5中的语义元素如、和帮助我们更好地组织页面结构,提高可访问性。 2. ** Data attributes **:通过自定义"data-"属性,我们可以为元素添加额外的数据,这在JavaScript中处理元素时...
It presents the essential HTML5 elements and attributes in a well-organized format that can be used as a handy reference. HTML5 Quick Markup Reference is an HTML5 reference title covering tags and ...
8. Semantic Markup:HTML5强调语义化的标记,有助于屏幕阅读器和搜索引擎理解页面内容,提高无障碍访问和搜索排名。 9. WebGL:虽然不直接涉及摇号抽奖程序,但WebGL是HTML5的一个强大扩展,它允许在浏览器中进行...
2. **Elements**: 包括基本的HTML元素,如段落、标题、链接等,提供了丰富的样式选项和定制能力。 3. **Collections**: 提供了诸如列表、表格、卡片等数据展示组件,便于组织和展示信息。 4. **Forms**: 支持...
例如,一个三维建筑模型通过语义标注可以明确区分出墙壁、窗户和门等元素,使得后续的自动处理和分析更加精准。 接下来,我们关注的是三维相似度计算。这是一个衡量两个或多个三维模型之间相似程度的技术,常用于...
然后我们使用预先训练的卷积神经网络对图像进行语义分割。为了获得语义分割的点云,我们将分数从分段投影回点云。我们的方法是在semantic3D数据集上进行评估的。我们发现我们的方法与最先进的技术相当,没有对...
在“Semantic_HTML5-main”这个文件中,我们可以期待看到一个使用上述语义元素构建的示例模板。这个模板将演示如何有效地组织和结构化网页内容,以实现更好的用户体验和搜索引擎理解。通过实践这些基本的语义HTML5...
SemanticUI 是一款流行的前端开发框架,它以语义化、直观和美观的代码设计为特点,使得开发者可以更轻松地创建响应式、易用的网页界面。在“semanticui管理模板_响应式网站后台模板html框架stagb”中,我们可以看到...
演示HTML5语义元素的使用 解释语义元素背后的历史推理 当开发人员最初开始定义用于构造HTML的容器时,他们只有一个通用元素: div 。 然后,创建复杂的页面布局需要数十个div元素,这些元素通常很难在代码中进行组织...
6. ** Semantic元素** - HTML5提供了一些语义化元素,如, , , 等,这些可以帮助结构化内容,提高可访问性和SEO优化。 7. **CSS3动画与过渡** - CSS3允许创建复杂的动画和过渡效果,可能会用于相册的图片切换,过渡...
Semantic-UI-Docs, 语义用户界面的官方文档 语义文档这里文件夹包含用于生成 semantic-ui.com的static 网站的模板。:如何使用安装插件,用于创建网站的HTML的static 站点生成器。npm install -g docpaddocpad in
1. **语义化HTML**:Semantic UI CSS的核心理念是将HTML元素与实际意义紧密结合,使代码更具可读性和可维护性。通过使用如`<div class="button">`而不是无意义的`<div>`,开发者可以更清晰地表达元素的意图,这不仅...