使用HTML 5语义化标签

为了在主流浏览器上使用HTML 5语义化标签,需要做一些修正,本文便是对这些修正原理的解释。
如果你正在寻找一个快速的解决方案,可以看以下HTML5 Shiv这个库。下载这个库的代码,然后在页面的head中使用以下代码即可:

1
2
3
<!--[if lt IE 9]>
<script type="text/javascript" src="path/to/html5-shiv.js></script>
<![endif]-->

如果看看这个代码背后的原理,请继续往下。

HTML 5语义化标签简述

语义化标签,顾名思义,是具备一定语义的标签。比如,当使用ol标签,语义就是创建一个有序的列表。语义化可以增强页面的可访问性。

一个页面通常会被划分成几个区域,比如头部,边栏,内容区域以及底部。在HTML 5之前,页面的结构代码看起来类似于:

1
2
3
4
5
6
<div id="header"></div>
<div id="main">
<div id="sidebar"></div>
<div id="article"></div>
</div>
<div id="footer"></div>

由于这些结构划分的通用性,HTML 5引入了几个具有此类语义的标签:

1
header, main, aside, article, footer

使用这些标签重写上面的页面:

1
2
3
4
5
6
<header></header>
<main>
<aside></aside>
<article></article>
</main>
<footer></footer>

新标签与旧浏览器的冲突

有些浏览器早于HTML 5草案发布,所以这些浏览器可能不支持这些新的标签。这就存在着一个问题,那就是浏览器对于未知的标签(元素)是如何处理?这个问题可以再细分为两个子问题:

  • 如何处理未知元素的样式
  • 如何处理未知元素在DOM树中的位置

不同的浏览器对于这两点的处理是不同的,特别在老版本的IE中存在特殊的行为。

第一个修正

针对第一条(即未知元素的样式),对于浏览器来说,最为简单的做法是不对未知元素的样式做任何处理。浏览器会给已知元素设置一些默认的样式,比如i标签,默认是斜体,p标签具有前后留白等。而对于未知元素,浏览器没有给定任何的默认样式,由页面作者自定义其样式。

但需要注意的是,浏览器会将未知元素认为是inline级别。所以对于旧版本的浏览器做的修正是明确指定新标签的display规则:

1
2
3
header, main, aside, article, footer {
display: block;
}

针对IE的处理

事情还未结束,因为IE 9之前的版本对于未知元素的处理存在着两个问题:

  • 无法应用样式到未知元素上
  • 错误地解析未知元素为空节点

第一个问题是,即使在样式表中指定了未知元素的样式规则,同样无法生效。

第二个问题从解析后的DOM结构来看很明了。假定有如下的代码:

1
2
3
4
<article>
<h1>Welcome to Initech</h1>
<p>This is your</p>
</article>

正确的渲染之后是如下的结构:

article
|
+--h1 (article子节点)
|  |
|  +--text node "Welcome to Initech"
|
+--p (article子节点)
   |
   +--text node "This is your "

在IE 9之前的版本中,article标签(未知元素)将被解析成一个空的标签,其子元素成为这个未知元素的相邻节点:

article (空节点)
h1 (article相邻节点)
|
+--text node "Welcome to Initech"
p  (article相邻节点)
|
+--text node "This is your "

幸运的是,IE中这两个问题可以很简单的被修正。

对于未知元素,在页面渲染前使用document.createElement()这个方法创建一次即可,不用注入到页面上。例如:

1
document.createElement("article");

需要注意的是,必须在浏览器解析未知元素之前使用这个方法。所以建议是将这个hotfix放置在页面的head区域中。

小結

为了在兼容当前主流浏览器的情况下使用HTML 5新的语义标签,需要做两个处理:

  1. 明确指定新标签的display属性

    header, main, aside, article, footer {
        display: block;
    }
    
  2. 针对IE 9以下版本的浏览器做处理。在页面head区域,使用以下代码:

    <!--[if lt IE 9]>
    <script type="text/javascript">
        var e = ("abbr,article,aside,audio,canvas,datalist,details," +   
                 "figure,footer,header,hgroup,mark,menu,meter,nav,output," +
                 "progress,section,time,video").split(',');
        for (var i = 0; i < e.length; i++) {
            document.createElement(e[i]);
        }
    </script>
    <![endif]-->
    

以上。

参考资料

0%