第2章 升级至HTML5

第2章 升级至HTML5

HTML5易学难精。没错,大多数的软件工程师、设计师甚至大批高中生都声称懂得 HTML,但是他们可能只了解很少的一些元素(element),而且可能这些元素的用法都不正确。

在本章,我们将介绍很多HTML5的分段(sectioning)元素。当你读完本章的时候,应该对HTML5的所有语义有一个很好的理解。我无法在三章的篇幅里向你传授HTML的所有内容。说实话,我自己还在继续学习HTML——而且不仅是因为HTML5仍是一个未完成的规范。由于规范尚未完成,可能仍然会有一些修改。但是也不用为这事担心。多数情况下,那些浏览器已经实现了的特性会保持不变,或者只有细微差异。

我希望你除了学习有关各种元素、它们的属性、它们语义含义以及它们的目的等相关知识之外,还能够认识到你对HTML的了解比你认为的要少:HTML有关的知识学得越多,越知道还有更多的知识要学。

简而言之,我们即将开始介绍元素。虽然可以只用一章来介绍每一个元素,但我们还是有充分的理由把它们划分到几个内容还算比较长的章节里面。我们用了足够的篇幅让你知道如何使用每个元素,而且至少还能够让你了解那些你之前所不了解的。

大家首先要了解的是,在HTML5这个术语中间没有空格:是HTML5,而不是HTML 5。

看到了吧?你已经学到些东西了!你现在已经先人一步了。那我们就快点开始吧。

2.1 HTML5语法

HTML5与HTML4与XHTML非常类似。后两者支持的大部分元素在HTML5中仍然是支持的。只有一些过时了的标记和属性已被剔除。在大多数情况下,如果你的文档能通过HTML4严格(Strict)模式或是XHTML模式的验证,那么它们作为HTML也能通过验证[1]。HTML和XHTML的语法虽略有不同,但是两者都被支持。仅仅把HTML 4.01或XHTML的doctype改成<!DOCTYPE html>,就可以通过HTML5验证(稍后将介绍更多有关doctype的内容)。

HTML5比HTML4和XHTML更好,包含了之前版本的元素,剔除了已过时的元素,添加了一些新元素,还重新定义或微调了另外一些元素。

HTML5规范的编写者调查了Web上那些开发者们已经在做的:哪些文档分段是各种网站都趋向的,他们都赋给这些组件哪些类(class)和ID,哪些脚本是大多数的网站作者反复使用的,以及哪些类库功能已经激增至普遍存在。

HTML5试图处理那些个人开发者们一直自行在做的:创建一个标准;详细说明浏览器都应该如何处理这些标准;以及当他们的代码,呃,不那么标准的时候,浏览器应该如何处理开发人员标记。HTML5规范明确细化了浏览器应该如何处理,或解析,各种代码正确或错误的情况。通过关注细节,HTML5的一个目标就是告诉浏览器如何处理所有可能会发生的情况,从而浏览器可以从同样的标记构造出一致的DOM,这样开发人员就不会一直把带宽浪费在处理浏览器差异上了。

从我个人而言,我乐于见到更严格的标准。我的观点是开发者们应该正确地编写代码,而不是指望浏览器从宽解析糟糕的代码。你正在读这本书,所以我假定你是“良好代码”阵营的一员。很好!这就是你要学的东西。

2.1.1 元素

Web页面是由一系列元素组成的。有些元素是空的,其他的元素则包含文本,而另一些可以包含其他元素(或者既有元素也有文本)。大多数元素可以包含子元素或文本节点。那些不能包含子元素的,例如图像和meta元素,称为空元素(empty element)。

如图2-1所示,一个元素就是一个结构体,由一个开始标记、一些可选的(有时是必需的)属性、通常还有一些内容,以及一个结束标记,而且如果你使用XHTML风格编写代码的话,还有一个专门针对像<img><input>这样空元素自闭合标记的可选的斜杠组成。

..\16-1116 改图\0201.tif

图2-1 组成元素的要素

在HTML之前版本的中,内联元素(inline element)只能包含其他内联元素和文本。根据元素的不同,块级元素(block-level element)可以包含其他块级元素、内联元素和(或)文本。它们的“后代”元素(descendant element),像“祖先”元素(ancestor element)一样,也可以由元素、属性和文本组成。

图像说明文字 

使用CSS,你可以把任何短语元素[2](phrase element)的样子更改成块(block)显示,还可以强制一个块元素或区块元素(sectioning element)显示成内联的样子(注意:我仍然在使用内联这个词。在HTML5中,内联指的是外在表现,而不是指元素类型)。

在HTML5中,我们终于从内联元素还是块元素的观念中解脱出来了——基于外观的命名约定。在HTML5中,元素被定义为区段元素、标题(heading)元素、短语元素、嵌入式(embedded)元素、流(flow)元素、元数据(metadata)元素以及交互式(interactive)元素。不过在语义上,一些观念还是保持不变的。举例来说,区段元素不能位于短语元素内部。

图像说明文字 

在选择一个元素时,要基于语义选择最恰当的元素,而不要基于默认的浏览器渲染。虽然你确实可以针对不管什么文体上的目的而使用任意元素,但你不应该这样做。每一个元素都有语义上的含义。

2.1.2 属性

所有的元素都可以有属性。有些元素有必需的属性。有关属性的一个例子是<a>元素的href属性,如图2-1所示。属性是典型的键/值对(name/value pair),尽管布尔属性的值是可选的[3]。属性为渲染引擎提供了有关元素的附加信息,并且都位于开始标记中,而不在结束标记中。

有几个属性对于几乎所有HTML5元素来说是全局的(global)——包括核心(或全局)属性和国际化(internationalization)属性(将在下一节中介绍)——以及另一些更加元素特有的属性,这些我们将在第3章当讲到这些属性正在被修改的元素时进行介绍。

2.1.3 全局属性和国际化属性

HTML5已经添加了几个国际化属性和核心属性,这些属性可以被应用到几乎任何元素上。

idclasstitlestylelangdir属性继续在所有元素上被支持。HTML5往核心属性列表中添加了accesskeyhiddentabindex属性,同时还有contenteditablecontextmenuspellcheckdraggabledropzone共5个建议性的交互式属性。随后将讨论这些属性。

除了全局属性,所有的元素也可以有微数据(microdata)属性(WIA-ARIA角色和aria-属性)和自定义数据属性。自定义数据属性是你自己的属性,写成data-*的形式,这里的*由你自己设置。HTML5通过添加data-前缀以允许开发者们创建不会与未来的HTML版本冲突的属性。我们将在“data-自定义数据属性”小节描述data-属性,在第6章介绍微数据和ARIA无障碍属性。

id

id属性是一个唯一标识符。每个文档不应该存在具有相同id的两个元素,并且每个元素最多也只能有一个id。在HTML5中,id的值必须至少一个字符长,而且不能包含空格。这与之前的版本有所不同,之前版本id的值必须以字母A-Z或a-z开始,后面可以跟字母(A-Za-z)、数字(0-9)、连字符(-)、下划线(_)、冒号(:)和句号(.)。

图像说明文字 

我建议你把id限制于仅使用字母和数字,然而无论你选择使用哪种命名约定,重要的是保持统一。

id属性一般是可选的。不过,对于内部页面锚点(anchoring)和正在实现显式标签(explicit label)的表单内部元素是必需的。通过使用标签的for属性和表单元素的id属性可以把显式标签和表单元素关联起来。要注意的是,对于嵌套在一个隐式标签(implicit label)之内的表单元素,id属性不是必需的。我们将在第4章讨论标签和id属性。

id属性作为一个锚点用于使用JavaScript进行定位也非常方便,只是可能有一点重度使用。id属性,如果有被包含的话,可以用在CSS中定位元素。然而,由于id在CSS样式中的高量值或特征性,即使id选择器用起来稍微更好一些,id值也应该尽量少在CSS选择器中使用。所有这些我们将在第6章讨论。现在你只要知道,在你读完这本书的时候,你将能意识到你可以使用CSS3选择器定位到页面中的任何元素,而不需要使用id选择器就够了。

class

class是该元素所属的一个类别的名字或一些类别的列表。class属性具体说明了该元素是哪一个或哪一些类的一员。和id属性不同,任何数量的元素都可以共用同一个类。一个元素可以有多个使用空格分开的类。

就CSS样式而言,class属性中类名的顺序无关紧要。然而在样式表(stylesheet)中的顺序,却很重要(这个问题我们将在第6章进行讨论):

<a href= " http://google.com " class="external popup search">link text</a>

title

title属性为它应用到的任意元素提供了一种人工可读的描述。title属性在有些可视浏览器上经常被实现为一个“工具提示”(tooltip),但是其他浏览器,尤其是移动浏览器,不会显示该title属性。虽然屏幕阅读器可以设置成支持title属性,但是大部分屏幕阅读器不会把title属性的值作为默认设置进行读取,因此在提高可访问性方面不能依赖title属性。

