什么是HTML的语义,直观的说就是HTML的含义,从HTML代码本身就可以判断包含内容的作用。HTML标签语义化是Web网页标准化的重要一环,也是标准制定时重要的设计原则。HTML5中新增加的很多标签(如:<article>、<nav>、<header>和<footer>等)就是基于这样的设计原则。页面标签语义化的优点明显,标签语义化使得诸如搜索引擎以及第三方内容抓取工具等更容易读懂页面代码。机器不会关注页面实际渲染的外观,只会关注页面内容本身,页面渲染的漂亮与否对机器识别毫无帮助。那么具体什么样的页面设计才是语义化的页面?浏览器会对语义化的标签设计默认的样式,所以验证页面是否语义规范的一个简单方式就是去掉CSS样式后页面是否还能正常阅读。先来看看一个例子。
假设我们要实现如下的一个工具栏:
如果仅仅是实现这样的外观,则如下的代码加上合适的CSS样式就可以达到要求。
1
2
3
4
5
6
7
8
9
|
< div id = "reader_main_action" class = "reader-main-action" > < span class = "reader-action-library" ></ span > < span class = "reader-action-spliter" >|</ span > < span class = "reader-action-toc " ></ span > < span class = "reader-action-spliter" >|</ span > < span class = "reader-action-note" ></ span > < span class = "reader-action-bookmark" ></ span > < span class = "reader-action-highlight" ></ span > </ div > |
如上的实现方式是一种常见的实现方式,但从标签语义的角度来看,不推荐此实现方式。代码中使用的标签<div>和<span>是在所有的HTML标签中最没有语义的。所以要做到标签语义化,首先要尽量少用<div>和<span>这两个标签,在使用这两个标签时尽量能找到更有语义的标签代替。
再来看看第二种实现方式。按照需求,这是一个包含5个操作项的工具栏,应该使用符合语义的<ul>标签。
1
2
3
4
5
6
7
8
9
|
< ul id = "reader_main_action" class = "reader-main-action" > < li class = "reader-action-library" ></ li > < li class = "reader-action-spliter" >|</ li > < li class = "reader-action-toc" ></ li > < li class = "reader-action-spliter" >|</ li > < li class = "reader-action-note" ></ li > < li class = "reader-action-bookmark" ></ li > < li class = "reader-action-highlight" ></ li > </ ul > |
第二个方案比第一个方案有所改进,使用了语义化的标签<ul>,但是我们总共有五个操作项,而此方案使用了七个<li>标签。两个非操作项的分隔符占用了两个<li>标签。单纯从语义上看,两个分隔符和其他五个操作项具有等同的重要性。试想一下,搜索引擎识别此段代码时,会认为工具栏中包含七个操作项,这明显偏离了实际的语义。所以此方案需要进一步改进,去掉多余的两个<li>,使用CSS样式来实现分隔符的效果。如下是改进后的代码:
1
2
3
4
5
6
7
|
< ul id = "reader_main_action" class = "reader-main-action" > < li class = "reader-action-library" ></ li > < li class = "reader-action-toc spliter" ></ li > < li class = "reader-action-note spliter" ></ li > < li class = "reader-action-bookmark" ></ li > < li class = "reader-action-highlight" ></ li > </ ul > |
使用CSS样式实现分隔符效果:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
.reader-main-action .spliter { margin-left : 30px ; } .reader-main-action .spliter:before { content : '|' ; line-height : 28px ; font-size : 20px ; color : #888 ; cursor : default ; text-indent : 0 ; float : left ; margin : 0 -20px ; } |
第三个方案把无关内容的元素彻底从HTML中分离了出来,删除了干扰语义的标签,是不是完美了?还差一点,假设搜索引擎解析到这段HTML代码,从语义上只能分析出这是有5个操作项的工具栏,具体每个操作项的作用则不得而知。需要继续添加文字说明,修改后的代码如下:
1
2
3
4
5
6
7
|
< ul id = "reader_main_action" class = "reader-main-action" > < li class = "reader-action-library" >library</ li > < li class = "reader-action-toc spliter" >toc</ li > < li class = "reader-action-note spliter" >note</ li > < li class = "reader-action-bookmark" >bookmark</ li > < li class = "reader-action-highlight" >highlight</ li > </ ul > |
给每个操作项添加了名称,这下语义清晰了。因为操作项在界面上显示的是图标按钮,需要把文字隐藏掉。如下的CSS样式可以实现文字的隐藏:
1
2
3
|
.reader-main-action li { Text-indent: -9999px ; } |
第四个方案中,添加了一些隐藏的文字,看似多余的代码,却是很有必要的。按照之前提到的验证HTML代码语义性的方法,去掉所有的CSS样式,只有此方案能在界面上正常显示5个操作项。如下是禁用CSS样式后,此方案的显示效果图:
编写语义明确的HTML代码需要有足够的耐心和良好的编码意识,这需要在实际的项目中不断地实践。当然编写高语义的HTML代码也是有一些最佳实践可以参考的,如下所列的是最主要的3条原则。
- 熟悉所有规范的HTML标签,理解各标签的语义,在合适的地方使用合适的标签。
如果不考虑HTML的语义,使用<div>和<span>就足够构建页面上大部分的布局,但是这两个标签是没有任何语义的标签。HTML语义化首先要从HTML标签语义化入手,HTML标签是页面内容的载体,语义化的标签相对于是对所包含内容的一个整体声明,也使得页面整体结构清晰。网页的开发者应该熟悉所有规范的HTML标签的使用场景,在合适的地方使用合适的标签。例如,标签Hx系列则表示标题,在网页中展示各层级的标题时使用、<ul>和<ol>表示列表,在展现各种数据列表或者菜单是使用,其它使用率较高的语义标签有:<p>、<em>、<strong>、<table>、<site>、<blockquote>等,以及HTML5新加入的标签:<header><footer><article><section><nav><aside>等。W3C规范中针对所有标签都有详细的解释和使用场景示例,这些最基本的内容需要前端开发者熟练掌握。
- 熟悉各标签规范的属性,给HTML标签设置必要的属性。
和标签语义化的重要性一样,某些属性的设置也是HTML语义化重要的环节。在很多规范中规定需要设置的两个属性是alt属性和title属性,这两个属性设置的也是为了提高HTML的语义。在<img>标签中,alt是必须要设置的属性,因为<img>是自闭合标签,并没有包含可以解释说明图片的额外信息。title属性是可选属性,当标签包含的内容不足以说明语义时,可以通过title添加额外的信息。如下示例展示这两个属性的使用:
1
2
3
4
|
<!—alt属性除了对图片作解释说明之外,当图片在浏览器中未加载时的显示的代替文字--> < img src = "/img/loading.gif" alt = "data loading…" /> <!—title属性是对元素的解释说明,并且作为在浏览器中当鼠标移到元素上时显示的提示文本--> < a href = "" title = "" ></ a > |
还有一个重要的属性是<label>标签中的for属性。<label>标签是<input>元素定义的标注。如下示例是<lable>标签的一种不规范用法,却是常见的用法。
1
2
3
4
|
< form > < label >User Name:</ label > < input type = "text" name = "user_name" id = " user_name" /> </ form > |
代码中的<label>标签和<input>标签仅仅是从UI的视觉上是关联在一起的,但是从代码本身并不能看出两者之间的关系。<label>标签上少了一个for属性。<label>标签的for属性值指代一个表单元素,属性值为此表单元素的id值。for属性的作用不仅把<lable>标签上的触发事件指向了for属性指代的表单元素,也从语义上绑定了<lable>和此表单元素。应该给如上示例中的<label>添加for属性,示例修改如下:
1
2
3
4
|
< form > < label for = "user_name" >User Name:</ label > < input type = "text" name = "user_name" id = "user_name" /> </ form > |
- 样式和结构分离。
我们之前提到的样式和结构分离,主要说的是CSS样式和HTML结构的分离。这里会更进一步,把HTML代码中用于表达外观的部分从HTML中删除,并改用CSS样式实现。简洁的HTML代码会代码的语义更加明确。如下的示例代码是上面的示例中展示分隔符的HTML代码:
1
2
3
|
< ul id = "reader_main_action" class = "reader-main-action" > < li class = "reader-action-spliter" >|</ li > </ ul > |
从实际需求分析,分隔符并不是网页内容的一部分,只是用于内容的分割,所以应该从HTML代码中分离,并使用CSS样式实现相同的效果,本例的CSS样式的实现可参照上面示例方案3中展示的代码。
CSS中的两个伪类:before和:after很适合在这样的场景中使用,在元素的前面或者后面添加修饰性的文字或者外观,实现了内容的添加并同时没有破坏HTML代码的语义。这里展示一个常用的场景,应该很多人写过这样的代码。示例如下:
1
2
3
4
5
|
< div id = "main" > < div class = "sidebar" >this is the side bar.</ div > < div class = "content" >this is the main content.</ div > < div class = "clear" ></ div > </ div > |
对应的CSS样式为:
1
2
3
|
.sidebar { float : left ; width : 150px ; } .container { float : right ; width : 450px ;} .clear { clear : both ; } |
代码中为了清除元素的浮动而添加了一个<div>元素,并给此<div>元素添加了clear样式。可能很多人觉得这是一个常规的做法,但是这种写法是破坏了HTML代码的语义,并不是一种好的方案,应该删除这个多余的<div>元素,并改用CSS样式来实现,如下示例代码:
1
2
3
4
|
< div id = "main clearfix" > < div class = "sidebar" >this is the side bar.</ div > < div class = "content" >this is the main content.</ div > </ div > |
对应的CSS类clearfix的声明为:
1
2
3
4
5
6
7
8
9
10
11
|
.clearfix { *zoom: 1 ; } .clearfix:before, .clearfix:after { display : table; content : "" ; } .clearfix:after { clear : both ; } |
上面的示例使用了:before和:after伪类,很好地解决了由于多余的元素而破坏HTML代码的语义的问题。
另外一个经常滥用的标签就是<br >换行符标签。很多新手经常会使用此标签让元素换行显示,甚至会连续使用多个<br>标签来加大元素之间的行距。
1
2
3
4
5
6
|
< div > < span >title</ span >< br >< br > < span >item1</ span >< br > < span >item2</ span >< br > < span >item3</ span >< br > </ div > |
这算是很初级的错误了,完全没有理解<br>标签的语义。<br>标签仅仅用于文本内容中的换行。
如下是从W3C网站上引用的示例:
1
|
< p >P. Sherman< br >42 Wallaby Way< br >Sydney</ p > |
如果要实现元素之间的换行或者增加行间距则可以通过设置display、margin或者是padding等样式。
另外我们在构建页面的时候,经常会添加图片,但是图片是以img元素存在,还是以背景图方式存在?很多时候,我们并没有仔细考虑这样的问题,实现的方式很随意。其实,从HTML语义的角度考虑,很容易决定应该使用img元素还是背景图。如果图片是作为页面内容的一部分,则应该使用img元素,如果图片仅仅是装饰作用,则应该使用背景图方式。
在构建页面的HTML时,如果能遵守以上介绍的这三点规则,则基本可以保证页面HTML代码的高语义。