图像说明文字 

title属性对于有些元素来说是必需的,例如<abbr>;对<abbr>来讲,其title属性的值就是其缩略语的扩展。除此之外的title属性一般是可选的。

然而title属性作为一个链接、图像、框架和多媒体元素的属性时还是有用的,它可以作为一种能根据用户交互显示一些零散隐藏信息的方法被派上用场。举例来说,我们可以使用CSS提取title属性的内容,然后通过把title的值作为通过::before::after伪元素(pseudoelement)生成的内容的一部分,就可以为“工具提示”弹出式窗口创建生成的内容。

虽然title属性的值可用于渐进式增强(progressive enhancement)的漂亮花招(trick),但是因为这种花招的非可访问本质,我们不应该依赖于它来提供重要信息。而且因为用户能够访问到它,因此只能在title的内容是有用而且适合的时候才能使用title。如果你为了让你的统计可用而往title属性中添加内容,或者添加供你的JavaScript使用的代码,不要这样做!随着自定义数据属性(我们将在“data-自定义数据属性”小节介绍)的加入,rel属性和title属性巧妙的滥用已经没有必要(而且根本不适合)。

style

style属性可以让你指定某一元素只会出现一次的样式规则。该属性在快速原型设计的时候可以派上用场。除了原型设计之外,应该都不需要使用该属性,因为Web标准规定内容应该与呈现分离。

另外还要注意,当在像Safari和Chrome的Web Inspector、Firefox的Firebug、Opera的Dragaonfly、IE的F1这样的工具中使用检查器来查看代码时,使用JavaScript或者通过调试器接口添加的样式,将作为style属性的值内联出现。这是动态地生成的。浏览器可以这么做。但你最好不要!

lang

lang属性是两个全局的国际化属性之一(dir是另外一个)。一个Web页面的首要语言使用<html>元素的lang属性,通过HTTP头的Content-Languagehttp-equiv="language"属性进行设置。用于国际化或者定义内容的非默认语言区块时,lang属性详细说明了该元素属性值及其内容的语言种类,包括它所包含的那些没有给自己指定lang属性的所有元素。

lang属性使得搜索引擎能够按内容的语言种类编制索引,并允许屏幕阅读器使用国际发音规则。

lang属性使我们能够根据语言来样式化文本。<q>元素应该根据在lang属性中定义的语言来呈现恰当的引号,但这并没有被很好地支持。

dir

lang属性经常一起使用,在书写阿拉伯语(Arabic)、希伯来语(Hebrew)或者其他自右向左的语言时,dir属性可以用于更改文本方向。dir属性的默认值是ltr(从左到右)。如果你的Web页面主要使用一门这种自右向左的语言,则在<html>元素中使用dir属性来设置主要的方向。

在页面正文里面,如果你有不是页面默认方向的内容,可以使用dir属性更改文本方向。虽然没有显式要求,但我还是建议无论何时你在一个元素上面包含了dir属性,同时也要包含title属性和lang属性。一般来讲,dir属性被用于把部分文本改成自右向左。包含lang属性是因为有必要通知搜索引擎、屏幕阅读器以及其他辅助技术该语言已经改变。title属性为你提供了一种方法,让你可以包含一份内容的翻译,使用你的网站的主要语言。这些属性提供了各种方法,不仅让你的网站内容对那些残障人士是可访问的,而且对你主要的“视觉障碍”用户Google也是可访问的!

注意,在HTML5中dir略有不同,现在已经引入了第三个值auto。这样dir属性可能的值就包括rtlltrauto

2.1.4 成为HTML5核心的HTML 4属性

上面的属性都是之前版本(X)HTML的全局或核心属性,而且继续还是。还有两个在交互式元素上所支持的可访问性属性,现在HTML5中是全局属性。这些将在下面的小节中介绍。

tabindex

在以前的规范中,tabindex被包含在像链接和表单元素这样的交互式元素上,允许开发者们设置这些元素接收焦点的顺序。HTML5已经把tabindex的作用扩展至包括所有的HTML元素。

很多人使用鼠标浏览网站,点击链接和表单元素参与交互。其他人使用键盘浏览页面;点击Tab键就把焦点从一个可交互元素移动到了下一个。在非可触控手机上,用户使用导航或方向键盘(简称D-pad)上的4个方向来导航可聚焦元素。在智能机上,大多数用户通常会触控他们希望跟踪的链接或希望输入的表单元素。一旦他们已经在一个表单元素中完成输入,很多动态键盘都提供了“下一步”按钮供前进到下一个表单元素。默认情况下,只有链接和表单字段通过这种方式接收焦点。不管是通过导航键盘的向右按钮、下一步按钮还是Tab键,从当前元素到正在接收焦点的元素的顺序,就是源代码中表单元素的顺序,除非先天的顺序已经被使用tabindex属性篡改。

在HTML5中,tabindex属性的全局性质给所有元素添加了“可聚焦性”——而不仅是表单元素和链接。该属性把它的值看作是一个整数。当用户按下Tab键时,具有tabindex属性的元素将根据tabindex属性的数字值按顺序接收焦点——适合那些具有正值的tabindex

不要使用带有正值的tabindex,除非你能够给页面上的每一个交互性元素都提供tabindex值,而且你还有很好的理由来重新排列这些顺序,并且你还要确保在该应用的整个“有生之年”你将都可以维护其正确的顺序。与此相反,我们应该使用正确的顺序来标记页面。Tab默认的顺序是与源代码中的顺序相同的。重新排列页面的Tab顺序可能会迷惑用户,从而可能导致非常糟糕的用户体验。最好以一种合理的顺序来布置页面,而且绝对不要使用tabindex属性。使用默认Tab(也就是源代码顺序)通常可以建立最佳用户体验。

所以,如果你不应该更改页面的顺序,那为什么tabindex成为一个全局变量了呢?tabindex属性成为全局性的目的是为了在所有元素上,包括非交互性上启用可编程的聚焦,一般是通过JavaScript或键盘焦点。

因为我们不希望真的更改源自页面源顺序的Tab或键盘焦点的顺序,所以tabindex的值只应该是0或−1。tabindex="-1"(任何负数值都起作用,不过−1是惯例)这样的值可被用于可编程聚焦;而tabindex="0"可被用于提供可访问性等方面的事由,假如你想要给一个链接或表单元素之外的元素提供键盘访问的同时又不更改页面的顺序的话。

图像说明文字 

你可能想知道,在通常不使用Tab进行导航的移动领域, tabindex能做什么。注意,你在填写一个表单元素的时候,有些设备上显示出来的键盘在顶部有一个“下一步”按钮。同样,就像在桌面环境上你希望通过JavaScript启用焦点一样,在手机上你可能也想这么做。并且,就像在桌面环境上一样,不是所有的用户都有一台指点设备(pointing device)[4]。许多视觉障碍人士在使用智能手机,尤其是在美国的iPhone。这样一来,tabindex就有助于可访问性。

accesskey

acesskeytabindex类似,除了它不通过使用Tab按顺序导航到下一个具有更高tabindex值的元素进行页面导航,而是把焦点直接移动到触发访问键(activated access key)已经设置好的元素。可以把它看成是一个键盘快捷键。

acecsskey属性的值创建了键盘快捷键。例如,<input acesskey="s"name= "search"type="text"/> 创建了一个accesskey等于s的搜索框。当用户按下字母“s”时,焦点就移到了搜索框。

accesskey属性的值是一个或多个使用一个空格分开的字符。通常情况下,它只是一个字符,但规范允许一个元素可以有不止一个键盘快捷键。accesskey值的语法与class属性类似,后者的属性的值是一个空格分开的标记(token)的有序集合。不过,这里的顺序是有意义的,第一个标记之后的标记被认为是为无法支持初始值的用户代理准备的回退方案。

虽然tabindexacesskey最初都曾被视为可能解决可访问性问题的方案而备受推崇,但它们不是大家都盼望的可访问性解决方案。如前所述,tabindex由于修改页面原本正常的焦点顺序会产生糟糕的用户体验。类似地,accesskey可能会扰乱客户端浏览器设定的默认行为和快捷键。

迄今为止,我还未发现在智能手机上accesskey有什么用,但是因为我们正在学习HTML5,所以就把它包含进来了。accesskey在智能手机到来之前曾经很有用,那时在一个很小的旧手机上浏览网站是件苦差事。

2.1.5 HTML5新内容:全局可访问性和交互性属性

HTML5包括若干新的属性,其中包括在本节介绍的一些新的全局属性。在接下来的两章,当我们讨论到一些元素的时候,将介绍这些元素特有的新的属性和值。

hidden

当含有hidden属性的时候,表示该元素尚未或者不再适用。支持的浏览器不会显示具有hidden属性,或在用户代理的样式表中定义了display:none;的元素。最好不要仅仅为了对用户隐藏元素而使用该属性,因为它是具有语义的:它表示围绕在该hidden属性的内容要么是已经过时的,要么是不再适用的。

contenteditable

contenteditable属性表示该元素是否是可编辑的。当包含该属性时,虽然用户对内容的更改并没有被保存,但的确修改了DOM,这样你就可以捕获这些更改并发回给服务器以保存。所有的桌面浏览器都支持contenteditable属性;随着Android 3.0和iOS 5.0开始提供支持,除了Opera Mini之外的所有移动设备也都支持该属性。

一旦设置了元素的contenteditable属性,触控设备上的动态键盘就应该弹开以启用编辑。

contextmenu

contextmenu属性使元素能够和一个提供了更多上下文相关信息的<menu><command>关联起来。该属性把你希望与之关联的<menu>元素的id的值作为它的值。除了Chrome试验性地提供支持之外,该属性尚未被其他任何浏览器所支持,因此本书并未涉及<menu><command>元素。

draggable

可拖动属性表示该元素是否是可拖动的。你也许已经注意到了,在大多数桌面浏览器上可以拖动图像,但无法放下。这就是目前默认的可拖动行为。为了使draggable属性变得确实有用,应该把它与JavaScript事件处理器结合起来使用,例如dragstartdragdragenterdragleavedragoverdropdragend。除IE10之外的移动浏览器都不支持拖放,因此这些API没有包含在本书中。

dropzone

拖动一个元素是一回事,但是拖完之后你要做什么呢?HTML5提供了一个dropzone属性,可以指定在一个元素上可放下什么类型的内容。你可以使用movecopylink属性值,分别移动、拷贝原来被拖动的内容或为其创建一个链接。因为移动浏览器没有对拖放提供很好的支持,所以我们在本书中不会对其进行进一步讨论。

spellcheck

spellcheck属性表示一个元素是否要进行拼写和语法检查。默认情况下,大多数  智能手机和平板电脑会在输入的时候自动更正(autocorrect)文本区域,但并不总是很  好——有几个拿“更正”寻开心的网站。虽然它们不支持spellcheck属性,但它们的确支持自动更正。

有趣的是,虽然iOS的默认行为是自动更正文本,但如果autocorrect属性被添加到一个文本类型输入,它实际上不检查拼写;它只会在没有包含这个属性的时候才自动更正。

ARIA无障碍属性

HTML5支持无障碍富Internet应用(ARIA)可访问性模块的rolearia-*属性。ARIA是一个单独的模块,而不是HTML5规范的一部分。使用实时区域(live region)、角色以及ARIA状态和属性,WAI-ARIA能够帮助提高动态更新内容和被劫持(hijacked)元素的易访问性。

当与富Internet应用程序交互时,使用屏幕阅读器访问的用户,可能正在让页面的一部分大声地朗读出来,同时页面的另一部分正被动态更新。ARIA实时区域可以帮助向用户表明页面其中的一部分 ——当前没有获得焦点的那部分 ——已经更新了。使用arialiveassertivepolite或默认的off值,ARIA为网站作者提供了一种方法,可以暂停屏幕阅读器,并通知用户页面的一部分已经被更新。相关的属性包括aria-atomicaria-busyaria-relevant

ARIA的role属性可以在改变用途的元素上创建一个语义化结构。举例来说,其用途改变为一个gridlistboxmenumenubartablisttoolbartreetreegrid的元素都可以认定为是这样的元素。使这看似非语义化的标记变得易于访问、可用,以及可以跟辅助技术互操作。虽然屏幕阅读器对新的HTML元素(参见第3章)的完全支持可能会使一些ARIA结构角色不再适用,但是现在就给页面添加rolearticleapplicationbannercomplementarycontentinfodocumentformheadingmainnavigationsearch值可以帮助支持ARIA但尚不支持HTML5的屏幕阅读器。

关于角色需要注意的两个问题是:(1)一旦设置之后,role不应该被动态更改,因为这将会扰乱辅助技术;(2)角色优先于元素的默认语义。

除了role属性和它的很多值之外,ARIA 还为状态和属性提供了相关属性。状态属性有aria-disabledaria-busyaria-expandedaria-hidden,有关属性的属性有aria-describedbyaria-haspopuparia-labelled,这些属性在动态部件(widget)和改变用途的元素上提供了附加信息。最好的作法是针对任务使用语义最符合的现有元素,但是当你针对一个无法预期的用途(例如一个树状菜单)无论如何必须使用一个特定的元素时,应该使用ARIA。

data-自定义数据属性

在HTML5中,你可以创建自己的属性。虽然之前也可以创建自己的属性,但是标记不会通过验证。HTML5引入了自定义数据属性,这样的话,作为作者的你,可以自己定义这些属性的名称。

为了给用户交互提供数据,开发者们一直在编写无效的属性和滥用titlerel属性。仅仅使用data-前缀创建一个属性,代码就可以通过验证,而不是误用像reltitle这样的HTML4属性。

例如,在我们的CubeeDoo游戏中,我们需要维护每一张卡片的值和位置,这样当我们对它们进行比较时,我们就能够知道第一张翻开的卡片是否与第二张翻开的卡片一致,而且在我们暂停游戏以及离开屏幕时,还需要和localStorage结合来维护状态。我们可以在JavaScript中使用数组的方式来记住每一张卡片。相反地,我们在代码中创建了data- positiondata-value属性,可以为每一局新游戏的设定动态地更新data-的值:

    <div id="board" class="level1">
        <div data-value="0" data-position="1">
            <div class="face"></div>
            <div class="back"></div>
        </div>
        <div data-value="0" data-position="2">
            <div class="face"></div>
            <div class="back"></div>
        </div>
        <div data-value="0" data-position="3">
            <div class="face"></div>
            <div class="back"></div>
        </div>
        <div data-value="0" data-position="4">
            <div class="face"></div>
            <div class="back"></div>
        </div>
        ...
        <div data-value="0" data-position="24">
            <div class="face"></div>
            <div class="back"></div>
        </div>
</div>

当用户选择两张卡片时,它们的data-value的值进行了比较。如果一致的话,我们就得到了一对相匹配的。data-position属性使我们可以跟踪每张卡片的位置,在两张卡片成功匹配的时候把它们的data-value的值都改成了0。我们还使用data-value的值来设计卡片正面的样式,使用的是属性选择器(attribute selector),将在第7章进行介绍。

在能够使用data-*属性之前,我们可能已经使用像<div class="…"rel="15" title="4">这样或类似的代码来构建我们的卡片了。虽然title可以通过验证,但却没什么好处,而且在桌面悬停的情况下,甚至会让人们能够轻易地作弊(在这个游戏中,你仍然可以使用一个元素查看器作弊,但是显示一个工具提示就让游戏变得有点太简单了)。data-前缀已经为此目的而被保留了,以避免和未来HTML的版本发生冲突。自定义数据属性旨在存储页面或应用程序的私有自定义数据。对这些属性的唯一要求就是它们不能用于像–moz-–webkit-这样的用户代理扩展(user agent extension)。

数据集(Dataset)API。自定义数据属性带来了dataset API。使用dataset API,你可以获得属性/值对,即使自定义数据属性的名称是动态生成的(即你不知道破折号后面的属性名称是什么)。

1              // get all the cards values and positions
2              // use dataset to get value for all the cards.
3              currCards = document.querySelectorAll('#board > div');
4              for (i = 0; i < qbdoo.cards; i++) {
5                  cardinfo.push(currCards[i].dataset);
6              }
7              currentState.cardPositions = JSON.stringify(cardinfo);

虽然我们记得已经设置了哪些属性,但当我们在暂停游戏前获取它们的值的时候,还将使用dataset API,而不是getAttribute()方法,目的就是为了讲授一下dataset API。来自qbdoo.pauseGame方法的代码片段使用了一个查询选择器(query selector)来获取所有的卡片(第3行),然后对所有卡片进行遍历,使用dataset API来获取以DOMStringMap形式表示的所有dataset属性的键/值对,并作为一个数组值存起来。最后一行(第7行)把我们已经获取的键/值对转换成了一个JSON字符串。或者,我们可能还已经遍历了整副牌:

1                for (i = 0; i < qbdoo.cards; i++) {
2                     for (key in currCards[i].dataset) {
3                       deck[key] = currCards[i].dataset[key];
4                  }
5                cardinfo[i] = deck;
6             }

Itemid、itemprop、itemref和itemtype

有5个与微数据(microdata)相关的其他全局属性被从HTML5规范的主体删除了,并且现在是微数据规范的一部分,包括itemiditempropitemrefitemscopeitemtype。我把它们包含在这里,这样就把所有的全局属性都罗列出来了。这些属性将在第6章的“微数据API”小节中进行讲解。

2.2 HTML元素/属性的语法

我们已经谈到了元素和属性,但我们还没有讨论如何把它们包含进来。语法是很重要的,所以让我们开始吧。

要在Web页面中包含一个元素,你要包含一个开始标记和一个结束标记。开始标记以一个左尖括号(或小于号<)开始,后面跟着元素名称,然后是右尖括号(或大于号>)。

正确:

<a>
<p>
<div>

错误:

<m> <!-- there is no 'm' element' -->
< div><!-- there can be no space before the element name -->

如果有属性的话,它们都包含在开始标记中,位于元素名称的后面,使用空格分开。所有的属性都是名称/值对。与XHTML不同的是,HTML5布尔型属性不需要被显式声明。在一个布尔型属性存在但值被忽略的情况下,浏览器默认为true

尽管HTML5没有提出要求,但为了便于阅读及符合最佳实践的要求,属性应该全部使用小写,同时属性的值应该全部用引号引起来。属性的值可能是大小写敏感的,这取决于属性的类型。

对于每个元素的开始标记来说,一个属性只能出现一次。虽然很可能你是知道的,而且也没有有意在一个元素中多次包含同一个属性,但这还是验证错误的一种常见情形,所以把这当作一个友情提示吧。

正确:

<a href="http://www.standardista.com" >
<p class="racket-tailed drongo">
<div id="content">

有效,但并非最佳实践:

<a href=http://www.yahoo.com>
<!-- best to quote all attribute values -->

无效:

<p class="racket-tailed" class="drongo">
 <!-- no duplicated attributes allowed. -->
<p class=Racket-Tailed Drongo>
 <!-- while HTML5 does not require quotes around all attributes, it is
best practice. And, if there is a space in the attribute value, the
quotes are required to unambiguously delineate the start and end of
the attribute's value! -->

要结束或者说是关闭一个元素,使用一个左尖括号和一个斜杠,后面跟着元素名称(与在开始标记中的元素一致)以及一个右尖括号。如果该元素是一个空元素(参见2.2.1节),你可以通过在紧挨开始标记的右尖括号前面添加一个可选的斜杠来结束元素:

<a href="http://standardista.com/mobile/ch2">Files for this chapter</a>
<p class="racket-tailed drongo">Exotic Asian Bird</p>
<div id="content">. . .</div>

元素的内容放在开始和结束标记之间,可能会包含其他元素以及文本节点。正确地嵌套元素!如果你把一个元素作为另一个元素的子元素包含了进来,嵌套的子元素的开始和结束都必须在父元素的关闭标记之前:

<div id="content">
 <p class="files">
  Examples in the <a href="http://standardista.com/mobile">
  online chapter resources</a>
 </p>
</div>

在上面这个例子中,<div>元素包含从第一个<到最后一个>的所有内容,包括了作为“后代”的段落(paragraph)和锚点(anchor)元素。注意,<a>元素的开始和结束都位于<p>元素的开始和结束标记内部,而且相应地<p>元素也在<div>元素内部开始和结束。

2.2.1 自闭合元素

所有元素都有结束标记,除了自闭合元素,也被称作空(empty)元素或空白(void)元素。按照XHTML语法,我们使用反斜杠来自闭合这些元素。

空元素不能包含嵌套元素或文本。作为自闭合元素,它们不能包含结束或关闭标记。如果你愿意的话,可以在开始标记的右尖括号前面包含一个斜杠。虽然HTML5并不要求元素一定要闭合,但XHTML语法却要求必须有一个结尾的斜杠。自闭合或空元素包括:

<img>       图像
<br/>       换行符
<meta/>    元数据
<hr/>      水平分隔线(thematic break)
<base/>    资源和链接的基准 URL 和默认目标
<link/>    外部链接<a href='#anchor25' id='ac25'><sup>[5]</sup></a>
<keygen/>  表单控件密钥对生成器
<area/>    图像映射中的区域(指的是带有可点击区域的图像)
<col/>     表格的列
<command/> 菜单命令
<embed/>   嵌入内容,如插件
<input/>   表单控件
<param/>   对象参数
<source/>  音频或视频的媒体源
<track/>   外部文本轨道,如字幕文件(Timed media tracking)
<wbr/>     单词换行时机(Word Break Opportunity)

2.2.2 最佳实践

有一些XHTML要求的编码规则在HTML中是可选的,甚至还不支持。虽然HTML5同时支持这两种编码格式,但还是有一些非必需的最佳实践:

标记使用小写

在XHTML中,元素标记和所有属性的名称必须全部小写。虽然HTML5支持驼峰命名(camelCase[6])以及其他形式,请使用全部小写的代码。在W3C中也没有任何地方规定属性的值需要小写,但有的属性的值,像id,是大小写敏感的,所以还是要坚持小写。

所有属性都用引号括起来

在XHTML中,所有属性的值必须使用单引号或双引号括起来。在HTML5中,只有属性的值包含空格或特殊字符的时候需要使用引号。让我快乐:把所有属性的值都用引号括起来。

闭合所有元素

在XHTML中,每一个开始标记必须同时有一个结束标记。像<img/><br/>这样的空元素必须是自闭合的。在HTML5中,有些标记可以不让它闭合。虽然省略结束元素可以减少页面上字符的数量,但它也会让你的代码难以阅读,从而更难以维护。有些演讲人/博客发文建议针对移动平台可以省略结束标记以减少字符数量从而生成更小的文件。节省的这些很少的字节并不值得带来的风险。减少DOM元素的数量比用这种方法减少字符数作用更大。让我高兴:闭合所有元素。

就用来关闭元素的末尾斜杠而言,你可以包括也可以忽略。选择哪种方式都可以,重要的是保持一致。

嵌套所有元素

所有标记必须正确地进行嵌套:如果你开始了一个<a>标记,然后开始或嵌套了一个<strong>,就必须在关闭</a>标记之前关闭</strong>标记。只要正确地嵌套标记:代码就会正常地渲染,除错也会变得更容易,而且代码也就会通过验证(还有,你会让我高兴)。

为所有非布尔型属性提供值

在XHTML中,所有的属性必须被编码为属性/值对,即使是布尔值。XHTML的selected的默认选项应该写成selected="selected"。在HTML5中,同样的代码可简写成selected。在HTML5中,给布尔型属性提供值不是必须的,因为包含状态属性就使一个布尔值为true,即使在大多数浏览器中该属性的值是false。不管你选择包含还是不包含布尔的值,都要让你的决定始终如一。如果你包含了布尔的值,就要总是包含它们。如果忽略的话,就要一直忽略。

对于一个布尔型(或甚至非布尔型)属性,不要包含一个空字符串="";可以总是包含一个值。

图像说明文字 

注意,如果你包含了一个布尔值,设成空字符串的话它将是true。如果希望是false,必须使用removeAttribute(attributeName)而不是setAttribute(attributeName,"),因为空字符串将导致布尔属性为true。

注意,空字符串可能会产生意外的结果,尤其是在涉及将在第3章出现的表单属性时。

针对任务使用语义上最合适的正确元素

在XHTML中,元素需要以语义的方式编码。表格和表单不能包含在段落中。表单元素,是短语元素,需要被包含在语义上的块级元素内部,例如段落或表格的单元格。是的,你可以使用span和div来包含页面上所有的东西,但是如果一个页眉就是一个页眉,则使用<h1-6>标记。

2.2.3 要素

元素是组成Web的构成要素(building block)。网站如果没有内容的话,CSS和JavaScript将无从增强。但实际上,一个Web页面要成为有效的XHTML只需要5个元素。

  •   文档类型声明,或DTD
  •   HTML根元素:<html></html>
  •   文档头,html的直接儿子:<head></head>
  •   文档标题,在head里面:<title></title>
  •   文档正文,html的直接儿子:<body></body>

换句话说,使用XHTML语法的有效HTML5文档的最低要求是:

<!DOCTYPE html>
<html>
  <head>
   <meta charset="utf-8"/>
   <title>Blank Document</title>
  </head>
  <body>
  </body>
</html>

我包括了charset &lt;meta>元素,如果你在服务器上正确设置了HTTP头的话,这个元素不是必需的。如果你对服务器没有控制权,则要把它当成必需的。

事实上,一个有效的HTML5甚至都不需要这么多元素。如果省略<html><head><body>的话,浏览器会隐式包含它们。最短且合理的HTML5文档实际是:

<!DOCTYPE html>
<title>Blank Document</title>

注意在图2-2中浏览器包含了那些缺失的标记。当忽略<html><head><body>或结束标记时,浏览器会正确地渲染文档,在渲染进DOM的时候会添加这些节点,并添加结束标记。

..\16-1116 图\0202.tif

图2-2 上面是HTML源码,下面是渲染出来的文档

是的,你可以把整个HTML5文档放进一条140字的微博里面。仅仅因为你可以省略一个页面上总共5个必需元素中的3个并不意味着你应该这样做。为了易读性和维护,尤其在是由其他人负责的情况下,选择一种编码风格并坚持下去:最好使用XHTML风格的语法编码,并包括这5个元素。

让我们看一下这5个“必需的”元素更细节的东西。

文档类型声明

文档类型声明(Document Type Declaration),doctype或DTD,告诉浏览器你使用的是哪种标记语法,这样浏览器就知道期望什么以及如何处理它。这个总是要发给浏览器的东西的第一行,如果作为XML解析的话,带着XML开端的例外。前一个例子使用HTML5的DTD,这个是最短的,而且是本书的点,但还是存在如表2-1所列的其他几种。

表2-1 HTML4、XHTML以及HTML5文档类型

页面类型

 

文档类型声明

HTML 4.01 Transitional

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional //EN" "http://www.w3.org/TR/HTML 4/loose.dtd">

 

HTML 4.01 Strict

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/HTML 4/strict.dtd">

 

XHTML 1.0 Transitional

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional// EN""http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional. dtd">

 

XHTML 1.0 Strict

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1- strict.dtd">

 

XHTML 1.1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

 

HTML5

<!DOCTYPE html> a

 

a.与HTML5的其他部分一样,doctype不区分大小写

虽然你可能有10年的XHTML DTD使用经验了,你可能还得把它拷贝粘贴到文档中,因为你仍然没有把它记住。我也是!在敲了一次HTML5 doctype之后,我再也没有再次查找它。

所有的现代移动浏览器支持所有的HTML和XHTML DTD,包括新的、更短的HTML5 doctype声明。

如果你担心旧代码会如何与新的HTML5 doctype相处,请放心[7]。如果你的Web页面作为HTML4或XHTML Strict验证通过,你的标记就是有效的HTML5。支持HTML5的浏览器应该提供对所有之前版本的HTML和XHTML的向后兼容,包括过时的元素。然而,仅因为已过时的元素被浏览器支持并不意味着你就应该使用!虽然<center><font>也许可以如预期般渲染,但是它们不能被当成有效或良好的代码[8]!为了确保一贯的整洁和可扩展的代码,我建议使用XHTML语法,包括把所有属性的值用引号括起来以及关闭所有元素。HTML5考虑到了懒惰的编码习惯,但不要做一个懒惰的编码者!

<html>元素

<html>元素是HTML文档的根元素。虽然它在HTML5中是可选的,但在使用XHTML语法时是必需的。HTML4 transitional不要求<html>元素,HTML5也不要求,但是我们希望编写良好、整洁且标准兼容的代码。所以,无论出于何种目的,它是必需的而且应该如表2-2所列的那样书写。

<html>有两个子嵌套其中:<head><body>。在HTML元素中包含lang属性是一个好的做法(但不是必须的)。

表2-2 HTML元素及页面类型要求

页 面 类 型

HTML元素

HTML 4.01 Transitional
HTML 4.01 Strict
HTML5

<html>
<html lang="en">

XHTML 1.0 Transitional
XHTML 1.0 Strict
XHTML 1.1

<html xmln="http://www.w3.org/1999/xhtml">
<html lang="en" xmlns="http://www.w3.org/ 1999/xhtml">

HTML5在<html>元素上提供了一个新属性。manifest属性,在包含了的情况下,把它的值作为manifest文件的URL。应用缓存、manifest文件和离线应用将在第6章讨论。

有些像modernizr的HTML5脚本工具会往<html>元素开始标记中添加一些类。这是完全合法的。算上应用缓存,用于特性检测的modernizr脚本,以及语言声明,我的<html>开始标记看起来往往是这样的:

<html lang="en" manifest="cache.appcache" class="no-js">

我们之前已经讲解了lang属性。第6章在讲解离线和存储时会讲到manifest属性。如果你使用modernizr<a href='#anchor29' id='ac29'><sup>[9]</sup></a>来测试本书讨论的各种Web技术的原生支持情况的话,应该包含no-js类。

<head>元素

文档的<head>包含了一些重要信息,除<title>元素之外,均不直接在浏览器窗口上显示[10]。虽然<head>的内容通常不显示,但是大部分浏览器会在标签或其他浏览器Chrome上显示标题,标题是一个有效的HTML5文档的唯一必需元素。<head>元素的其他内容告诉浏览器如何渲染页面,以及与搜索引擎爬虫关于页面内容进行“对话”。就HTML4和HTML5之间的变更而言,<head>元素中的profile属性从未被使用过,因此没有包含进提议的HTML5规范里面。

<head>是必需的<title>元素以及可选的<style><script><link><meta><base>元素的父元素。

<title>元素

<title>属性是必需的,而且必须包含</title>结束标记。你的页面没有head><body>甚至没有<html>标记都可以通过验证,但是如果没有必需的<title>就无法通过验证,而且如果结束标记缺失的话就无法解析。<body>可以是空的,并且对用户可以不显示任何内容。尽管<title>可以不包含任何文本,但它还是必需的。

<title>标签的内容应该是对文档综合内容的定义。虽然<title>可能好像对Web页面的布局并不重要,但是当涉及搜索引擎的时候,<title>是文档中最重要的元素。

注意<title>标记的内容是如何在浏览器Chrome中显示的,如图2-3所示。虽然与<title>在桌面环境上搜索引擎优化中的重要性相比,这可能不是一个重要因素,但是当你在手机的小屏幕上浏览的时候,它可能快速变丑,所以要谨慎地选择标题。

..\16-1116 图\0203.tif

图2-3 显示在iOS Safari和Firefox OS浏览器Chrome中的<title>元素内容

<body>元素

我们已经添加了<title>,但Web页面还是空白。你希望在网站上显示的所有内容需要放到页面的主体中,包含在唯一的<body>元素里面。<body><html>根元素的两个子元素中的第二个,也是最后一个元素。

body元素有一些外观类属性,在XHTML中是过时了的。HTML5赞同XHTML的这个机智传统:HTML5没有任何的曾经属于HTML4的外观类属性,像alignbgcolor,以及背景和链接配色,因为这些功能由CSS能够处理得更好。如果有必要的话,你能给<body>元素添加的属性应该只有idclasslangdir

在查看Web页面的源代码时,你经常会在<body>的开始标签中碰到事件处理器,例如 onload="doSomething();"。一般来说,你应该只添加像classid这样的全局属性到<body>开始标记中。事件处理器应该放在外部的JavaScript文件中,同时样式应该放在外部的CSS文件中。

我们的第一个最基本的HTML5文档应该像下面这样编码,唯一能注意到的差别是字符集和文档类型声明:

<!DOCTYPE html>
<html>
<meta charset="UTF-8"/>
 <head>
  <title> My First HTMLS Web Page </title>
 </head>
<body>
</body>
</html>

而且使用这6个元素(DTD、<html>根、<head><meta>字符集、<title>元素,以及<body>元素),我们已经创建了一个Web页面—— 一个空白的Web页面,但仍然是一个网页。而且,因为<title>元素中的相关内容,我们的空白网页比Web上的很多网站更容易被搜索引擎找到。

我之前提到,你甚至都不需要这么多的元素:

<!DOCTYPE html>
<meta charset="utf-8">
<title>我的第一个 HTML5 网页</title>
<p>Hello World

虽然这是一个有效的HTML5文档,但却不是好习惯。让你的代码更清楚,以后维护你代码的开发人员,包括你自己,就会更好地体会你的代码的原本意图。

2.2.4 存在于<head>中的元素

<head>可能是网页标记中最不诱人的部分,因为它默认对用户不可见。但是只是因为它不诱人并不意味着你就可以不重视它。在Web文档的头部分,作为一名开发人员,你可以告诉浏览器如何渲染你的页面,还可以在此为打印机、搜索引擎和解析器提供你的内容应该被如何处理的提示。

<head>中,你总能找到<title>,但你也可能会遇到<meta><base><link><script><style><command>以及<noscript>标记。

这里是一个非常饱满的头部区域可能的样子:

<head>
<meta charset="UTF-8"/>
<title>Mobile HTML5</title>
<meta name="author" content="Estelle Weyl"/>
<meta name="publisher" content="O'Reilly"/>
<meta name="copyright" content="Copyright 2013"/>
<meta http-equiv="date" content="Mon, 18 Nov 2013 16:15:30 GMT"/>
<meta http-equiv="date-modified"
    content="11/18/2013" scheme="MM/DD/YYYY"/>
<meta name="keywords" content="html5 css3 svg
    border-radius canvas audio iphone android ipad"/>
<meta name="description" content="Moving from desktop to mobile:
    Learning CSS3 and HTML5."/>
<meta name="pagetopic" content="Internet"/>
<meta name="page-type" content="Instruction"/>
<meta name="audience" content="all"/>
<meta name="robots" content="index,follow"/>
<meta name="generator" content="Sublime"/>
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<base href="http://www.standardista.com/"/>
<script src="/js/application.js"></script>
<link rel="apple-touch-icon" href="touch-icon-iphone.png"/>
<link rel="apple-touch-icon" sizes="72x72"
    href="touch-icon-ipad.png"/>
<link rel="apple-touch-icon" sizes="114x114"
    href="touch-icon-iphone4.png"/>
<link href="/css/prettification.css" media="all" rel="stylesheet"/>
<link href="/css/tinylittledevice.css" media="only screen and
    (max-device-width: 480px)" rel="stylesheet"/>
<link href="/css/print.css" media="print" rel="stylesheet"/>
<style>
     p {color: #333333;}
</style>
</head>

这是一个冗长的头部,而且你的永远不要看起来像这样子,但是你应该理解它。所以,让我们来看一下所有这些都是什么意思。

2.2.5 <meta>:添加元数据

<meta>元素能让Web开发者通过指定一个属性和一个值在页面上包含各种类型的元数据。<meta>有4个特有属性:charsethttp-equivcontentname

<meta charset="UTF-8" >

我们将涵盖的第一个<meta>元素是在你创建的每一个HTML5文档中最可能使用的:

<meta charset="utf-8"/>

你可能很长时间以来一直往文档添加:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

高速浏览器把页面作为HTML处理,以及在服务器的HTTP头没有设置字符集的情况下使用UTF-8字符集。

虽然<title>元素应该是<head>开始标记后面的第一个元素,但我们还是允许字符集声明这个例外,因为我们希望确保在字符得到渲染之前,渲染代理知道渲染哪一个charset。尽管是HTML5新增的,但下面这行代码还是在所有主流浏览器中都支持,因为浏览器一直支持错误地没有用引号括起来的meta

<meta http-euiv=Content-Type content=text/html; charset=utf-8>

注意,在这个书写错误的<meta>标签中,由于缺少引号以及content属性值中的空格,浏览器把charset看作一个单独的属性。这个从前的“错误”,因为实在是太普遍了,导致所有的浏览器都支持,现在是HTML5建议规范已经实现的部分。

你可以(或者说应该)使用UTF-8的方式从服务器上提供所有文件。如果你运行的是Apache,可以在.htaccess文件中添加一行AddDefaultCharset UTF-8

对于charset这个例外,<meta>标记的类型是通过name的值或是http-equiv属性的值定义的。除charset之外,每个<meta>标记必须包含namehttp-equiv属性以及一个content属性。

一个<meta>元素由name属性和content属性组成。一般来说,除非你正在试图生成一个HTTP响应消息头,否则这两个属性的值总的来说是自由的:你来创建name的值和content的值。我们将首先覆盖普遍存在的<meta>类型,然后再深入更移动特有的那些。

描述meta标记

有一些标准值,包括一个最重要的非移动特有的description。"description" <meta>标记的内容是那些许多搜索引擎返回的当你的网页被包含在搜索结果中时。所以,确保description的content值是一个与页面内容相关的符合语法规则的描述性的句子,包括关于页面的关键字(参见图2-4):

<meta name="description"
  content="CSS3, JavaScript and HTML5 as explained by Estelle Weyl">

..\16-1116 图\0204.tif

图2-4 显示Google搜索结果中的description <meta>标记的content

关键字meta标记

在所有的<meta>标记中,"keyword"是最知名的。然后,由于在上一个世纪垃圾邮件发送者对"keyword"meta标记的滥用,搜索引擎不会给其内容很高的评估值。你可以随意包括keyword元数据,但是对于你的搜索引擎的努力不要依赖它:

<meta name="keyword" content="CSS3, HTML5, JavaScript">

<meta http-equiv="…">

虽然使用name属性的<meta>元素是相当自由的,但http-equiv属性却不是。使用http-equiv属性来代替name,能够替换由服务器所创建的HTTP响应头。我在http:// www.standardista.com/html5/http-equiv-the-meta-attribute-explained/上创建了一个http- equiv&lt;meta>标记的值的列表。如果你在服务器上有权限访问.htaccess文件,则可以使用该文件来设置头。依赖于<meta>标记来设置头应该是你的最后一招,而不是优先考虑:

<meta http-equiv="cache-control" content="no-cache" />

2.2.6 移动meta标记

有一些<meta>标记特别适合移动设备。其中有些是让浏览器占据整个视区和禁止缩放以及改变状态栏颜色,这些都将在下面的各小节中讨论。

视口meta标记

在桌面环境上,除非你把浏览器窗口大小延展到超过显示器的边界,否则视口的大小就是浏览器窗口大小。在大多数移动设备上,页面缩放是可以控制的,但视口大小保持不变,由设备屏幕的尺寸所决定[11]

"viewport"<meta>标记能让我们在移动设备上支配浏览器窗口的逻辑尺寸及缩放。在我们的Web应用CubeeDoo里面,我使用了下面的meta标记:

<meta name="viewport"
content="user-scalable=no, width=device-width, initial-scale=1.0"/>

视口<meta>标记在所有的智能手机和移动设备上都支持,包括iOS、Android、webOS、Windows Phone以及Opera Mobile。通过设置视口宽度等于device-width,我们等于告诉浏览器把文档宽度设成设备宽度。

视口<meta>标记支持一个逗号分隔的指示列表,能让我们支配浏览器视口的宽度、缩放和高度。你可以告诉浏览器不支持缩放,或放大到某个最大值,或缩小到某个最小值。

width=<num>|device-width

一般来讲,你可能希望使用device-width关键词来把视口宽度设置成设备宽度,虽然数字值也是有效的。默认值依据浏览器各有不同,但一般都是980像素左右。最小值200,最大值10000。

height=<num>|device-height

设置成device-height,或者一个值,像iPhone 4及其更早版本就是480像素,定义视口高度。这个值一般是被忽略的,我赞成只使用宽度。参考起见,最小值是223。

user-scalable=no|yes

决定用户是否可以改变视口的缩放比例。设成yes是允许缩放,no是禁止缩放。默认是yes。设成no同时也阻止了在数据集上的滚动。用户缩放,如果允许的话,可以使用视口<meta>minimum-scalemaximum-scale属性进行限定。

initial-scale=<float>

设置用于查看网页的初始比例或缩放因子(或乘数)。默认值1.0不使用缩放来显示网页。

maximum-scale=<float>

除非user-scalable被设成no,否则设置用户放大的上限。最大值是10,但可以是浮点数0.25或更大的浮点数。

minimum-scale=<float>

设置用户缩放网页的下限。最小值是0.25。

大多数移动浏览器的渲染出来的默认宽度是980像素。通过把宽度设成device-width,用户就不需要在页面加载时放大页面,只是因为你在一个320像素的设备上提供的是980像素。我们也可以针对320像素把视区宽度设成320而不是device-width,但这样它就只能在正好320像素宽的设备上正常运行了。我们将把窗口的宽度设成设备宽度,这是最适宜的:它会相应于设备缩放页面,不需要作者必须知道用户可能使用的设备的宽度。

然而,这不是对所有网站都最适宜的,而是仅适合移动网站和移动Web应用。然后,在user-scalable被启用的情况下,用户可以放大页面从而让难以阅读的小字体变得清晰易读。

使用CubeeDoo,我们将创建一个移动游戏。在玩的时候,用户将触控屏幕。我们不希望用户在试图轻击标题的时候不小心把页面放大或缩小了,所以我们告诉浏览器让游戏全屏而且不允许缩放。我们一直在设计网站而不是一个app,为了更好的可用性,我们将允许用户无限制地缩放,我们在语言选择器中是这样做的:

<meta name="viewport" content="user-scalable=yes, width=device-width, initial-scale=1.0"/>

视口<meta>标记的功能就是上面说的这些,而从来不是任何规范的一部分;更确切地说,它是由Apple发起的一项特性。把这项功能从HTML标记转换到使用@viewport的CSS的规范正在顺利进行中,而且在IE10中已经部分支持。

2.2.7 移动厂商特有的值

还存在一些移动厂商特有的值。例如,Google和Apple为了与它们自己的一些服务/API相整合,已经创建了它们自己的名称/值对。我们已经在项目中使用3个这样的标记,将在下面的几个小节进行讲解。

apple-mobile-web-app-capable

这个<meta>标记显示的是“apple”,但在Android上也支持;它设定一个Web应用是否运行在全屏模式。当在全屏模式下运行的时候,不会显示任何浏览器边框。浏览器占据全部的屏幕,只显示手机的状态条。这个<meta>标记只会影响网站被加入收藏的Web应用。在我们的应用中包含了这个<meta>标记,这样如果用户选择收藏我们的应用的话,我们就可以使用尽可能多的屏幕空间:

<meta name="apple-mobile-web-app-capable" content="yes"/>

如果将content设成yes,Web应用就以全屏模式运行;否则不会。

你可以用JavaScript来判断网页是否以全屏模式显示,为此可使用window.navigator. standalone这个布尔型的只读属性。

apple-mobile-web-app-status-bar-style

正如前面已经指出的,即使在你使用apple-mobile-web-app-capable启用了全屏模式的情况下,状态栏仍然显示。这是在移动设备上开发者们无法删除的一个元素,即使是原生Web应用。然而很少有人知道,你是可以对状态栏的呈现进行一些控制的,即使只是极小的控制:我们可以使用apple-mobile-web-app-status-bar- style&lt;meta>标记影响它的颜色和透明度:

<meta name="apple-mobile-web-app-status-bar-style" content="black"/>

如果你的Web应用主要是黑色,让状态栏变得相匹配可以改善设计并让Web应用看起来更像原生应用。iOS对应的值是defaultblackblack-translucent。不幸的是(或者是幸好,考虑到某些人缺乏品味),目前你只有这些选择。

format-detection

format-detection动&lt;meta>标记启用或者禁用对网页上可能出现的手机号码的自动检测:

<meta name="format-detection" content="telephone=no"/>

默认情况下,有些设备会自动检测格式看起来像手机号码的字符串,没有链接的会自动创建,能够直接呼叫,或至少启动手机号码已经预先输入进去的手机应用。指定telephone="no"将禁用这项功能。在我们的应用中没有手机号码以及类似手机号码的任何事物,所以我们在应用中将不使用这个<meta>标记。

2.2.8 网页的<base>

虽然几乎从来没有用到,<base>在涉及本地测试时还是非常有用的。<base>元素为解引用(de-referencing)相对URL提供了一个基础。举个例子,假设你的代码中有一个像<img src="image/drongo.gif"alt="Meandering Racket-TailedDrongo"/>这样的相对路径的图像。通过包含<basesrc="http://RacketTailedDrongo. com"/>,浏览器会到RacketTailedDrongo.com服务器上的image目录寻找drongo.gif[12]

这个base URL可以使用HTTP头重写,但它通常用于本地测试。试着从Web上保存一个文件到你的硬盘,然后在文件的<head>中添加一个到源服务器的base指针。当你在本地打开页面时,页面很可能在桌面环境上正确渲染,即使该文件是一个本地文件,而且你从未下载图像或者修改页面body中的路径。该语法是:

<base href="http://www.mydomain.com"/>

2.2.9 <link>不仅用于样式

<link>元素没有获得称赞。它是一个强大且经常使用但却又很少被当回事的元素。<link>元素提供了在HTML文档和其他文档及资源之间定义关系的能力。<link>可被用于控制打印渲染、链接样式表和脚本、定义favicon,或者提供当前文档的替代形式。

我们的Web应用有4个link标记:

<link rel="icon" href="/appleicon.png"/>υ
<link rel="apple-touch-icon" href="/appleicon.png"/>
<link rel="apple-touch-startup-image" href="startup.png"/>
<link rel="stylesheet" href="styles.css"/>

υ IE需要添加rel="shortcut icon",在favicon没有被命名为favico.ico或者没有存储在网站根目录下的情况下,IE需要“shortcut”项。

<link>元素可以包括href、rel、type、size、hreflang、mediatitle等属性。在HTML5里面,rev和charset属性均被从<link>上剔除了。下面是语法:

<link href="url to resource" rel="type of relationship" title="title"/>

rel属性指明了从当前文档到由href属性指定的资源之间的命名关系(named relationship)。relhref属性都是必需的。

在4个<link>标记中,前三个用于图片,第四个也是你可能最熟悉的:到样式表的链接。

添加样式表<link>

这个短小精悍的<link>元素可以被用于给手机、平板电脑和桌面电脑发送不同的样式表。可以被用于根据任意类型手机的倾斜方向或用户浏览器的宽度提供不同的样式表。

尽管我们的Web应用只包含了一个样式表,但我们本可以包含几个的,每个都面向不同或重叠的媒体、浏览器大小、DPI,甚至浏览器朝向:

<link href="/css/styles.css" media="all" rel="stylesheet"/>
<link href="/css/tinylittledevice.css"
  media="only screen and (max-device-width: 480px)" rel="stylesheet"/>
<link href="/css/print.css" media="print" rel="stylesheet"/>

这些示例应该看起来很熟悉,可能有两点例外。注意下type="text/css"属性/值对没了。当前不存在其他类型的样式表语言(在可以预见的未来也没看到),所以HTML5就假定类型是text/css,并明确规定可以不写。此外,media="only screen and (max-device-width: 480px)"对你来说可能也比较陌生。我们将在下面的几个小节中把这个属性和<link>标记的其他属性一起快速讲解,并将在第7章深入有关媒体查询的细节。

<link>标记的属性

像几乎所有元素一样,<link>标记接受所有全局属性。表2-3显示的是<link>元素的其他属性。

表2-3 <link>元素属性

属  性

描  述

href

必选。“超链接引用(hyperlink reference)”是<link>目标文件的URL

media

描述将被包含的链接内容适用哪种媒体

rel

指定<link>和当前文档的关系

hreflang

被链接媒体的语言

type

被链接媒体的MIME类型。可选,除非该值不是rel关系希望的类型

sizes

新的。如果媒体是一个图标,则它定义了该图标的尺寸

media属性

media属性描述了将被包含的链接内容是针对哪种媒体。如果没有声明,默认是all,表明由href属性描述的源将一直出现。

media的值曾经相当有限,例如针对桌面环境的screen和针对打印机的print等。现在包括screen、tty、tv、projection、handheld、print、braille、auralall。现在你可以包括@media查询。media属性的值已经随着CSS3大大增加了。我们现在可以基于media属性更深奥的值提供不同的样式表。举个例子,移动设备的翻转和桌面浏览器的大小调整将把屏幕宽高比从纵向模式变成横向模式并再次返回,所以你可以相对于处于纵向模式和处于横向模式的不同情况下提供不同的CSS文件:

<link rel="stylesheet" media="all and  (orientation:portait)" href="prtrt.css"/>
<link rel="stylesheet" media="all and (orientation:landscape)" href="lndscp.css"/>

CSS3新的@media查询是media属性可以接受的值。在该属性的值中新近可以接受的关键词如下所列。

  • (min/max)-width:视区宽度。
  • (min/max)-height:视区高度。
  • (min/max)-device-width:屏幕宽度。
  • (min/max)-device-height:屏幕高度。
  • orientation:纵向模式(高>宽)|横向模式(宽>高)。
  • (min/max)-aspect-ratio:宽/高。
  • (min/max)-device-aspect-ratio:设备的宽/高。

曾经是HTML 4的一些<link>属性后来被从HTML5规范中剔除了,包括cords``、shape、urn、target、charset、methodsrev属性。此外,该元素的title属性具有特定的语义。

rel属性

rel属性指定了从当前文档到href属性指定的资源的命名关系。rel属性从规范上来讲是可选的,但如果你没有包含它,浏览器将不会正确地把资源链接到文档。没有rel="stylesheet"的样式表链接可能无法正确地呈现任何样式:浏览器将仅下载该文件,然后会想“唉,浪费带宽啊。”(是的,浏览器能够思考,而且还经常取笑我们。)表2-4把rel属性的一些值和这些值的释义一起列了出来。

表2-4 rel属性

rel属性值

释  义

stylesheet

rel属性最常用的值,告诉浏览器链接的文件应用于渲染当前文档的呈现
在包含stylesheet的情况下,type="text/css"不再是一个必需的属性/值对,因为text/css是样式表语言的唯一类型,从而是可以推断出来的

next

该链接指向一个引导性浏览或一个有序系列中的下一篇文档。该规范最初用来辅助后续文档的预加载,提升用户体验

prev

该链接指向一个引导性浏览或者一个有序系列中的上一篇文档

index

该文档的索引

help

该链接指向一个帮助文档(例如,对一个大背景的描述或者提供了与本文相关的更多链接),旨在帮助迷失方向的用户重定位

contents

链接到包含当前文档或网站目录的一个文档

alternate

指定该文档的一个替代版本。当与hreflang属性一起使用的时候,意味着链接的文件是该文档的一篇译文。当与media属性一起使用的时候,意味着链接的文件是一个媒体专用版本,例如打印机。当与stylesheet结合的时候,表示还有一个可供用户选择的备选样式表

copyright

指向该文档或网站的版权声明

glossary

包含当前文档所使用的术语定义的文档

icon

该页面或网站的网站图标(favicon)

apple-touch-icon

定义了当一个Web应用被用户收藏并添加到屏幕时,在用户屏幕上显示哪个图标

apple-touch- startup-image

在该Web应用启动时显示的启动图像。对离线Web应用尤其有帮助。如果没有包含该引用,有些浏览器会显示Web应用最后一次使用时的屏幕快照

Android和iOS都支持apple-touch-iconapple-touch-startup- image。Windows Phone使用图块[13](tile)而不是图标。要包含图块信息,添加:

<meta name="msapplication-TileColor" content="#<color>"/>
<meta name="msapplication-TileImage" content="<image reference>"/>

<style>

<style>元素提供了一种添加样式到文档的方法。与通过<link>元素导入的样式不同,包含在页面头中<style>标记中的样式只适用于当前页面,因而对于其他文档而言无法在缓存中直接读取使用。与在一个元素上使用style属性添加的样式也不同,该样式只影响该style属性所在的元素,除非支持了scoped属性,包含在<style>里面的样式适用于整个文档中相匹配的选择器。

<style>属性过去要求具有type属性(通常是type="text/css")。在HTML5中可以忽略,在这种情况下使用"text/css"值的type属性是隐式存在的。与像<link>标记一样,<style>也接受media属性。

scoped属性是HTML5新增的,但还没被任何浏览器支持。为<style>元素添加scoped属性就告诉渲染代理(rendering agent)在该范围或区段内查找样式,应用这些CSS。这对于你在非你控制的网站上创建小挂件非常有帮助,确保了针对小挂件的CSS不会不小心覆盖了宿主网站的CSS。

<style>和移动性能:标准反模式。在过去的12年里,一直都建议使用<link>而不是<style>来包含全站范围的样式。通过<style>来包含CSS可能会减少HTTP请求的数量,但它无法缓存。这显然不是最优的。

由于额外HTTP请求等待时间的问题,一个移动类反模式出现了。

为了减少等待时间,站点CSS被内嵌包含在主响应的一个或多个style标记内部。style代码块(block)被使用JavaScript提取并作为localStorage保存起来,并把key的值添加到了cookie字符串。额外的HTTP请求包含了带着在localStorage中存储的样式名称的cookie。在服务端,服务器读取该cookie,检查还需要哪些资源(如果有的话),然后只返回在localStorage中还没有的嵌入在第一个响应中的文件。这导致第一次请求的下载很大,而后续请求的下载就小得多,以及初始的网站加载和所有后续的网站重新加载都是单次HTTP请求和响应。

虽然这是一种反模式,但减少HTTP请求的数量可以大大地提升性能。性能的提升和发送相当数量的大文件(其内容无论如何都是必需的)及访问存储在localStorage中数据的代价相比完全更有价值。

添加<script>到网页

<script>标记能够让我们包含JavaScript代码块或链接到外部的JavaScript(或其他脚本类型)文件。type属性在XHTML中是必需的,而且几乎永远是type="text/javascript"。在HTML5中,type被假定为text/javascript。只要你的脚本是JavaScripttype属性就应该省略。还有,它的language属性也是过时的了。

在包含了src的情况下,该元素可能看起来像是空的,因为在开始和结束标记之间没有任何文本。总之要包含一个完整的结束标记,还有就是不要在这些标记之间放置任何JavaScript代码。

JavaScript性能小贴士。虽然我们正在讨论的是位于文档的<head>内的元素,但是在文档的<body><head>内部都能看到<script>元素的存在,而且有时候(其实是经常性地)body的末尾是<script>元素的最佳位置。

为什么?因为JavaScript通常会在一下载完就立刻被解析,会把它这一条通路上的文档下载挂起,直到该JavaScrip完成下载、解析和执行。这将使感觉上的页面下载时间大大变慢。基于这个原因,建议把脚本包含在接近文档末尾的地方,而不是在<head>中。

在页面所有元素花时间下载、解析和执行期间内,要把你的访客当成非JavaScript用户。难道你不愿让他们看到一些内容而不是一个空白屏幕吗?这就是为什么JavaScript性能以及源代码顺序很重要的原因。

有两个属性可以改变JavaScript的执行顺序:defer属性和async属性。都是布尔型,async是HTML5新增的。async表明该脚本变得可用时应该异步执行。defer表明该脚本应该在文档解析完成后再执行。如果任一属性都不存在,那么一遇到JavaScript就开始解析。两个属性都只对外部脚本有效,内置脚本无效。

如前所述,JavaScript是一碰到就立即解析(除非包含了asyncdefer,而且浏览器还支持)。浏览器会停止从服务器上下载另外的元素,直到JavaScript被完全下载、解析和执行。通过在文档末尾而不是头部包含JavaScript,感觉上的下载时间被大大缩短了。当脚本位于<head>中时,页面在加载和执行JavaScript的时候会挂起。把<script>放在页脚,虽然下载和执行脚本实际上会花费同样的时间,但因为没有明显的没有响应,所以感觉上是下载得更快了。

在HTML5中有一个新的解决方案,可以用于解决因为耗时的JavaScript引起的UI挂起问题。将在第6章进行描述的Web Workers,使JavaScript的多线程能够并发执行。动态生成脚本标签是提升性能的另一个技巧。

用户关闭JavaScript时——<noscript>

你可以包含一个<noscript>元素,该元素的内容只有在用户禁用JavaScript时可见。一般来说,最好渐进地增强页面的静态功能,让<noscript>成为过去就好。然而有一些项目经理坚决主张网站要完全依托JavaScript。在这种情况下,你可以在文档的body中使用<noscript>包含一个指南,告诉用户如何再次启用JavaScript。JavaScript在所有移动浏览器和其他现代浏览器中是默认启用了的,包括 mobile WebKi、Blink、Opera Mobile、Windows和Firefox。

元素之<body>

<body>永远是<html>元素的第二个也是最后一个子元素,第一个子元素是<head>。在浏览器主窗口中显示给用户的所有内容都存在<boby>元素里面。<head>包含了页面所有的元数据,<body>包含了所有可见(而且偶尔有一些不可见)的内容。

下一章讨论实际地显示到客户端的元素:<body>元素及其所有子元素。如前面讨论必需的元素时已经提到的,<body>元素没有元素特有的属性,但有很多事件处理器,包括:

  • onafterprint
  • onbeforeprint
  • onbeforeunload
  • onblur
  • onerror
  • onfocus
  • onhashchange
  • onload
  • onmessage
  • onoffline
  • ononline
  • onpopstate
  • onredo
  • onresize
  • onstorage
  • onundo
  • onunload

最好把这些事件处理器包含在外部JavaScript中,而不是在<body>元素中。我把它们包含在这里这样你就知道哪些是可用的,但我强烈建议并完全鼓励你保持内容和呈现分离,也与行为分离。

现在是时候关注在我们页面的实际内容了。


[1] 要查看改变了的元素和属性可参阅http://www.w3.org/TR/html5-diff/,另外还有过时了的元素和属性。

[2] 译者注:短语元素(phrase element)是内联元素的一种类型,用于在块或结构化元素中描述词或短语,主要是给文本片段添加结构化信息。每一种短语元素都表示一种特定的语义,例如<strong>、<blockquote>、<cite>、<code> 等。参见http://en.wikipedia.org/wiki/HTML_element#Phrase_elements

[3] 布尔属性是如果有赋值就是true,没有赋值就是false的属性。XHTML中的例子包括readonly=“readonly”、checked=“checked”以及disabled=“disabled”,这些在HTML5中可以(而且是应该)分别写成readonly、checked或者disabled。

[4] 译者注:指点设备,指的是可以在屏幕上控制指针的移动进行选择的设备,如鼠标、轨迹球、摇杆、触摸板和手写笔等。参见http://en.wikipedia.org/wiki/Pointing_device

[5] 译者注:例如,链接一个外部样式表。

[6] 译者注:参见http://en.wikipedia.org/wiki/CamelCase

[7] HTML5 DTD会使较旧的IE桌面浏览器进入非标准(quirk)模式。

[8] 过期特性请见http://bit.ly/16t5Z6L

[9] modernizr是一个JavaScript类库,用于在用户浏览器中检测HTML5和CSS3特性的浏览器支持情况。

[10] 使用CSS来显示<head>的内容是可行的。

[11] 在大多数小设备上,浏览器是自动全屏而且不是用户可改变的。在某些设备上,例如平板电脑,浏览器是可以调整大小的。

[12] 你想知道为什么我不断提到Racket-tailed Drongo吗?因为它就是本书封面上的鸟。

[13] 译者注:Windows Phone的图块,指的是“开始”屏幕上代表应用程序的图像。详见http://msdn. microsoft.com/zh-cn/library/windowsphone/develop/hh202948(v=vs.105).aspx

目录

相关技术