从 HTML5 的新特性概述开始,我们迅速转向实际示例。从那里,我们继续探索,一直到最前沿的实验。关于新的 HTML5 规范有很多要了解的地方。本书审查了规范摘录,并将其与当前使用的示例相关联。本书编织了丰富的理论、实用性、代码示例、屏幕截图、商业智慧和其他资源链接,这将使热心的开发人员一次又一次地回到它身边。HTML5 多媒体开发食谱是最新前端 Web 开发技术的必备指南。
不要听信唱衰者:HTML5 的许多方面已经准备好供我们使用。尽管有些人可能认为,没有遥远的日期可以开始使用这一系列新技术。事实上,下一代 Web 标记并不是遥远的梦想,它已经到来,准备好探索和使用。
没有网站可以存在没有至少一些简单的超文本标记语言。这种开放技术非常重要。如果你多年来一直在使用 HTML 创建和发布网站和应用程序,你可能会觉得自己已经掌握了这门语言。你已经知道语义标记的好处,内容、表现和行为的分离,以及无障碍问题,你对此已经很熟悉。事情可能会感到有点乏味。你已经准备好迎接新的挑战。
无论哪种方式,你的道路是清晰的:在你现有的 HTML 和相关技术编码能力的基础上,这本书将推动你的技能到下一个水平,并迅速让你创造出以前 HTML 无法做到的惊人的东西。
幸运的是,HTML5、大量的层叠样式表和一点 JavaScript,可以应对这些新挑战。Web 开发的最新创新使得这是在线出版商的新黄金时代。对于我们许多人来说,经历了一段低迷之后,我们现在迅速发现,为 Web 开发是再次有趣的!毕竟,HTML5 代表了进化 - 而不是革命。
在几个成功的知名客户项目中,我使用了一种自定义的 JavaScript 方法来部署 HTML5 的一些方面,并支持包括微软 Internet Explorer 6 在内的旧版浏览器。
当我们使用 HTML5 开发时,我们将语义命名的基本原则(将事物命名为它们是什么,而不是根据它们的外观命名)提升到一个全新的水平。这是使 HTML5 与其所有前身不同的关键因素。在本书的过程中,你会发现自己重新思考和优化许多你的代码命名约定。
尽管 Web 超文本应用技术工作组(WHATWG)提出的 HTML5 建议推荐计划直到 2022 年才全面实施,但由于前瞻性的浏览器制造商,没有理由你不能立即开始使用它,并获得更好的语义命名、增强的可访问性等诸多好处。
如果我们要使用 HTML5 构建新的令人兴奋的项目,我们需要为成功做好准备。毕竟,我们希望确保我们构建的内容对我们自己和我们的客户来说能够以可预测的方式显示和行为。让我们用一个代码编辑器和至少一个网络浏览器构建一个测试套件。
我们需要一些东西才能开始。至少,我们都需要一个代码编辑器和一个浏览器来查看我们的工作。经验丰富的专业人士知道我们实际上需要一系列反映我们受众使用情况的浏览器。我们想要以他们的方式看待事物。我们需要 以他们的方式看待事物。
许多网络开发人员说他们能够使用像 Microsoft Windows 的记事本或 Mac OSX 的 TextEdit 这样的纯文本软件编写代码。这很好,但尽管吹嘘,我们不知道有哪个网络开发人员实际上每天都这样工作。
相反,大多数人使用一些开发应用程序,比如 Adobe Dreamweaver(适用于 Windows 和 Mac)或 Aptana Studio(适用于 Windows 和 Mac 和 Linux)或 Coda(我个人偏好,仅适用于 Mac)或 TextMate(也仅适用于 Mac)。
为了使我们创建的代码正确呈现,我们需要一个网络浏览器 —— 可能不止一个。并非所有浏览器都是一样的。正如我们将看到的,一些浏览器需要一些额外的帮助来显示一些 HTML5 标签。以下是我们至少会使用的浏览器。
如果您在 Mac 上使用 OSX,苹果 Safari 已经安装。如果您是 Microsoft Windows 用户,Internet Explorer 已经安装。
幸运的是,Safari 和 Chrome 使用相同的 WebKit 渲染引擎。iPhone 和 iPad 的移动 Safari,以及 Android 移动设备的网络浏览器,都使用 WebKit 渲染引擎的一个版本。
我只是想告诉你我的感受。必须让你明白:微软多次改变和更新了其名为 Trident 的 Internet Explorer 渲染引擎,这让我们作为开发人员的生活相当困难。我们经常感觉自己在瞄准一个移动的目标。随着 Internet Explorer 10 的到来,似乎这种情况不会很快改变。
Camino(仅限 Mac)和 Opera(适用于 Microsoft Windows、Apple OSX、Linux 和移动设备)都是出色的替代浏览器,支持 HTML5 的许多功能。考虑将这些浏览器添加到您的测试套件中。
我们将使用渐进增强的概念来构建我们的页面,这意味着从纯 HTML 标记开始,然后添加 CSS 进行呈现,最后再添加一点 JavaScript 进行行为。我们听到的最好的类比之一是,基本的 HTML 就像黑白电视。添加 CSS 就像添加颜色,添加 JavaScript 有点像添加高清。
您还会注意到一个条件注释,检查用户是否在使用 Internet Explorer。如果是,我们告诉浏览器执行 Remy Sharp 的“HTML5 Shiv”脚本,这只是告诉 IE 要表现良好:<article>、<aside>、<audio>、<canvas>、<command>、<datalist>、<details>、<embed>、<figcaption>、<figure>、<footer>、<header>、<hgroup>、<keygen>、<mark>、<meter>、<nav>、<output>、<progress>、<rp>、<ruby>、<section>、<source>、<summary>、<time>、<video>、<wbr>
。
我们将为一位名叫 Roxane 的年轻开发者创建一个单页专业网页作品集。假设 Roxane 是一位有很多技能的才华横溢的网页开发者,就像你一样。她应该拥有一个与她的才华相称的专业单页作品集网站,你也一样。请随意在以下示例中用你的信息替换她的信息。
我们将添加主导航栏,就像我们经常在网页上看到的那样。这使用户可以轻松地在页面之间移动,或者在这种情况下,在同一个页面内移动。Roxane 想展示她的个人简介信息、工作样本以及联系方式,所以我们将使用这些作为我们的锚点。
要使用 HTML5 大纲,我们可以使用存储在本地计算机上的 HTML 或通过 URL 可见的代码。确保在此步骤中将我们一直在创建的代码保存在本地或上传到公共可访问的 Web 服务器上。
我们已经通过整理单页作品集网站的大部分内容做好了准备。虽然现在还不太时尚,但当我们在其上添加 CSS 时,它将真正地融合在一起,并且会像我们的想象力允许的那样时尚。
到目前为止,我们拥有的代码。它符合万维网联盟的 HTML5 和第五百零八部分无障碍测试。这个未经样式化的代码应该可以在任何现代网络浏览器上轻松查看,无论是在桌面上还是移动设备上。
作为一个实验,关闭代码中的“HTML5 Shiv” JavaScript 引用,看看各个版本的 Internet Explorer 如何处理我们的新 HTML5 标签。
在过去的 15 年左右,我们花了很多时间和精力抨击微软的 Internet Explorer,因为它缺乏标准支持,对盒模型的解释也有 bug。即将推出的 IE10 使我们更接近一个更统一的网络开发世界,但我们仍然需要数年的时间才能摆脱对 IE 的诅咒。
时间。我们为什么如此着迷?在网络上关注时间和日期的一个非常合理的原因是搜索引擎优化。SEO 曾经被视为一种只有黑帽巫师才能理解的神秘巫术,现在已经成为每个人在网上的责任。你花时间编写良好的代码,期望作家创作值得阅读的内容。现在再进一步,确保你的目标受众实际上能够找到你花时间创建的内容。新的<time>
元素只是搜索引擎吸引注意力到最新内容的方式之一。
不久以前,我们设计师和开发人员只能在文本中使用少数“网页安全”字体。如果我们想要在一个不被认为“安全”的字体中显示文本,我们就把它做成了图片。这很愚蠢,但我们别无选择。现在我们有了选择。字体终于在网页上得到了解放。
良好的排版对于任何设计都是必不可少的,而新的@font-face 功能让我们嵌入字体供浏览器使用。虽然技术上不属于 HTML5 的一部分,但这个 CSS3 属性太重要了,不容忽视。
对于这个配方,让我们找一个有趣的字体,并将其嵌入为一个简单的标志。下面你会找到一些链接,可以找到用于网页的免费和付费字体的几个很棒的网站。在这个例子中,让我们看看作者个人作品集的以前版本,网址是dalejcruse.com
。
浏览器在网页上显示时使用自己的专有字体文件。通过下载和引用每种可能的格式,我们确保现代浏览器如 Firefox、Chrome 和 Safari,以及传统浏览器如 Internet Explorer 甚至移动浏览器都能显示我们想要的字体。
曾经,似乎网络设计师和开发人员给每个视觉元素都添加了下拉阴影。几乎就像他们是按下拉阴影付费一样。幸运的是,那个时代已经过去了。今天,只有最时尚的设计师和开发人员知道如何非常节制地添加下拉阴影。让我们看看如何只使用 CSS 来做到这一点。
text-shadow CSS 属性在现代浏览器中显示一个微妙的黑色下拉阴影,向右移动一个像素,向下移动一个像素。虽然在作者的作品集网站上非常微妙,但如果我们将背景和字体颜色都设置为白色,效果会更加明显。
当背景和文本颜色都设置为白色时,我们在这里看到的只是向右移动一个像素,向下移动一个像素的黑色下拉阴影。由于 IE 不支持 text-shadow,这在该浏览器中将呈现为纯白色。这可能不是你想要的。
现代浏览器如 Chrome 2+,Firefox 3.1+,Opera 9.5+和 Safari 1.1+都支持 text-shadow CSS 属性。这首歌现在已经很老了,但可以说 Internet Explorer 不支持它。
你已经接受了以不同的方式思考 HTML 的挑战。接下来,你将被挑战扩展你的层叠样式表知识。除此之外,我们将挑战一些关于跨浏览器显示的假设。如果你和你的客户认为网站在每个浏览器中应该看起来一样,我们将改变一些想法。但如果你已经知道跨浏览器显示的谬误,你将成为帮助改变其他人想法的人。
我们中很少有人在无菌实验室中工作,我们对所创建的内容的显示具有 100%的创造控制。甚至更少的人有时间或意愿为每个浏览器创建单独的定制体验。肯定有一个中间的方法。有一句老话这位作者非常喜欢:
在这种情况下,事实是你将不得不与你的客户合作,无论他们是企业所有者,项目经理还是任何付钱让你为他们创建网站的人。但是,坐视这些人告诉我们如何做我们的工作的日子已经结束了。如果你知道有更好、更快、更高效的开发方式,你必须大声说出来。这是你的责任。如果你不这样做,没有人会为你说话。这对你不利,对你的客户不利,对整个行业也不利。不要成为那个人。
CSS 并不是 HTML5 规范的正式部分。事实上,它值得有一本自己的书。但在本章中,作者将向您展示其他人如何使用 CSS 应用视觉效果的真实示例,如将元素显示为块级,模拟导航栏,使用多个背景图像,应用圆角以及高级样式,如添加盒子阴影,并为 Internet Explorer 浏览器进行样式设置。
注意:我们应该将这个简短的样式放在一个外部样式表中,然后在我们网站的每个页面中引用它,而不是在每个页面的顶部内联显示它。最好只声明一次,然后让它在整个网站中生效,而不是一遍又一遍地重复。
出于某种原因,一些开发人员不想学习 HTML5。你会听到他们说出各种关于规范尚未准备好,在所有浏览器中都没有完全支持,以及需要像 CSS 或 JavaScript 这样的“黑客”来使其工作的无稽之谈。这都是无稽之谈。不要理会他们的抱怨。你真正听到的是恐龙灭绝的声音。如果恐龙决心通过自己的不作为来将自己灭绝,那就让它灭绝吧。只有强者才能生存。
我们并不是点燃了火。它一直在燃烧。自世界开始转动以来。杰弗里·泽尔德曼的《与糟糕的浏览器说再见》一文于 2001 年发表后,在 Web 开发界引起了轰动。在这篇文章中,泽尔德曼,现在被广泛认为是 Web 标准运动的奠基人,激励了一代又一代的网页设计师和开发人员使用 CSS 来进行网页呈现,并抛弃破损的旧版浏览器。阅读这篇开创性的宣言:alistapart.com/articles/tohell
。
这些破折号只是表示浏览器制造商正在进行的工作。请记住,HTML5 和 CSS3 是不断发展的规范。我们现在可以开始使用它们的元素,但完全支持还没有到位。就像我们在为未来做饭一样。
使用 CSS3,我们现在可以指定背景图像的大小。我们可以用像素、宽度和高度或百分比来指定这个大小。当您将大小指定为百分比时,大小是相对于我们使用 background-origin 指定的区域的宽度或高度的。
那么当我们在不支持 background-size 的浏览器中查看网站时会发生什么?在这里,我们可以看到 Internet Explorer 10 之前的版本无法拉伸背景图像,而是简单地用黑色填充剩余的画布。这是一个完美的例子,即使不是每个浏览器看起来都一样,但仍然提供了完全令人满意的用户体验。没有网站浏览者——即使是使用 IE6 的浏览者——都不能合理地抱怨他们没有按照作者的意图体验网站。
以前,像图像下方或周围的阴影这样的视觉效果只能通过使用第二个图像来实现阴影,或者将阴影本身作为图像的一部分来实现。问题在于,如果您想要调整阴影,就必须重新裁剪它。让我们看看使用 CSS3 的现代智能方法。
在为自己的项目创建样式表时,您可以完全控制创建一个 CSS 来统治它们所有,或者为移动和/或打印友好页面创建单独的定制体验。但是当您没有完全控制时会发生什么?这时,我们就需要像printfriendly.com
这样的工具来帮助我们。
现在显而易见,作者强烈主张为现代浏览器提供最佳的 CSS3 体验,让旧版本的 IE 随心所欲。如果在旧浏览器中某个元素缺少圆角或阴影,作者确实不在乎。但事实上,您的客户可能在乎。让我们打开潘多拉盒子,谈谈如何适应过时的浏览器。
到目前为止,我们已经谈了很多关于语义网页编码以及 HTML5 如何使我们能够将这种命名方法提升到以前无法达到的新水平。我们的讨论大部分集中在语义网页编码如何使我们作为网页开发人员的工作更加轻松、快速和有意义。
在本章中,我们将关注语义网页编码如何改善我们的受众在线体验。现在,应用语义标签——有意义的标签而不仅仅是表现性的标签——对于屏幕阅读器和依赖它们来浏览我们创建的网站、应用程序和接口的人来说变得更加重要。
与 HTML 或 CSS 验证不同,第 508 条验证方式不同。在 HTML 或 CSS 中,代码要么有效,要么无效。这是二进制的。但在第 508 条中,情况并非如此。在这种情况下,有三种不同级别的验证,每一级别都更难达到。
让我们从使用由 Faruk Ates 和 Paul Irish 开发的开源 Modernizr 项目开始。根据该网站,Modernizr 使用特性检测来测试当前浏览器对即将推出的特性的支持情况。
在你的标记中包含该脚本和简单的 body 类,可以使 Modernizr 检测浏览器支持的项目。然后它将添加类和 JavaScript API 来检测对某些功能的支持。如果给定浏览器不支持这些功能,Modernizr 就不会添加它们。
Modernizr 不做的是在浏览器中添加或启用本来不存在的功能。例如,如果您的浏览器不支持输入属性,Modernizr 不会自动为您的浏览器添加该功能。这是不可能的。它只是让您作为开发人员知道您可以使用什么。
有些 Web 开发人员使用 Modernizr,因为他们在某篇文章中读到他们应该使用它。这没问题,但你比他们聪明。您知道在浏览器中检测这些功能如何更好地告知您如何为不支持某些属性的浏览器提供可访问的体验。聪明又英俊的你!
跳过重复元素如导航的能力对于使用屏幕阅读器的人非常有益。想象一下,当访问网站时,您需要读取每个导航元素,然后才能继续查看主要内容。那会很烦人,不是吗?对于使用屏幕阅读器的人来说也是如此。让我们看看如何轻松地不让我们的一部分受众感到烦恼。
如果您不指定元语言,最糟糕的情况会是什么?什么都不会发生,对吗?错。事实证明,如果我们不指定元语言,我们的宿敌 Internet Explorer 的旧版本将尝试猜测您打算使用的语言。正如我们已经看到的,有时 IE 的猜测是错误的。根据这篇文章,无害的用户输入可能会变成活动的 HTML 并执行,导致安全漏洞:code.google.com/p/doctype/wiki/ArticleUtf7
。
调查一下您已经发布的具有辅助功能要求的项目。如果您仍然能够更新它们,这是一个重温它们并添加更多语义上有意义的标记的绝佳机会。记住:只是因为一个站点、应用程序或界面已经发布,这并不意味着您以后不能再次访问它。如果一个项目在发布时是一个失败,那么现在是更新它然后重新发布的绝佳时机。谁知道呢?它可能会变成一个完美的作品集,让您得到另一份工作!得分!
标签编码一个区域,那么你团队中的另一个开发者或将来在你的项目上工作的开发者将立即理解你的意图。作者曾经与一个开发者合作,他用毫无意义的命名,比如<div id="banana">
,用于与香蕉无关的东西。那个开发者认为这是一种通过成为唯一知道某些标签含义的方式来确保工作。不幸的是,当他几年后编辑他之前创建的东西时,这种方法对他来说变得痛苦,他无法记住它的含义。教训是什么?不要惹自己以后生气!
另请参阅
caniuse.com
提供 HTML5、CSS3、SVG 等在台式机和移动浏览器中的兼容性表。该网站是了解哪些新标签可以被支持的宝贵帮助。它不断更新,不仅值得收藏,而且值得一遍又一遍地参考。
提供备用站点视图
驻剑桥,马萨诸塞州的网站开发者伊桑·马科特创建了一种他称之为“响应式网页设计”的方法,以支持具有不同尺寸显示屏的台式电脑以及移动设备 - 所有这些都使用一个代码库。虽然这种方法并非必需,但可以视为朝着创建可访问体验的另一步。让我们更仔细地看看他的方法。
准备好了
马科特在 2010 年 5 月 25 日的《A List Apart》杂志上发表了这篇文章:alistapart.com/articles/responsive-web-design
。阅读这篇文章将让你提前了解本节的其余内容。
如何做...
让我们仔细看看 Jon Hicks 的作品集,网址为hicksdesign.co.uk
,这是 Marcotte 方法的一个出色示例。
Hicks 在 27 英寸显示器上以全宽度看到的作品集。
调整窗口大小会导致网站从四列变为三列:
进一步调整窗口大小会导致网站从三列变为两列:
进一步调整窗口大小会导致网站从两列变为一列:
它是如何工作的...
通过在样式表中使用灵活网格以及min-width
和max-width
值,Hicks 创建了一个可以轻松适应不同显示尺寸的体验。让我们看看它是如何做到的。
还有更多...
这种新的灵活的前端网页开发方式使我们能够创建体验,无论设备分辨率如何都能正常工作。多亏了 Marcotte,我们不再被迫为每个设备创建单独的体验。当前状态:一次编码,到处显示。
我们从一个流动网格开始,列可以适应任何可用的屏幕空间,灵活的图像,并让媒体查询根据分辨率和视口提供独特的样式表。
这是一个样本媒体查询:
@media screen and (max-width: 600px) {
body {
font-size: 80%;
}
#content-main {float: none; width: 100%;}
}
你可以很容易地看到,我们说的是当设备的最大宽度为 600 像素时,我们告诉body
以 80%的高度显示字体。我们还指定 content-main div
将是一个 100%宽度的单列。如果设备的最大宽度是 601 像素或更多,这些规则将被忽略。请注意,由于这个媒体查询指定了屏幕,如果用户打印页面,这些规则也将被忽略。
最小宽度
正如你可以想象的,如果我们能够为这样的窄宽度指定样式,你也可以为更宽的宽度指定其他样式,比如:
@media screen and (min-width: 1024px)
请注意,我们仍然在媒体查询中针对屏幕进行定位,但现在我们说的是只有视口大于 1024 像素时才应用一些样式。
我的数学老师是对的
那些习惯于使用像 Grid960 这样的固定网格布局系统的人可能会发现使用灵活网格一开始是一种心理挑战。正如 Marcotte 所解释的:
“网格的每个方面,以及放置在其上的元素,都可以相对于其容器表达为比例。”
我们可以将基于像素的宽度转换为百分比,以保持比例不变,无论显示的大小如何。让我们从一个简单的例子开始:假设我们的header
宽度为 600 像素,我们想在一个宽度为 1200 像素的设备上显示它。如果方程式是目标÷上下文=结果,那么 600÷1200= .5。我们的 CSS 看起来像这样:
header {width: 50%; /* 600px / 1200px = .5 */}
那很容易。但是如果你想在 960 像素宽度上显示一个不同的header
,宽度为 510 像素呢?简单的除法给我们留下了这个:510÷960= .53125。我们可以这样调整我们的 CSS:
header {width: 53.125%; /* 510px / 960px = .53125 */}
通过将每个宽度定义为整体的一部分来重复这个过程,你将在通向多种设备的响应式显示的道路上取得很大进展。
更大总是更好吗?
流动图像更容易,因为没有数学可做。相反,只需包括:
img {max-width: 100%;}
在你的样式表中,这些图像将永远不会超出你的显示或设备的宽度。
将这三种技术结合在一起可以为多个平台、浏览器甚至屏幕阅读器上的用户创建一个几乎无缝的网站体验。
另请参阅
2011 年,Marcotte 在books.alistapart.com/products/responsive-web-design
上发表了关于响应式网页设计的权威书籍。
使用 hgroup 创建可访问的标题区域
记得hgroups
吗?当然记得。我们在前一章中看过它们,作为一种逻辑上组合相关标题标签的方法。现在,我们将看看这个新的 HTML5 元素如何具有附加的可访问性益处。
准备工作
之前,我们以 Roxane 的作品集为例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Roxane</title>
<!--[if lt IE 9]><script src="img/html5.js"> </script>[endif]-->
</head>
<body>
<header>
<hgroup>
<h1>Roxane is my name.</h1>
<h2>Developing websites is my game.</h2>
</hgroup>
</header>
</body>
</html>
在过去,我们可能会这样编写她网站的主体区域:
<body>
<div>
<div>
<h1>Roxane is my name.</h1>
<h2>Developing websites is my game.</h2>
</div>
</div>
</body>
如何做...
对于屏幕阅读器来说,过时的第二个示例在语义上毫无意义。它不知道那些标题标签除了在同一个div
中之外,还有其他任何相关性。
它是如何工作的...
现在,由于 WHATWG 的 HTML5 草案标准在whatwg.org/html5
,我们和屏幕阅读器都明白hgroup
是相关标题的分组。那又怎样,你会问?如果你不能依靠视力知道这些标题是相关的,难道你不希望有其他机制 - 比如屏幕阅读器 - 告诉你它们是相关的吗?
另请参阅
diveintoaccessibility.org
是一个了不起的 30 天逐步资源,可以更多地了解 508 部分和可访问性标准。作者 Mark Pilgrim(也是diveintohtml5.org
的* Dive Into HTML5*作者)提供了易于理解的技巧,可以按人员,残疾,设计原则,Web 浏览器和发布工具分类。该网站已经存在几年了,但由于多年来可访问性标准并没有发生太大变化,因此仍然是一个宝贵的免费资源。
为不支持的浏览器显示替代内容
一些新的 HTML5 元素是如此新,以至于并非所有桌面浏览器都支持它们。那么我们怎么能假设所有屏幕阅读器都会支持它们呢?
准备就绪
幸运的是,我们可以放心地认为屏幕阅读器将支持常见的文本标签,如:
<h1>
<h2>
<h3>
<h4>
<h5>
<h6>
<p>
<ul>
<ol>
<li>
<dl>
<dt>
<dd>
以及其他预期的内容。但是对于那些新的 HTML5 元素呢,比如:
<article>
<aside>
<audio>
<canvas>
<datalist>
<details>
<figcaption>
<figure>
<footer>
<header>
<hgroup>
<mark>
<meter>
<nav>
<output>
<progress>
<section>
<summary>
<time>
<video>
这些是否会按我们的意图传达给用户?如果是,那太棒了。但如果不是,用户会得到什么信息?这是否有意义?当然,我们会同意我们最不想做的事情就是通过我们的新标签提供更少的含义。即使盲人也能看到这将是一个史诗般的失败。
如何做...
在撰写本文时,许多 HTML5 元素至少提供了与屏幕阅读器相同数量的语义信息。让我们更具体地看看每个新元素:
<article>
- 与div
具有相同的语义信息。
<aside>
- 与div
具有相同的语义信息。
<details>
- 与div
具有相同的语义信息。
<figcaption>
- 与div
具有相同的语义信息。
<figure>
- 与div
具有相同的语义信息。
<footer>
- 与div
具有相同的语义信息。
<header>
- 与div
具有相同的语义信息。
<hgroup>
- 与div
具有相同的语义信息。
<meter>
- 与div
具有相同的语义信息。
<nav>
- 与div
具有相同的语义信息。
<output>
- 与div
具有相同的语义信息。
<progress>
- 与div
具有相同的语义信息。
<section>
- 与div
具有相同的语义信息。
<summary>
- 与div
具有相同的语义信息。
然而,对于其他新的 HTML5 元素,它们的含义对于屏幕阅读器来说并不那么清晰:
<audio>
- 语义信息似乎是一致的,但 Firefox 在内置滑块控件上存在问题,Internet Explorer 9 只有部分播放/暂停支持,Opera 具有良好的键盘支持,但没有实际的辅助技术支持。
<canvas>
- 几乎不提供可用的语义信息来辅助技术。任何依赖新的 HTML <canvas>
元素传达信息的人都必须极度谨慎。故意使用它会让观众无法进入。
<datalist>
- 仅在 Opera 中可通过键盘访问。
<mark>
- 不提供额外的语义信息。
<time>
- 仅在 Opera 中存在键盘访问的问题。
<video>
-语义信息似乎是一致的,但 Firefox 在内置滑块控件上有问题,Internet Explorer 9 只有部分播放/暂停支持,Opera 具有良好的键盘支持,但没有实际的辅助技术支持。
它是如何工作的...
目前,直到屏幕阅读器能够跟上所有新的 HTML5 元素,我们在决定使用哪些新标签以及我们打算用它们传达什么含义给使用辅助技术的人时必须小心。
另请参阅
艾米莉·刘易斯对 HTML 和 CSS 以及可用性、语义和可访问性都感到兴奋。她是我们需要更多的热情倡导者,以使前端网页开发世界蓬勃发展。请查看她出色的“Web Accessibility and WAI-ARIA Primer”,了解如何开始思考可访问性的未来,网址为msdn.microsoft.com/en-us/scriptjunkie/ff743762.aspx
。
使用 WAI-ARIA
通过使用技术,我们已经开发出了在浏览器窗口中动态更新信息的方法,而无需手动从服务器刷新页面。对于有视力的人来说,这是一个福音,可以更快地检索信息并以更有用的方式呈现。但是当一个人看不见时会发生什么?他们如何知道页面上的信息已经以任何方式更新,而无需刷新页面,重新显示其内容,并让辅助技术再次完整地读给他们听?
准备就绪
可访问的富互联网应用程序(WAI-ARIA)是一项新兴的技术规范,与 HTML5 的许多新语义标签一样,迫使我们真正思考我们的内容以及我们想要如何向受众呈现它。我们可以使用 WAI-ARIA 来定义角色、属性和状态,以帮助我们定义我们的元素应该做什么。
基于 Marcotte 的响应式 Web 设计方法的 WAI-ARIA 概述,网址为w3.org/WAI/intro/aria
。
如何做到...
还记得我们在 Roxane 的作品集中包含了新的 HTML5 nav
元素吗?以下是我们如何使用 WAI-ARIA 添加额外含义的方法:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Roxane</title>
<!--[if lt IE 9]><script src="img/html5.js"> </script>[endif]-->
</head>
<body>
<header>
<hgroup>
<h1>Roxane is my name.</h1>
<h2>Developing websites is my game.</h2>
</hgroup>
</header>
<nav role="navigation">
<ul>
<li><a href="#About">About</a></li>
<li><a href="#Work">Work</a></li>
<li><a href="#Contact">Contact</a></li>
</ul>
</nav>
</body>
</html>
因为并非每个浏览器都理解nav
标签,也并非每个浏览器都理解它的角色。WAI-ARIA 为我们提供了这样做的方法。role="navigation"
被称为“地标角色”,对于一个无视力的人来说,它就像现实世界中的实际地标一样:它让他们知道自己在哪里。
它是如何工作的...
现在,即使没有视力的人也可以通过这些地标角色知道页面上的变化。WAI-ARIA 通过“监视”更新来通知用户这些动态页面变化。而不是重新阅读整个屏幕,只呈现新信息。
还有更多...
WAI-ARIA 允许我们创建复杂的、数据驱动的对象,如下拉菜单、选项卡、滑块、文件树等,这些是有视力的用户多年来习惯的,并且通过使用这些角色,即使那些无法看到内容更新的人也会被通知它已经这样做了。
仍在等待浏览器支持
总是有一个陷阱,对吧?在这种情况下的陷阱是,与本书中描述的许多其他 HTML5 功能一样,WAI-ARIA 并不是所有辅助技术浏览器完全支持的。无论我们作为开发人员多么勤奋和善意,如果我们的目标受众没有具有 WAI-ARIA 支持的最新浏览器,他们将无法获得我们希望他们获得的信息。
这就是我的角色
还有一个问题:错误地使用 WAI-ARIA 实际上可能会使情况变得更糟。如果比你水平低的开发人员将role="navigation"
分配给一些经常更新但允许用户跳过导航的内容,那么用户将永远不会知道信息正在更新。幸运的是,这可能永远不会发生在你身上,因为你会在同行代码审查中发现这个错误。伟大的力量伴随着巨大的责任。
首要考虑无障碍
如果您正在开发网站,并且需要支持残障人士,就必须从最初的启动会议开始非常小心,以确保满足他们的需求。最具可访问性的成功项目是从一开始就考虑人们的需求。试图在最后添加一系列功能只会让自己和项目失败。我们要么让人们和项目成功,要么让它们失败。你会选择哪一个?
另请参阅
要了解如何使用 WAI-ARIA 构建更具可访问性的网络,请阅读 Scott Gilbertson 的这篇出色的 WebMonkey 文章:webmonkey.com/2010/11/can-wai-aria-build-a-more-accessible-web
。
吉尔伯特森后来写了一篇关于使用 ARIA 角色为网站设计样式的绝妙资源:webmonkey.com/2011/01/styling-webpages-with-arias-landmark-roles
。
第五章:学会爱上表单
在本章中,我们将涵盖:
显示占位符文本
向表单字段添加自动对焦
使用 HTML5 和 CSS3 样式化表单
使用电子邮件输入类型
使用 URL 输入类型添加 URL
使用数字标签
使用范围标签
创建搜索字段
创建一个选择器来显示日期和时间
介绍
“我们已经遇到了敌人,他就是我们自己。”-波戈
无聊。乏味。无聊。为什么当在线交互表单呈现给网络用户时,他们的眼睛会变得无神和心智麻木?这位作者认为问题至少部分在于安排表单字段的信息架构师,以及在较小程度上编码它的前端开发人员。
诚然,表单并不性感。但是如果你是一个网页开发人员(如果你正在阅读这篇文章,很可能你是),那么你的职业生涯中某个时刻很可能被要求标记和样式化某种形式的表单。如果你厌恶编写那个表单,想象一下你在用户中创造的恐惧程度。现在结束了。
你已经成熟,并寻求值得这种成熟的新挑战。如果我们能停止担心并学会爱上表单,那么我们的观众实际上也更有可能喜欢它们。
在本章中,我们将看一些 HTML5 用于交互式表单的实际示例,包括显示占位符文本,向表单字段添加自动对焦,使用 HTML5 和 CSS3 样式化表单,使用电子邮件输入类型,使用 URL 输入类型添加 URL,使用数字标签,使用范围标签,创建搜索字段,以及创建一个选择器来显示日期和时间。
现在让我们开始吧!
显示占位符文本
我们要检查的第一个新的 HTML5 表单功能是本地显示占位符文本的能力。
如何做...
我们都曾使用过 - 甚至创建过 - 表单占位符文本。但现在有了 HTML5,我们将以稍有不同和更高效的方式来做。Packt Publishing 网站具有搜索整个网站或仅搜索书籍/电子书的功能。
!如何做...
一旦用户点击这两个表单字段中的一个,占位符文本就会消失。
!如何做...
这是通过使用值属性来显示占位符文本的传统方法:
<form action='/search'>
<div id="search-site">
<input type="text" class="form-text" name='keys' value="Search entire site" onclick='clearIf(this, "Search entire site")'/>
</div>
<div id="search-button-site">
<input type="image" src="img/search- button.png">
</div>
</form>
<form action='/books'>
<div id="search-books">
<input type="text" class="form-text" name='keys' value="Search only books/eBooks" onclick='clearIf(this, "Search only books/eBooks")'/>
</div>
<div id="search-button-books">
<input type="image" src="img/search- button.png">
</div>
</form>
使用placeholder
属性而不是value
的结果是:
<form action='/search'>
<div id="search-site">
<input type="text" class="form-text" name='keys' placeholder="Search entire site" onclick='clearIf(this, "Search entire site")'/>
</div>
<div id="search-button-site">
<input type="image" src="img/search- button.png">
</div>
</form>
<form action='/books'>
<div id="search-books">
<input type="text" class="form-text" name='keys' placeholder="Search only books/eBooks" onclick='clearIf(this, "Search only books/eBooks")'/>
</div>
<div id="search-button-books">
<input type="image" src="img/search- button.png">
</div>
</form>
它是如何工作的...
placeholder
属性可以取代value
属性在表单中显示占位符文本。在这种情况下,开发人员添加了一个onclick
事件处理程序来适应旧的浏览器。这是另一个例子,优秀的语义增加了标签的额外含义。
还有更多...
记住 - 并计划 - 当用户点击每个表单字段时,占位符文本本身将消失。如果用户在不填写表单字段的情况下点击离开,placeholder
将重新出现。
仅文本
placeholder
属性只能包含文本。我们不能在其中包含其他标记、图像或任何其他元素。
拥抱斜体
默认情况下,占位符文本将以斜体显示。不幸的是,没有好的方法可以更改这一点。与其对着墙撞头,不如事先知道这一点,并说服你的设计师,文本应该 是斜体,并让他专注于真正重要的事情。
浏览器支持
支持新的placeholder
属性的 Web 浏览器。
!浏览器支持
另请参阅
Build Guild 是全国网页人员的每月聚会。使用 HTML5(并使用占位符属性!)在buildguild.org
建立,开发人员可以每隔几周聚在一起喝酒聊天。已经在城市建立了本地分会,例如:德克萨斯州阿比林;纽约州奥尔巴尼;蒙大拿州比灵斯;密歇根州大急流城;康涅狄格州哈特福德;肯塔基州路易斯维尔;威斯康星州密尔沃基;纽约市;宾夕法尼亚州费城;宾夕法尼亚州匹兹堡;密苏里州圣路易斯;马萨诸塞州塞勒姆。
如果您所在地区还没有 Build Guild,请创建一个!联系buildguild.org
的网站所有者开始!胡子是可选的。
向表单字段添加自动对焦
过去,我们不得不依赖 JavaScript 来为特定的表单字段添加输入焦点,但现在不再需要了!现在我们可以在 HTML5 中本地实现它的能力!
如何做...
Ally Creative 在allycreative.net/contact
有效地使用了他们联系表单中的autofocus
能力。
它是如何工作的...
他们是这样做的:
<form action="" method="post">
<ol id="left">
<li>
<label for="contact-name" class="label-fade">Jane Doe of ACME Corporation</label>
<input type="text" id="contact-name" name="contact-name" title="Name / Business" autofocus /></li>
<li>
<label for="contact-mail" class="label- fade">jane.doe@acme.com</label>
<input type="text" id="contact-mail" name="contact-mail" title="E-mail Addy" /></li>
<li>
<label for="contact-phone" class="label-fade">541 / 567- 5309</label>
<input type="text" id="contact-phone" name="contact-phone" title="Phone Number" /></li>
<li>
<label for="contact-budget" class="label-fade">Project Budget</label>
<input type="text" id="contact-budget" name="contact-budget" title="Budget" /></li>
<li><input type="hidden" id="contact-human" name="contact-human" title="Human" /></li>
</ol>
<ol id="right">
<li>
<label for="contact-subject" class="label-fade">Subject</label>
<input type="text" id="contact-subject" name="contact-subject" title="Budget" /></li>
<li>
<label for="contact-body" id="textarea-label" class="label- fade">Say something.</label>
<textarea id="contact-body" name="contact-body" title="Contact Copy"></textarea></li>
<li class="f-right"><span id="required"></span> <input type="image" src="img/button.png" id="submit-button" alt="Submit!" /></li>
</ol>
</form>
通过将autofocus
属性应用于联系人姓名的表单字段,并添加适当的样式来更改背景颜色,Ally Creative 的开发人员创建了一个流畅、互动的表单,用户可以轻松完成。
还有更多...
新的 HTML5 autofocus
属性旨在适用于所有表单控件。因此,无论您是收集用户的姓名、地址、电话号码还是其他数据,都可以聪明地使用autofocus
的能力!
每页一个
请记住,每页只能设置一个表单字段为autofocus
。
旧版浏览器
一会儿,您将看到目前只有两个现代浏览器支持autofocus
。幸运的是,旧版浏览器只是忽略这个属性。考虑到像autofocus
这样的工具可以丰富那些能够看到它的用户体验,而不会损害或降低那些使用较差浏览器的用户体验。无害,无犯。
浏览器支持
支持新的autofocus
属性的 Web 浏览器:
另请参阅
Mozilla 的“HTML5 的人”视频系列展示了 HTML5 运动的许多领军人物。Remy Sharpe,我们在其他地方检查和使用的“HTML5 Shim ”的作者,是一位 JavaScript 工匠。当他描述新的 HTML5 规范的最喜欢的方面时,这应该不足为奇:
“对我来说,HTML5 最令人兴奋的方面是 JavaScript API 的深度。向 Joe Bloggs 解释这个新规范的 HTML 实际上并不是大部分 HTML,而是大部分 JavaScript 是相当棘手的。”
阅读并观看完整的采访:hacks.mozilla.org/2011/01/people-of-html5-remy-sharp
。
使用 HTML5 和 CSS3 样式表单
作者见过的使用 HTML5 和 CSS3 制作表单的最简单但最美丽的例子之一是总部位于加拿大的 FoundationSix 在:foundationsix.com/contact
。他们是这样做的。
如何做...
FoundationSix 团队从一个相当简单的联系表单标记开始。请注意,出于空间考虑,这个示例中省略了冗长的国家下拉列表。
它是如何工作的...
<form id="contactf6" method="post" action="http://foundationsix.com/index.php" enctype="multipart/form-data" >
<fieldset id="contactinfo">
<ul>
<li>
<label for="name">Name</label>
<input id="name" name="name" type="text" class="required">
</li>
<li>
<label for="email">Email</label>
<input id="email" name="email" type="text" class="required email">
</li>
<li>
<label for="website">Website</label>
<input id="website" name="website" type="text" class="required">
</li>
<li>
<label for="country">Country</label>
<select id="country" name="country" class="selectors">
<option selected value="">Please Select...</option>
</select>
</li>
</ul>
</fieldset>
<fieldset id="natureinfo">
<ul>
<li class="selectli">
<label for="nature">Nature</label>
<select id="nature" name="nature" class="selectors">
<option selected value="Get A Quote">Get A Quote</option>
<option value="Get More Info">Get More Info</option>
<option value="Say Hello">Say Hello</option>
</select>
</li>
<li class="selectli showmore">
<label for="scope">Scope</label>
<select id="scope" name="scope" class="selectors">
<option selected value="">Please Select...</option>
<option value="Complete Website Design">Complete Website Design</option>
<option value="Design Only">Design Only</option>
<option value="Coding Only">HTML / CSS Coding Only</option>
<option value="Other">Other</option>
</select>
</li>
<li class="selectli showmore">
<label for="budget">Budget</label>
<select id="budget" name="budget" class="selectors">
<option selected value="">Please Select...</option>
<option value="$2,500-$5,000">$2,500-$5,000</option>
<option value="$5,000-$7,500">$5,000-$7,500</option>
<option value="$7,500-$10,000">$7,500-$10,000</option>
<option value="$10,000-$15,000">$10,000-$15,000</option>
<option value="$15,000-$20,000">$15,000-$20,000</option>
<option value="$20,000-$50,000">$20,000-$50,000</option>
<option value="$50,000+">$50,000+</option>
</select>
</li>
<li class="selectli showmore">
<label for="timeframe">Timeframe</label>
<select id="timeframe" name="timeframe" class="selectors">
<option selected value="">Please Select...</option>
<option value="Right Away">Right Away</option>
<option value="Within 1 Month">Within 1 Month</option>
<option value="Within 2 Months">Within 2 Months</option>
<option value="Within 3 Months">Within 3 Months</option>
<option value="Within 6 Months">Within 6 Months</option>
<option value="Don't Know Yet">Don't Know Yet</option>
</select>
</li>
</ul>
</fieldset>
<fieldset id="message">
<ul>
<li>
<label for="messagetext">Message</label>
<textarea id="messagetext" name="message"></textarea>
</li>
</ul>
</fieldset>
<div id="submitbutton"><input type="submit" name="submit"></div>
</form>
团队为这个联系页面提供了一个特殊的样式表。请注意它是多么干净,只定义了必要的值,而省略了任何多余的东西。
html {
background: url(../img/sitebg.jpg) repeat; -webkit-font-smoothing: antialiased;
}
body {
color: #8a8a8a; font: 13px/19px "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif; background: url(../img/subbg.jpg) repeat-x;
}
#contactform {
float: left; width: 498px; margin-bottom: 40px;
}
#formtop {
height: 97px; width: 498px; background: url(../img/formtop.png) no-repeat;
}
#formtop h1 {
text-indent: -9999px; width: 445px; height: 57px; margin: 0 auto; background: url(../img/formheader.png) no-repeat; position: relative; top: 39px;
}
#formcontent {
background-image: url(../img/formrepeat.png); width: 498px; background-position: 1px;
}
form {
width: 445px; margin: 0 auto;
}
form label {
font: 13px "ClarendonRoman", Georgia, Times, serif; color: #525250; letter-spacing: 2px; text-transform: uppercase; float: left; position: relative; top: 4px;
}
form label.error {
text-transform: none; letter-spacing: 0; color: #a21714; font: 15px "SeanRegular", Courier New, Courier New, Courier6, monospace; margin-top: -10px; clear: both; padding: 0px 0px 10px 21px; background: url(../img/errow.png) no-repeat 0 0;
}
form ul {
padding-top: 10px;
}
form ul li {
padding-top: 10px; clear: both; overflow: hidden;
}
form ul li.selectli {
padding-bottom: 10px;
}
form select, form input {
float: right;
}
form input {
border-bottom: 1px dashed #989895; border-right: none; border-left: none; border-top: none; color: #4f4f4f; background: none; outline: none; position: relative; bottom: 13px; font: 16px "SeanRegular", Courier New, Courier New, Courier6, monospace; letter-spacing: 1px;
}
form input:focus {
border-bottom: 1px dashed #000; -webkit-transition:border 0.3s ease-in; -moz-transition:border 0.3s ease-in; -o-transition:border 0.3s ease-in; transition:border 0.3s ease-in;
}
form select {
width: 300px;
}
input#name {
width: 370px;
}
input#email {
width: 360px;
}
input#website {
width: 340px;
}
fieldset#contactinfo {
padding-bottom: 23px; border-bottom: 1px solid #a7a7a4;
}
fieldset#natureinfo {
margin-top: 4px;
}
fieldset#message {
background: url(../img/messagebar.png) top no-repeat; width: 445; margin-top: 25px;
background: url(../img/messagebar.png) top no-repeat; width: 445; margin-top: 25px;
}
fieldset#message label {
display: none;
}
textarea#messagetext {
margin-top: 4px; width: 445px; height: 150px; border: none; background: none; outline: none; resize: none; overflow: auto; color: #4f4f4f; font: 16px "SeanRegular", Courier New, Courier New, Courier6, monospace; letter-spacing: 1px; float: left; display: block;
}
#submitbutton {
float: right;
}
#submitbutton input {
cursor: pointer; background: url(../img/submit.png) no-repeat; width: 445px; height: 86px; border: none; text-indent: -9999px; position: relative; bottom: 10px;
}
#submitbutton input:hover {
background-position: 0 -86px;
}
span#formbottom {
background: url(../img/formbottom.png) no-repeat; width: 498px; height: 108px; display: block;
}
#othercontact {
float: right; width: 566px; margin-bottom: 40px;
}
#map {
width: 552px; height: 269px; background: url(../img/map.jpg) center no-repeat rgb(233,233,228); background: url(../img/map.jpg) center no-repeat rgba(255,255,255,0.3); padding: 6px; border: 1px solid rgb(249,249,248); border: 1px solid rgba(255,255,255,0.7); margin-bottom: 28px; position: relative;
}
span#mappointer {
width: 77px; height: 80px; display: block; position: absolute; top: 66px; left: 257px; background-image: url(../img/map-pin.png);
}
section.subcontact {
float: left; width: 267px; position: relative; padding-left: 3px; border-top: 6px solid #d3d2c5; -webkit-transition:border 0.4s ease-in; -moz-transition:border 0.4s ease-in; -o-transition:border 0.4s ease-in; transition:border 0.4s ease-in;
float: left; width: 267px; position: relative; padding-left: 3px; border-top: 6px solid #d3d2c5; -webkit-transition:border 0.4s ease-in; -moz-transition:border 0.4s ease-in; -o-transition:border 0.4s ease-in; transition:border 0.4s ease-in;
}
section.subcontact:hover {
border-top: 6px solid #cc7b58; -webkit-transition:border 0.3s ease-in; -moz-transition:border 0.3s ease-in; -o-transition:border 0.3s ease-in; transition:border 0.3s ease-in;
}
section.subcontact h2 {
padding-top: 17px; color: #5a5a5a; font: 20px "ClarendonRoman", Georgia, Times, serif; margin-bottom: 10px; letter-spacing: -0.05em;
}
section.subcontact p {
margin-bottom: 16px; width: 260px;
}
section.subcontact.subright {
position: relative; left: 25px;
}
ul.iconlist {
padding-top: 6px;
}
ul.iconlist li {
padding: 12px 25px; border-top: 1px dashed #b2b2ab;
}
li#mapicon {
background: url(../img/icons/map.png) no-repeat 0 14px;
}
li#emailicon {
background: url(../img/icons/mail.png) no-repeat 0 13px;
}
li#vcardicon {
background: url(../img/icons/card.png) no-repeat 0 13px;
}
li#twittericon {
background: url(../img/icons/twitter.png) no-repeat 0 13px;
}
li#docicon {
background: url(../img/icons/doc.png) no-repeat 3px 13px;
}
还有更多...
在大多数情况下,向 HTML5 添加层叠样式表与向 XHTML 或以前版本的 HTML 添加 CSS 一样。只是现在我们有额外的标签需要跟踪。
提示
请记住,HTML5 和 CSS3 是两回事。人们经常把它们混在一起 - 就像他们对“Web 2.0”这个术语做的那样,直到这个术语最终失去了所有意义(如果它确实有任何意义的话)。我们会滥用“HTML5”这个术语,以至于最终失去所有意义吗?或者它已经发生了?只有你可以防止森林火灾。
旧版浏览器
在为 HTML5 设置样式时,我们需要注意两件事:
当所有浏览器都不支持新元素时,如何为新元素设置样式。
当新的 HTML5 元素在任何给定的浏览器中不受支持时,回退看起来是什么样子。
测试,测试,测试
在为 HTML5 设置样式时,关键是在浏览器中进行测试,测试,测试。为了我们的客户和整个网络开发的利益,我们必须了解浏览器中发生的事情,并根据我们的经验进行调整。
关于伪类
CSS3 提供了一些新的伪类,用于区分必填表单字段和非必填表单字段。我们将把这些与内置的 HTML5 表单验证结合起来:
:required
- 让我们根据所需的内容来设置字段样式
:optional
- 让我们根据所需的内容来设置字段样式
:valid
- 将与表单验证一起工作
:invalid
- 将与表单验证一起工作
:in-range
- 与最小和最大字符一样工作,比如电话号码
:out-of-range
- 与最小和最大字符一样工作,比如电话号码
另请参阅
如果你想尝试使用 CSS3 来为 HTML5 设置样式,Blue Griffon 的开发人员创建了bluegriffon.org
,这是一个新的所见即所得的网络内容编辑器。这个工具支持多种语言,允许用户在不太考虑代码的情况下使用网络标准。
使用电子邮件输入类型
HTML5 支持的众多新输入类型之一是email
。你有多少次使用<input type="text" />
构建表单,意图收集电子邮件地址?现在我们可以使用更语义正确的东西了!稍后,我们将看到这也支持表单验证。
如何做...
先前的 FoundationSix 示例可以很容易地转换为这种新的输入类型。而不是:
<li>
<label for="email">Email</label>
<input id="email" name="email" type="text" class="required email">
</li>
我们可以简单地改变输入类型,最终得到:
<li>
<label for="email">Email</label>
<input id="email" name="email" type="email" class="required email">
</li>
在视觉上,<input type="email" />
标签看起来与<input type="text" />
完全相同。区别在于浏览器对信息的处理方式。
它是如何工作的...
将类型从"text"
更改为"email"
允许较新的浏览器验证用户输入的是否真的是有效的电子邮件地址。请注意,服务器无法确定电子邮件帐户是否处于活动状态,只能确定地址本身是否格式良好。
还有更多...
那么如果提交的电子邮件地址无效会发生什么?事实上,目前还没有定论。Opera 浏览器有一个实验性的错误消息,Firefox 有自己的实验性附加组件。不幸的是,这是一个灰色地带,我们必须耐心等待,直到浏览器以一致的方式处理它。
浏览器支持
但是关于<input type="email" />
的酷炫之处在于:浏览器支持它!嗯,有点。即使不理解<input type="email" />
的浏览器也会默认回到<input type="text" />
,所以它仍然有效。太棒了!
没有 JavaScript
正如我们将在其他情况下看到的那样,HTML5 中的<input type="email" />
允许我们停止使用 JavaScript 来实现类似的结果。我们不再需要使用行为层来弥补标记或演示层的不足。
验证的演变
表单验证已经从互联网的早期发展了。在最早期,开发人员被迫使用 CGI 脚本等技术来提交表单并完全重绘结果页面。只有在页面提交到服务器后,用户才知道他们的信息是否被接受。如果没有,他们就必须重新开始。
随着时间的推移,开发人员学会了使用 AJAX 来执行表单的客户端验证。这样做虽然有效,但大部分工作都落在了 JavaScript 身上。当 JavaScript 被关闭或者需要满足无障碍要求时,这就带来了挑战。
现在,使用 HTML5,一些验证可以在浏览器中进行,而不需要将信息发送到服务器或依赖 JavaScript。虽然不像 AJAX 解决方案那样强大,但这种类型的验证可以在错误发生之前捕获许多最常见的错误。
使用 URL 输入类型添加 URL
HTML5 支持的众多新输入类型之一是URL
。你有多少次使用<input type="text" />
构建表单,意图收集网站地址?现在我们可以使用更语义正确的东西!稍后我们将看到这也支持表单验证。
如何做到这一点...
以前的 FoundationSix 示例也可以很容易地转换为这种新的输入类型。而不是:
<li>
<label for="website">Website</label>
<input id="website" name="website" type="text" class="required">
</li>
我们可以简单地改变输入类型,最终得到:
<li>
<label for="website">Website</label>
<input id="website" name="website" type="URL" class="required">
</li>
与<input type="email" />
类似,<input type="URL" />
标签在视觉上看起来与<input type="text" />
相同。再次强调的是浏览器对输入信息的处理方式有所不同。
它是如何工作...
将类型从"text"
更改为"URL"
允许较新的浏览器验证用户输入的是否实际上是有效的网站地址。请注意,服务器无法确定网站是否活动,只能确定地址本身是否格式良好。
还有更多...
如果提交的网站地址无效会发生什么?事实上,这里的情况还没有定论。不幸的是,这是一个灰色地带,我们需要耐心等待,直到浏览器以一致的方式处理它。
浏览器支持
但是关于<input type="URL" />
的酷炫之处在于:浏览器支持它!嗯,有点。即使不理解<input type="URL" />
的浏览器也会默认回到<input type="text" />
,所以它仍然有效。太棒了!
没有 JavaScript
正如我们将在其他情况下看到的那样,HTML5 中的<input type="URL" />
允许我们停止使用 JavaScript 来实现类似的结果。我们不再需要使用行为层来弥补标记或表现层的不足。
接下来呢?
随着浏览器的发展,未来我们可能会看到更智能的实现,允许浏览器对<input type="URL" />
做更聪明的事情,比如预取一个站点图标以在评论字段中显示。时间会告诉我们。
另请参阅
乐队 Arcade Fire 与电影制作人 Chris Milk 合作,为 Chrome 浏览器创建了基于该乐队歌曲"We *Used To Wait"的互动在线电影"The Wilderness Downtown",网址为thewildernessdowntown.com
,完全使用 HTML5 和 CSS3。该网站因其使用画布、HTML5 视频、Google 地图等而成为有史以来最受关注的 HTML5 体验之一。
使用数字标签
HTML5 现在允许用户在一系列数字中进行选择。例如,如果你希望你的观众购买东西,你可能希望他们使用整数。毕竟,谁会订购 2 双半鞋呢?
如何做到这一点...
如果我们继续购买鞋子的例子,我们可以开发一个这样的表单:
<form>
<label>How many shoes would you like to purchase?<label>
<input type="number" name="quantity" min="2" max="6" step="2" value="2" size="4" />
</form>
请注意,在input
中,我们可以选择性地指定可以订购的最小数量(2)和可以订购的最大数量(6)。在这种情况下,step
允许我们确保用户只能成对订购鞋子,而value
设置了显示的初始物品数量。然后size
控制了input
框的宽度。
它是如何工作的...
指定<input type="number">
将显示带有上下箭头的新表单控件,允许用户增加和减少字段中的值。这些通常被称为“微调器”或“微调框”。您还可以设置此字段的增量:
还有更多...
新的<input type="number" />
标签在在线电子商务之外还有其他用途。例如,我们可以想象一个非营利组织使用它来设置一个表单,允许用户捐赠固定金额的钱。由于组织有时会针对不同的捐款金额提供奖品,表单可以被创建为只允许以这些最小增量输入。
浏览器支持
目前<input type="number" />
仅受 Opera 以及基于 Webkit 的浏览器(如 Chrome 和 Safari)的支持。但是<input type="number" />
的酷之处在于:像<input type="email" />
和<input type="URL" />
一样,其他浏览器也支持它!嗯,有点。就像这些标签一样,即使不理解<input type="number" />
的浏览器也会默认回到<input type="text" />
,所以它仍然有效。太棒了!
没有 JavaScript
正如我们将在其他情况下看到的那样,HTML5 中的<input type="number" />
允许我们停止使用 JavaScript 来实现类似的结果。我们不再需要使用行为层来弥补标记或表示层的不足。
使用 range 标签
HTML5 现在允许我们创建一种全新的输入方式。range 标签创建了一个滑块控件,允许用户在一系列值中进行选择。这以前很困难,但现在不是了!看看吧!
如何做到...
有趣的是,我们可以使用几乎与数字示例中相同的代码,但将输入类型更改为"range"
。以下是如何做到的:
<form>
<label>How many shoes would you like to purchase?<label>
<input type="range" name="quantity" min="2" max="6" step="2" value="2" />
</form>
我们可以使用相同的可选属性min,max,step,value
和size
。
它是如何工作的...
指定<input type="range">
将显示带有滑块的新表单控件,允许用户增加和减少字段中的值:
还有更多...
<input type="range">
标签的用途绝不仅限于电子商务。事实上,由于我们无法看到当前选择的值,购物可能并不是这个新标签的最佳用途。作者可以想象在基于网络的音乐播放应用程序中使用<input type="range">
,用户可以在不必看到具体音量数字的情况下直观地增加或减少音量。
使用时要小心
不幸的是,没有非 JavaScript 的方法来显示范围输入标签的当前选择值。希望随着 HTML5 的进一步定义和更多浏览器支持其原生控件,我们将能够更好地控制它。在那之前,请谨慎使用。
没有 JavaScript
正如我们将在其他情况下看到的那样,HTML5 中的<input type="range" />
允许我们停止使用 JavaScript 来实现类似的结果。我们不再需要使用行为层来弥补标记或表示层的不足。
浏览器支持
与<input type="number" />
一样,目前<input type="range" />
仅受 Opera 以及基于 Webkit 的浏览器(如 Chrome 和 Safari)的支持。但是<input type="range" />
的酷之处在于:像<input type="email" />
和<input type="URL" />
以及<input type="number" />
一样,其他浏览器也支持它!嗯,有点。就像这些标签一样,即使不理解<input type="range" />
的浏览器(Firefox,我在看你!)也会默认回到<input type="text" />
,所以它仍然有效。太棒了!
另请参阅
Mozilla 的“HTML5 之人”视频系列展示了 HTML5 运动的许多主要声音。作者 Bruce Lawson 在娱乐性和权威性方面表现出色,尤其是当他批评将 HTML5 用作涵盖相关但不同技术的总称时。
“客户和记者将使用'HTML5'来表示 CSS 3/在 iThings 上运行的视频/启用地理位置的应用程序。这是新的'Web 2.0'。但我们从业者需要搞清楚我们的命名。没有 HTML5 图像转换,就像没有 CSS 语义一样-说有这些东西表明你没有收到关于分离样式和内容的 2001 备忘录。”
阅读并观看完整访谈:hacks.mozilla.org/2011/01/people-of-html5-bruce-lawson
。
创建搜索字段
HTML5 支持的许多新输入类型之一是search
。有多少次您使用<input type="text" />
构建表单,意图是允许用户搜索网站?现在我们可以使用更具语义的东西。
如何做到...
让我们使用占位符属性构建一个快速搜索字段。到目前为止,您已经熟悉了这种过时的方法:
<form>
<input name="something" type="text" value="keyword" />
<input type="submit" value="Search" />
</form>
我们都做过这个动作,对吧?好吧,让我们尝试这个替代方案:
<form>
<input name="something" type="search" placeholder="keyword" />
<input type="submit" value="Search" />
</form>
发现了区别吗?我们的类型已从text
更改为search
,占位符文本不再使用值标记。对于我们开发人员以及搜索引擎和辅助技术来说更有意义。
它是如何工作的...
指定<input type="search">
将在 Opera 以及 Chrome 和 Safari 等基于 Webkit 的浏览器中显示具有圆角的新表单字段:
还有更多...
圆角搜索框是由苹果在 OSX 上以及 iPad 和 iPhone 上推广的设计方法。苹果正在逐渐成为移动体验的思想领袖,以及 HTML5 的最积极的倡导者之一。
为什么要修复完美?
当然,可以覆盖新的 HTML5 搜索字段的默认圆角样式,但是为什么呢?它已经看起来很酷了!
浏览器支持
这已经成为一个熟悉的叮咛,但是像<input type="email" />
和<input type="URL" />
和<input type="number" />
和<input type="range" />
一样,您可以放心,如果浏览器不会原生理解<input type="search" />
,它将继续像<input type="text" />
一样进行处理。
搜索结果
新的search
规范还支持新的results
属性,以在下拉列表中显示已搜索的术语。
另请参阅
nevermindthebullets.com
上的 Never Mind The Bullets 是一个交互式在线游戏,专门用于演示 Microsoft Internet Explorer 9 能够处理的 HTML5 和 CSS3 功能,包括:@font-face;<canvas>
动画;<header>
和<section>
布局;JavaScript 加速;CSS3 2D 变换;CSS3 多背景;可编辑内容;<audio>
音轨播放器;<video>
播放器。
创建一个显示日期和时间的选择器
每个飞机、火车和汽车租赁网站都将拥有某种时间/日期选择器。终于有了一种语义方法来处理这个问题,让我们看看如何使用 HTML5 创建这些input
类型。
提示
截至目前,只有 Opera 浏览器完全支持这些新的input
标签。
如何做...
HTML5 实际上有六种不同的新input
,可以控制日期和时间。简而言之,它们是:
每种input
类型都可以被视为彼此的变体。作为开发人员,我们的工作是选择最适合您收集的数据的那种类型。
它是如何工作的...
对于日期选择器:
<form>
<input type="date"/>
</form>
对于日期/时间选择器:
<form>
<input type="datetime"/>
</form>
对于本地日期/时间选择器:
<form>
<input type="datetime-local"/>
</form>
对于月/年选择器:
<form>
<input type="month"/>
</form>
对于时间选择器:
<form>
<input type="time"/>
</form>
对于周选择器:
<form>
<input type="week"/>
</form>
还有更多...
鼓励您尝试每个基于新日历的input
标签,以确定哪个最适合您特定的网站或应用程序。
浏览器支持
截至目前,只有 Opera 为这些新的input
标签提供了全面支持。随着时间的推移,预计其他浏览器也会赶上。一旦我们拥有了完全可样式化的日期/时间input
方法,那将是一个真正快乐的日子。
与此同时,其他浏览器将默认显示这些input
类型为纯文本框。它们仍然可以工作,但不会像我们希望的那样漂亮。耐心点,小草 hopper。记住,我们正在处理最新的技术 —— 还不是完全成熟、经过验证和批准的方法。
如果一切都失败了
User Agent Man 撰写了一篇关于当这些各种新的 HTML5 input
标签不按照您的期望或预期的方式工作时,您应该怎么做的好文章。请查看完整文章:useragentman.com/blog/2010/07/27/cross-browser-html5-forms-using-modernizr-webforms2-and-html5widgets
。
另请参阅
Forrst.com 是由 Kyle Bragger 使用 HTML5 创建的一个很棒的在线资源。Forrst 是一个充满活力的网络开发者和设计师社区,他们相信通过分享和建设性地批评彼此的工作,可以增加他们对网站创建工艺的知识、技能和热情。我们很欣赏他们的工作态度。
第六章:使用 Canvas 开发丰富的媒体应用程序
在本章中,我们将涵盖:
设置“画布”环境
了解 2D 渲染上下文
动态处理形状
使用“画布”为图像绘制边框
圆角
创建交互式可视化
弹跳球
创建备用内容
介绍
“我更喜欢画画而不是说话。画画更快,也给谎言留下更少的空间。”-勒·柯布西耶
这可能是整本书中最实验性的一章。在接下来的配方中,我们将真正推动这组配方所能实现的极限。
注意
请注意,随着时间的推移,实验性的新“画布”元素规范可能会发生变化。在出版时,可以将这组配方视为可能性的一个快照。
在网站上放置图像是如此容易,我们现在认为理所当然。通过代码,你只需告诉浏览器显示一个图像,就完成了。所有这一切似乎都是小孩的游戏。目前,一些浏览器实际上可以使用新的“画布”元素动态地创建图像。所有繁重的工作都交给了 JavaScript。
新的开源“画布”元素的酷之处在于,不仅可以动态地创建图像,而且用户的操作也可以实时创建新的图像,而无需插件。听起来很棒,对吧?在许多方面确实如此,但它也让使用辅助技术的朋友们感到孤立。
提示
如果你使用的浏览器不支持新的“画布”元素会发生什么?基本上什么都不会发生。浏览器只是不会显示它。这就是为什么你需要特别小心使用这项技术,不要在新的“画布”元素中放置任何你的网站或应用程序绝对依赖的东西。你还必须考虑备用内容。
支持“画布”的浏览器包括:
提示
在继续使用新的“画布”元素进行开发之前,请确保你对 HTML 和 JavaScript 有扎实的基础技能。对面向对象编程感到舒适肯定也是有好处的。
在本章中,我们将看一些设置“画布”环境、了解 2D 渲染上下文、动态处理形状、使用“画布”为图像绘制边框、圆角、创建交互式可视化、弹跳球和创建备用内容的实际示例。
现在,让我们开始吧!
设置画布环境
创建新的“画布”元素很容易。
如何做...
看看这有多简单:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
它是如何工作的...
当然,我们可以使用任何需要的高度和宽度尺寸,但这组简单的标签是我们开始所需的。
提示
你可能会认为我们可以使用 CSS 来控制高度和宽度,但要抵制这种诱惑。因为新的“画布”元素包含一个 2D 渲染上下文,这种方法可能会导致不可预测的行为。
还有更多...
接下来,我们将调用新的“画布”元素 JavaScript API,同时调用 jQuery:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
他很聪明
“让我完全明确一件事:当你使用‘画布’时,你并不是在画布元素本身上绘图。相反,你实际上是在通过 JavaScript API 访问‘画布’元素的 2D 渲染上下文上绘图。”-罗布·霍克斯
我在说什么?
苹果早在多年前就在 OSX Dashboard 中首次引入了新的“画布”元素。后来它在 Safari 和 Chrome 等网络浏览器中实现,其他浏览器也纷纷效仿。从那时起,它已成为 HTML5 规范的正式部分。
的下一步是什么?
现在,我们只是初步了解了新的“画布”元素可以做什么。现在和将来,我们将使用它来创建动画、图表、图表、绘图应用程序、图形和用户界面。你会梦想出什么?
另请参阅
开发者 Martin Angelov 为 Tutorial Zine 撰写了一篇名为《使用 Canvas 和 jQuery 创建 HTML5 幻灯片》的很棒的指南:tutorialzine.com/2010/09/html5-canvas-slideshow-jquery
。在这篇文章中,Martin 演示了如何将新的 canvas 元素与 jQuery 这个最流行的 JavaScript 框架结合起来,创建一个非常互动的图像幻灯片。
理解 2D 渲染上下文
重要的是要理解,新的canvas
元素实际上是一个在浏览器中绘制位图图像的“表面”。
如何做到...
像这样定义一个canvas
标签只是讲了一半的故事:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
工作原理...
单独的 HTML5 代码不会做任何事情。我们必须使用 JavaScript 来使文档对象模型检索 2D 渲染上下文,以便让一些事情发生:
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
});
</script>
公平地说,如果没有 HTML 中的canvas
标签,那么 JavaScript 也不会做任何事情。
还有更多...
你可能会对这个名字感到好奇。如果有一个 2D 渲染上下文,那么可能也有一个 3D 渲染上下文吗?简短的答案是肯定的。但更详细的答案并不那么简单。
尽管在理论上存在 3D 渲染上下文,但在本出版物发表时,没有浏览器支持它。因此,如果新的canvas
元素以 3D 方式呈现,但没有人看到它,它真的做了什么吗?
你可以掌握
2D 上下文使用了许多不同的绘图上下文来使用新的canvas
元素,这些语法应该看起来非常熟悉,如果你熟悉 CSS 和 JavaScript 的话。
X,见 Y
在绘图时,请记住浏览器窗口左上角的 X 和 Y 轴。数值向下增加。
尊重我的权威!
万维网联盟的 HTML5 Canvas
2d 上下文规范在线上可以找到:dev.w3.org/html5/2dcontext
。在那里,我们可以深入了解诸如符合性要求、canvas
状态、变换、合成、颜色和样式、线条样式、阴影、简单形状、复杂形状、焦点管理、文本、图像、像素操作、绘图模型、示例等更多信息。
另请参阅
Steve Fulton 和 Jeff Fulton 为 O'Reilly Books 撰写了《HTML5 Canvas》一书。虽然本章将为您提供大约 30 页有价值的新canvas
元素技巧,但 Fulton 的书大约有 400 页。可以将其视为在本章结束后继续学习的资源。在这里查看:oreilly.com/catalog/0636920013327
。
动态处理形状
让我们看看允许新的canvas
元素绘制矩形的 JavaScript 函数。
如何做到...
fillRect(x,y,width,height)
strokeRect(x,y,width,height)
按顺序:
fillRect(x,y,width,height)
绘制一个填充的矩形。接下来,
strokeRect(x,y,width,height)
绘制一个矩形的轮廓。
现在,让我们画一些形状。
工作原理...
我们将从基本的canvas
代码开始,并整合我们的新功能:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(10, 10, 396, 236);
ctx.fillStyle = "red";
ctx.fillRect(11, 11, 100, 100);
ctx.fillStyle = "white";
ctx.fillRect(111, 11, 34, 100);
ctx.fillStyle = "red";
ctx.fillRect(156, 11, 249, 100);
ctx.fillStyle = "white";
ctx.fillRect(11, 111, 394, 34);
ctx.fillStyle = "red";
ctx.fillRect(11, 145, 100, 100);
ctx.fillStyle = "white";
ctx.fillRect(111, 145, 34, 100);
ctx.fillStyle = "red";
ctx.fillRect(156, 145, 249, 100);
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="416" height="256">
<p>Flag of Denmark</p>
</canvas>
</body>
</html>
我们创建的东西类似于丹麦的国旗!
还有更多...
这个例子一开始可能并不令人震惊,但当你记住我们几乎没有使用任何 HTML 和 CSS 就创建了一个图像时,新的canvas
元素开始看起来相当令人印象深刻。
你想要的任何方式
请注意,虽然我们使用了颜色名称(“white”和“red”),但我们也可以使用十六进制值或 RGB 甚至 HSL!使用对你和你的互动项目最有意义的内容。
类似于表格?
对于这个例子的颜色和大小规格,几乎可以将其视为我们过去用于布局的老式tables
。虽然肯定不一样,但在这种情况下,这种技术确实有相似之处。
首先成为一个正方形
掌握矩形是在掌握设置元素本身之后非常重要的canvas
技术。理解这种方法的基础将有助于你掌握接下来几个技巧的基本原理。
另请参阅
另一本书,近 400 页,是 Rob Hawkes 的《Foundation HTML5 Canvas: For Games and Entertainment》,由 Friends of Ed 出版。在这本书中,Hawkes 为那些刚接触新的canvas
元素的人,一直到最有经验的专家提供了一个提升技能的出版物。听起来像你认识的人吗?在这里查看:friendsofed.com/book.html?isbn=1430232919
.
使用 canvas 为图像绘制边框
让我们更仔细地看看使用新的canvas
元素绘制图像边框的超简单方法。
如何做...
首先,我们将从基本的canvas
代码开始,然后添加一行新代码来绘制边框:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("FirstCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
它是如何工作的...
这一行 JavaScript 告诉浏览器创建一个矩形,从新的canvas
元素的左边 10 像素,顶部 20 像素开始。它绘制了一个 100 像素的正方形。
更多内容...
这很好,但如果我们希望边框是除了默认颜色之外的任何其他颜色,我们需要指定:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "rgb(0, 128, 0)";
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
在这种情况下,我们使用strokeStyle
来指定纯绿色的 RGB 颜色。
首先是样式
提示
如果您打算为边框设置样式,您需要在浏览器绘制边框之前指定。如果您在之后指定样式,浏览器将简单地忽略它。
许多颜色值都可以使用
我们刚刚使用的样式属性是 RGB,但该方法也适用于颜色(例如“绿色”)、十六进制值、HSL 和 RGBA。
我喜欢大边框,我无法否认
如果未指定边框宽度,浏览器将自动绘制一个像素的边框。以下是如何更改它的方法:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.lineWidth = 10;
ctx.strokeStyle = "rgb(0, 128, 0)";
ctx.strokeRect(10, 20, 100, 100);
});
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
就是这么简单:
另请参阅
rgraph.net
是一个专门为新的canvas
元素设计的图形库。它允许您轻松创建各种图表类型:条形图、双极图、圆环图、漏斗图、甘特图、水平条形图、LED 显示、折线图、仪表、里程表、饼图、进度条、玫瑰图、散点图和传统的雷达图,使用 HTML5、canvas
和 JavaScript。
圆角
到目前为止,我们已经使用方形或矩形形状创建了图像和边框。接下来,我们将看看如何使用新的canvas
元素通过 JavaScript 来圆角这些图像和边框。
如何做...
canvas
的圆角能力并非原生支持,但 Rob Hawkes 是一个非常聪明的人,他找到了实现这一功能的方法。这就是 Rob 所做的事情,解释在:rawkes.com/blog/2010/12/11/rounded-corners-in-html5-canvas
。
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
$(document).ready(function() {
var canvas = $("#myCanvas");
var context = canvas.get(0).getContext("2d");
var rectX = 10;
var rectY = 10;
var rectWidth = 100;
var rectHeight = 100;
var cornerRadius = 15;
context.lineJoin = "round";
context.lineWidth = cornerRadius;
context.strokeStyle = "rgb(0, 128, 0)";
context.strokeRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
});
</script>
</head>
<body>
<canvas id="myCanvas" width="600" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
它是如何工作的...
首先,Rob 选择了一种稍微不同的调用 2dcanvas
渲染上下文的方法,但他的方法也完全有效。看看:
$(document).ready(function() {
var canvas = $("#myCanvas");
var context = canvas.get(0).getContext("2d");
Rob 的代码的下一部分应该看起来很熟悉:他设置了图像的 X 和 Y 坐标,大小,然后是边框半径:
var rectX = 10;
var rectY = 10;
var rectWidth = 100;
var rectHeight = 100;
var cornerRadius = 15;
然后 Rob 调用了连接线的能力和他想要使用的特定边框半径。假装直到你成功为止!
context.lineJoin = "round";
context.lineWidth = cornerRadius;
最后是边框的颜色(仍然是绿色!)和将所有内容联系在一起的最后一部分脚本:
context.strokeStyle = "rgb(0, 128, 0)";
context.strokeRect(rectX+(cornerRadius/2), rectY+(cornerRadius/2), rectWidth-cornerRadius, rectHeight-cornerRadius);
更多内容...
现在 Rob - 以及你,如果你在跟着做 - 可以成为一个拥有美丽圆角图像的摇滚明星。
就像学术能力测试一样
提示
记住:lineWidth
对于新的canvas
元素来说就像border-radius
对于 CSS 一样。它们都实现了相同的功能 - 但是通过非常不同的方式。
IE 怎么样?
可以使用 ExplorerCanvas 库在 Internet Explorer 6-8 中支持一些新的canvas
元素功能:code.google.com/p/explorercanvas.
我们正在奠定基础
在本章的大部分食谱中,我们只使用新的canvas
元素在浏览器中绘制静态形状,而没有使用图像。这可能看起来平淡无奇,甚至可能逆向思考。重点是为您提供这种新能力的坚实基础,以便您可以扩展它,使用新的canvas
元素来创建游戏,可视化数据,并允许用户动态绘制对象。
另请参阅
Mozilla 的“HTML5 的人”视频系列展示了许多 HTML5 运动的领军人物。约翰·福利奥特是 HTML5 中媒体元素无障碍性小组委员会的联合主席。当他对当前浏览器对这些技术的支持状态感到遗憾时,这一点应该不足为奇:
“我认为 HTML5 开始提供的许多功能将使所有用户受益,包括使用辅助技术的用户。然而,许多承诺的功能在所有浏览器中尚不受支持,相关技术——辅助技术——还有很长的路要走才能利用这一好处。”
阅读并观看完整的采访内容:hacks.mozilla.org/2011/02/people-of-html5-john-foliot
.
创建交互式可视化
Carbon Five 团队面临着一个艰巨的任务:创建他们的技能和兴趣的物理图表。他们可能从办公室的墙壁开始,但很快意识到新的canvas
元素带来的新能力将允许交互性,并且可以根据此进行结论。这是他们的做法:carbonfive.github.com/html5-playground/interest-map/interest-map.html.
如何做...
提示
在按照本文进行操作时,查看源代码将非常有帮助:查看源代码:http://carbonfive.github.com/html5-playground/interest-map/interest-map.html
Carbon Five 团队提醒我们,画布并不是 HTML5 规范的正式部分,他们使用 HTML4.01 Transitional DOCTYPE 创建了这个交互式可视化。
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
这里详细介绍了他们如何使用 JavaScript 和新的canvas
元素。他们从一些变量开始,比如卡片样式。在这里,他们做了几件事:设置背景颜色,创建黑色边框,卡片的宽度,以及围绕它的阴影的值。
var CARD_STYLE = { fill:'rgb(240,240,240)',stroke:'rgb(0,0,0)',width:.05, shadow:{x:0, y:4, blur:4, color:'rgba(0, 0, 0, 0.3)'} };
下一个变量对于了解 CSS 的人来说应该很熟悉。在这里,设置了卡片的字体重量、大小、字体、颜色等:
var CARD_FONT = {font:'bold 8pt Courier', color:'#555', yoffset:10, height:14};
接下来,他们设置了与边距、宽度、高度、比例、半径、阴影等相关的几个变量。
var MARGIN = [75,75,75,100], WIDTH = 1000-MARGIN[1]-MARGIN[3], HEIGHT = 650-MARGIN[0]-MARGIN[2], CARD_SCALE=.75, CARD_RADIUS = 40, TAG_RADIUS = 50, CACHE_RADIUS=70, CLEAR_RADIUS = 50, ITERATIONS = 20, DEGREE = .5, CARD_SHADOW = 2, AXIS_ANIM=700;
最后,他们为技能、人员和人员与技能矩阵设置了变量。不幸的是,这些代码块太长,无法在此重新发布。
它是如何工作的...
变量本身并不会有太大作用,除非它们有函数来对其进行操作。
在初始化显示后,Carbon Five 团队使用更多的函数,如在 2Dcanvas
渲染元素上绘制:
function draw(t) {
var ctx = el('display').getContext('2d');
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.save(); ctx.globalAlpha = 1 - .75*arrow_visibility;
each( cards, function(card) {
var t0=card.tween(t); x = MARGIN[3] + card.lx + (card.x-card.lx)*t0, y = MARGIN[0] + card.ly + (card.y-card.ly)*t0;
draw_card( ctx, x, y, card.index);
});
ctx.restore();
if ( arrow_visibility > 0 ) {
ctx.save(); ctx.globalAlpha = arrow_visibility;
each( PEOPLE, function(p) { draw_interest_arrow(ctx,p,t); });
ctx.restore();
if (over_person) draw_over_arrow(ctx,over_person,t);
}
draw_axes(ctx);
}
除了创建名牌之外:
function nametag( ctx, cardx, cardy, person, r, interest ) {
ctx.save(); ctx.translate( cardx, cardy ); ctx.rotate( r + .4*(Math.random()-.5) );
ctx.translate( -TAG_RADIUS - + 4*Math.random(), 0 ); ctx.rotate( -r );
draw_nametag( ctx, person, interest );
ctx.restore();
}
并且绘制箭头:
function draw_arrow( ctx, length, head_length, head_width ) {
var cx1 = .9*(length - head_length), cy1 = .2*head_width, cx2 = (length - head_length), cy2=.2*head_width;
ctx.beginPath();
ctx.moveTo(0,0);
ctx.bezierCurveTo( cx1, cy1, cx2, cy2, length-head_length, head_width );
ctx.lineTo( length, 0 ); ctx.lineTo( length-head_length, -head_width );
ctx.bezierCurveTo( cx2, -cy2, cx1, -cy1, 0, 0 );
ctx.closePath();
}
还有更多...
已经设置了变量和函数,最后要做的就是在 HTML 中调用canvas
元素本身,为其提供运行的空间:
<canvas id="display" width="1000" height="650"></canvas>
两害相权取其轻
在旧的网络时代,Carbon Five 团队可以选择将他们的地图留在物理墙上,或者为计算机显示创建静态图像。虽然任何一种方式都可以渲染得和使用新的canvas
元素一样好,但它们都不允许团队提取有价值的信息,就像新的canvas
元素那样。
备用内容呢?
有趣的是,Carbon Five 在这种情况下没有在新的canvas
元素中使用回退内容。这是一个你需要仔细权衡的方法,因为那些使用旧浏览器或辅助技术的人将什么也看不到。Carbon Five 在这个内部项目中得以成功。你能吗?
接受他的提议。
在blog.carbonfive.com/2011/02/17/visualizing-skillsets-in-html5-canvas-part-1
上写到这个项目时,Carbon Five 的开发者 Alex Cruikshank 甚至表示愿意为前五位以合理格式提供数据的人创建可视化地图。截至出版日期,尚不清楚是否有人接受了他的提议。
另请参阅
Jacob Seidelin 用他的新 canvas 元素可视化了乐队 Radiohead 的歌曲“Idioteque”,这首歌收录在专辑“Kid A”中:nihilogic.dk/labs/canvas_music_visualization
。Jacob 正在挑战canvas
元素和 JavaScript 的极限,这就是为什么我们认为他很棒!
弹跳球
我们已经看过如何使用新的canvas
元素绘制形状,接下来我们将把注意力转向使这些形状移动。作者 Vinci Rufus 向我们展示了如何。
如何做...
我们将从通常的canvas
HTML 代码开始:
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
</head>
<body>
<canvas id="FirstCanvas" width="800" height="600">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
接下来是独特的部分:JavaScript。在这里,Vinci 选择了一个稍微不同的方法来调用 2Dcanvas
渲染上下文,但他的方法也完全有效。看看:
<script>
var context;
function init()
{
context= myCanvas.getContext('2d');
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100, 100 on the canvas
context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();
}
</script>
将这些代码放在一起,应该是这样的。注意在body
标签中添加的onLoad
函数。
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
var context;
function init()
{
context= myCanvas.getContext('2d');
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100, 100 on the canvas
context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();
}
</script>
</head>
<body onLoad="init();">
<canvas id="myCanvas" width="300" height="300">
<!-- Fallback code goes here -->
</canvas>
</body>
</html>
并渲染这个蓝色的球:
它是如何工作的...
到目前为止,Vinci 的代码非常简单。我们看到他如何调用 2Dcanvas
渲染上下文。接下来他设置填充的颜色:
context.fillStyle="#0000ff";
然后在距离顶部和左边 100 像素的地方绘制一个弧线,并用他已经设置的蓝色填充:
context.arc(100,100,20,0,Math.PI*2,true); context.closePath();
context.fill();
但现在我们只有一个蓝色的球坐在那里。接下来,Vinci 向我们展示了如何使用变量和一个名为draw
的新函数使其移动。
还有更多...
<!DOCTYPE html>
<html>
<head>
<title>Canvas</title>
<meta charset="utf-8" />
<script src="img/ jquery.min.js"></script>
<script>
var context;var x=100;var y=200;var dx=5;var dy=5;
function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100, 100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
x+=dx;
y+=dy;
}
</script>
</head>
<body onLoad="init();">
<canvas id="myCanvas" width="300" height="300" >
</canvas>
</body>
</html>
正如你所看到的,球在运动,但只是在canvas
的边缘画了一条直线。Vinci 解释了原因:
“这是因为每次调用draw()
函数时,它都会在新坐标处绘制一个圆圈,而不会删除旧的圆圈。这就是getContext
对象的工作原理,所以这不是一个 bug;它实际上并没有移动圆圈,而是在每次调用函数时在新坐标处绘制一个圆圈。”
重新开始
Vinci 向我们展示了一种方法,可以擦除旧的圆圈,因为新的canvas
元素绘制了每一个新的圆圈:
<script>
var context;
var x=100;
var y=200;
var dx=5;
var dy=5;
function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.clearRect(0,0, 300,300);
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100, 100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
x+=dx;
y+=dy;
}
</script>
现在,球似乎向右下方的canvas
边界外掉落。
不要把我困住
为了确保球留在canvas
的边界内,Vinci 编写了一些逻辑来检查 x 和 y 坐标是否超出了canvas
的尺寸。如果超出了,他就让球改变方向。
<script>
var context;
var x=100;
var y=200;
var dx=5;
var dy=5;
function init()
{
context= myCanvas.getContext('2d');
setInterval(draw,10);
}
function draw()
{
context.clearRect(0,0, 300,300);
context.beginPath();
context.fillStyle="#0000ff";
// Draws a circle of radius 20 at the coordinates 100, 100 on the canvas
context.arc(x,y,20,0,Math.PI*2,true);
context.closePath();
context.fill();
// Boundary Logic
if( x<0 || x>300) dx=-dx;if( y<0 || y>300) dy=-dy;x+=dx;y+=dy;
}
</script>
现在球应该在canvas
的四个边上不断地弹跳。
还有一个要学习的
正如 Vinci 在他引人入胜的教程中提醒我们:sixrevisions.com/html/bouncing-a-ball-around-with-html5-and-javascript
,弹跳球起初可能看起来很简单,但实际上这是一个关键的技术,需要理解才能开发几乎任何新 HTML5canvas
元素的游戏。
另请参阅
可以在 Yuri Vishnevsky 的weavesilk.com
上看到用户生成的图形的美丽示例。该网站使用新的“画布”元素作为生成艺术实验的一部分。一些生成的图像非常美丽,Yuri 已经将它们作为令人惊叹的桌面背景图像提供。iPhone 和 iPad 版本也已计划。
创建备用内容
“当作者使用‘画布’元素时,他们还必须提供内容,当呈现给用户时,传达的基本上与位图‘画布’相同的功能或目的。此内容可以放置为‘画布’元素的内容。‘画布’元素的内容(如果有)是元素的备用内容。”- WHATWG HTML5 规范
如果有人在使用旧版浏览器并且无法识别您的编码天赋时,您的出色的新“画布”应用会发生什么?或者当有人使用辅助技术时会发生什么?让我们来看看。
如何做...
如果由于某种原因,用户的浏览器不支持新的“画布”元素,作为开发人员,我们需要给他们提供有价值的替代内容。
在这里我们可以使用图像作为备用内容。
<canvas id="clock" width="200" height="200">
<img src="img/clock.gif" width="200" height="200" alt="clock"/>
</canvas>
或者文本:
<canvas id="clock" width="200" height="200">
<p>clock</p>
</canvas>
或几乎任何其他元素。
它是如何工作的...
到目前为止,您对图像文件中alt
标签的工作原理已经很熟悉:如果图像文件不显示或用户依赖辅助技术,alt
标签至少会给他们一个有价值的文本标签,代表他们所错过的内容。新的“画布”元素的备用内容是一个类似的概念,但它能够做得更多,而不仅仅是一个alt
标签。
还有更多...
支持新的“画布”元素的浏览器将忽略容器内的内容,并正常呈现新的“画布”元素。
谢谢,Mozilla
“如果需要备用内容,则必须使用一些 CSS 技巧来掩盖 Safari 中的备用内容(应该只呈现‘画布’),并且还要掩盖 IE 中的 CSS 技巧本身(应该呈现备用内容)。”- Mozilla.org
我们将如何处理可访问性?
规范撰写者和 HTML5 社区普遍认为新的“画布”元素只是部分成熟。让使用辅助技术的人置身于寒冷中似乎不是正确的做法。敬请关注。
我们准备好使用了吗?
许多开发人员认为新的“画布”元素的可访问性是新 HTML5 规范中的最后一个难点。由于几乎没有有意义的备用功能,这个新元素似乎还没有准备好投入使用。
第七章:使用 JavaScript 进行交互
在本章中,我们将涵盖:
使用 JavaScript 播放音频文件
使用文本的拖放 API
使用vid.ly
和 jQuery 实现跨浏览器视频支持
使用 jQuery 动态显示视频
使用 jQuery 创建可移动的视频广告
使用Easel.js
和canvas
标签控制图像的显示
使用Easel.js
和canvas
标签来显示一系列图像的动画
使用canvas
标签和 JavaScript 进行随机动画和音频
介绍
虽然 HTML5 可能会结束对 Flash 的许多丰富媒体应用程序的使用,但它正在导致 JavaScript 比以前更受欢迎。有许多库和插件可用于增强和扩展 HTML5 和 CSS3,以创建丰富的交互体验。
本章包含了一些示例,展示了 JavaScript 如何与 HTML5 标签(如音频、视频和画布)、CSS3 选择器和元素一起使用。
使用 JavaScript 播放音频文件
HTML5 在互联网上如何使用音频文件提供了更多的灵活性。在这个示例中,我们将创建一个游戏,练习使用音频标签和 JavaScript 加载和播放声音。
准备工作
您需要一个要播放的音频文件,一张图片,以及支持 HTML5 的现代浏览器。本章的示例文件可以从www.packtpub.com/support?nid=7940
下载。Free Sound Project (freesound.org
)有您可以使用的音频文件,只要给予制作人信用,照片可以在www.Morguefile.com
找到,供您在个人项目中使用。
如何做...
现在我们准备创建一系列按钮和一个简短的 JavaScript 程序,当其中一个按钮被按下时,它将播放一个随机的音频文件。
打开您的 HTML 编辑器并创建一个 HTML5 页面的开头部分。
<!DOCTYPE html><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Playing a sound file with JavaScript</title>
因为我们只有一些样式,我们将把它们添加到 HTML 页面的 head 区域。
<style>h1{font-family:"Comic Sans MS", cursive; font-size:large; font-weight:bold;}
button{ padding:5px;margin:5px;}
button.crosshair { cursor: crosshair; }
button.crosshairthree {margin-left:40px;
cursor:crosshair;} </style>
脚本需要创建三个变量。打开脚本标签并创建变量,应该看起来像下面的代码块:
<script>//variables
var mySounds=new Array();
mySounds[0]="boing";
mySounds[1]="impact";
mySounds[2]="squeak";
mySounds[3]="whack";
mySounds[4]="space";
var soundElements;
var soundChoice;
现在我们已经为脚本创建了全局变量,我们可以创建函数。键入function whackmole(){
开始函数,然后在新行上键入var i = Math.floor(Math.random() * 5)
;使用 JavaScript 数学库生成一个随机数。接下来,键入soundChoice = mySounds[i]
;将数组值分配给soundChoice
。使用soundElements[soundChoice].play();}
关闭函数。您的函数代码目前应该看起来像下面的代码:
function whackmole() {
var i = Math.floor(Math.random() *5);
soundChoice = mySounds[i];
soundElements[soundChoice].play();}
键入function init(){
开始函数。在新行上,键入soundElements = document.getElementsByTagName("audio");} </script>
来完成我们的 JavaScript 代码块。它应该看起来像下面的代码块:
function init(){
soundElements = document.getElementsByTagName("audio");}
</script>
关闭 head 标签并键入 body 标签,添加一个init()
函数调用,使其看起来像:
</head><body onLoad="init();">
使用<header>
标签为页面的头部区域创建一个标题区域。使用标题标签<h1>
显示页面的标题:
<header><h1>Whack A Mole!</h1></header>
有五个按钮来创建一个平衡的外观,它们都被分配了一个类。
<section> <p> <button class="crosshair" onclick="whackmole();"> <img src="img/downmole.png" width="37" height="24" alt="Mole peeping out of hole"></button>
<button class="crosshair" onclick="whackmole();"> <img src="img/downmole.png" width="37" height="24" alt="Mole peeping out of hole"></button></p>
第三个按钮的类名为crosshairthree
,以便我们更好地控制它在屏幕上的位置。
<p style="padding-left:30px;"><button class="crosshair" onclick="whackmole();"><img src="img/downmole.png" width="37" height="24" alt="Mole peeping out of hole"></button></p> <p><button class="crosshair" onclick="whackmole();"> <img src="img/downmole.png" width="37" height="24" alt="Mole peeping out of hole"></button><button class="crosshair" onclick="whackmole();"><img src="img/downmole.png" width="37" height="24" alt="Mole peeping out of hole"></button></p></section>
如果您正在使用本书的代码文件,那么音频文件标签应该类似于下面的代码块:
<section><audio id ="boing" autobuffer>
<source src="img/cartoonboing.ogg" />
<source src="img/cartoonboing.mp3" /></audio>
<audio id ="impact" autobuffer>
<source src="img/cartoonimpact.ogg" />
<source src="img/cartoonimpact.mp3" /></audio>
<audio id ="squeak" autobuffer>
<source src="img/cartoonsqueak.ogg" />
<source src="img/cartoonsqueak.mp3" /></audio>
<audio id ="whack" autobuffer>
<source src="img/cartoonwhack.ogg" />
<source src="img/cartoonwhack.mp3" /></audio>
<audio id="space" autobuffer>
<source src="img/cartoonspaceboing.ogg" />
<source src="img/cartoonspaceboing.mp3" /></audio>
使用以下标签完成页面:
</section></body></html>
将文件保存为playing-audio-files-with-javascript.html
并在浏览器中查看。它应该看起来类似于以下屏幕截图:
它是如何工作的...
首先,我们创建了一个基本的 HTML5 页面。然后,我们添加了 CSS 样式,为按钮添加了背景图像,并在鼠标或指向设备移动到按钮上时将鼠标图标更改为十字准星。这给我们提供了一个视觉模拟的瞄准武器,比默认的鼠标图标更有趣。
创建了三个变量以在脚本中使用:mySounds,soundElements
和soundch
。我们创建的第一个函数名为whackmole()
包含一个内部变量i
,该变量保存了随机生成的数字的结果。Math.random()
导致生成一个伪随机数。然后我们将其乘以5
,我们的音频文件数量,并将结果用于Math.floor()
以创建一个值范围从零到五的整数。然后将该值分配给临时变量i
,然后用于使用随机生成的数组值填充变量mySounds
。将新的数组值存储在变量soundChoice
中,soundChoice = mySounds[i]
。这使我们能够在按下按钮时使用soundElements[soundChoice].play()
触发audio
标签的play()
动作。
我们创建的第二个函数是init()
,稍后我们将其与onLoad
一起绑定到body
标签,以便我们可以使用audio
标签及其数组值在soundElements
变量中获取音频文件。
接下来,我们添加了<body onLoad="init();">
标签,并在页面上添加了一系列包含可爱的鼹鼠图像的按钮。每个按钮都包含一个onClick()
事件,该事件调用了whackmole()
函数。我们的第三个按钮与其他按钮的类不同,crosshairthree
,它在按钮左侧添加了额外的边距,使其看起来更加居中。
注意
Firefox 目前存在一个怪癖,如果您不首先列出.ogg
音频源,它将无法找到它。
最后,我们使用<audio>
和<source>
标签将声音文件添加到页面中。使用源标签列出了每个文件的ogg
和mp3
格式。因为源标签被认为是其所包围的父音频标签的“子级”,所以根据使用的浏览器不同,任何文件格式都会播放,因为不同的浏览器目前更喜欢不同的声音文件格式。
还有更多...
您可以看到,通过为不同的图像播放不同的声音文件,非常容易创建一个类似于儿童读物的形状或动物的页面的应用程序。
使用 jQuery 控制音频剪辑的外观
jQuery 中的.animate
函数为使音频控件在访问者采取行动时出现,淡出和消失提供了新的方法,这是丰富媒体体验的一部分。以下是一个示例,演示了如何使音频控件淡出,然后迅速重新出现:
<script> $(document).ready(function(){
$('audio').delay(500).hide('fade', {}, 1000 ).slideDown('fast'); }); </script>
<!- - the HTML -- ><audio id ="boing" autobuffer> <source src="img/cartoonboing.ogg" /> <source src="img/cartoonboing.mp3" /></audio>
我们将在本章的一个示例中使用视频文件执行类似的技巧。
另请参阅
第八章 拥抱音频和视频 将涵盖有关音频标签及其使用方式的更多信息。
使用文本的拖放 API
虽然所有浏览器都可以本地拖动图像或链接,但放置对象以前需要复杂的 JavaScript 或第三方库。拖放 API 旨在提供一种更简单,标准化的方式,使用户能够将任何类型的对象放入标识区域。实际上,在不同浏览器中使用该 API 是一项挑战。目前主要支持此 API 的浏览器是 Firefox,Chrome 和 Safari。
准备就绪
在www.packtpub.com/support?nid=7940
下载本教程的代码。本教程标题中使用的字体来自www.fontsquirrel.com
,您也可以在那里下载不同的字体。本教程可能无法在 Internet Explorer 中使用。我们将创建一个井字棋游戏,演示拖放 API 的工作原理。
如何做...
打开您的 HTML 编辑器,首先创建一个基本的 HTML5 页面。我们将添加两个样式表链接,一个用于支持我们将为页面标题加载的@fontface
字体,另一个用于我们的主样式表。输入以下代码,然后将文件保存为using-drag-drop-api.html
。
<!DOCTYPE html><html lang="en"> <head> <meta charset="utf-8"> <title>Using the drag-and-drop API element</title> <link rel="stylesheet" href="fonts/specimen_files/specimen_stylesheet.css" type="text/css" charset="utf-8" /> <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" />
让我们继续为页面添加样式。创建或打开名为stylesheet.css
的 CSS 文件。将页面的整体margin
设置为100px
,默认颜色设置为#666
。
@charset "UTF-8";/* CSS Document */body { margin:100px; color:#666; }
页面的内容标签应该都设置为display:block
,如下面的代码所示:
article, aside, figure, footer, header, hgroup, menu, nav, section { display:block; }
现在,我们指定@fontface
信息。代码和字体文件来自于www.fontsquirrel.com
字体包,该字体包包含在本教程的代码文件中。
@font-face { /* This declaration targets Internet Explorer */ font- family: '3DumbRegular';src: url('3dumb-webfont.eot');}@font-face {/* This declaration targets everything else */font-family: '3DumbRegular';src: url(//:) format('no404'), url('fonts/3dumb- webfont.woff') format('woff'), url('fonts/3dumb-webfont.ttf') format('truetype'), url('fonts/3dumb-webfont.svg#webfontlNpyKhxD') format('svg');font-weight: normal;font-style: normal;}
为h1
标签添加颜色,并将font-family
属性设置为3DumbRegular
,这是我们字体的名称。
h1{color:#C60;font-family: '3DumbRegular';}
创建一个名为gametilebox
的新 div 来容纳组成游戏块的字母。将该框的float
属性设置为left
,宽度和高度设置为280px
。按照以下代码片段中所示的方式设置padding, margin-right, border
和background-color
。
#gametilebox{ float:left;width:280px; height:280px; padding:10px; margin-right:30px; border:1px solid #000; background-color:#ccc; }
游戏板将共享许多与瓷砖框相同的属性,因此复制gametilebox
的样式,粘贴并命名为“gameboard”。添加一个background-image
属性,其 url 为images/tictactoegrid.jpg
,并将background-color
设置为aa
。
gameboard div
应该看起来像以下代码:
#gameboard { float:left; width:280px; height:280px; padding:10px; margin-right:30px;border:1px solid #000; background-image:url(images/tictactoegrid.jpg); background-color:#aaa;}
让我们为放置字母的div
块添加样式。所有block
div 的float
应该设置为left
。width
不应大于85px
,height
不应大于80px
。它们将位于 3x3 的网格上,因此第二行和第三行的第一个块也需要具有clear:both
属性。第二行和第三行的第三个块应该具有较低或没有padding
和margin-right
属性。因为有九个,所以这里只显示了一个块代码的示例:
#blockA {float:left; width:75px; height:75px; padding:5px 5px 5px 2px; margin-right:10px; border:none; background-color:red;}
#blockB {float:left; width:75px; height:75px; padding:5px; margin-right:10px; border:none; background-color:blue;}
现在,我们将为字母游戏块设置样式。在样式表中创建一个名为lettertile
的新类,然后按照以下方式设置类的属性:
.lettertile { width:60px; height:60px; padding:5px; margin:5px; text-align:center; font-weight:bold;font-size:36px;color:#930; background-color:transparent;display:inline-block;}
我们将添加的最后一个样式是draggable
属性。创建下面的样式以帮助跨浏览器兼容性:
*[draggable=true] { -moz-user-select:none; -khtml-user-drag: element; cursor: move;}
样式表已经完成,现在我们可以开始编写脚本来拖动字母块并放置它们。
打开先前创建的 html 页面using-drag-drop-api.html
,并为 IE 浏览器键入以下代码:
<!--[if IE]><script src="img/html5.js"> </script><![endif]-->
在样式表链接的下面添加一个开放的<script>
标签,并键入第一个函数dragDefine(ev)
,它接受一个事件参数,然后跟着一个{
。在大括号之后,键入ev.dataTransfer.effectAllowed ='move'
;然后,在新的一行上,键入ev.dataTransfer.setData("text/plain", ev.target.getAttribute('id'))
;以设置数据类型和目标属性。最后,键入return true
;并加上一个闭合的}
以完成函数。
function dragDefine(ev) {ev.dataTransfer.effectAllowed = 'move'; ev.dataTransfer.setData("text/plain", ev.target.getAttribute('id')); return true;}
现在,我们需要定义dragOver
函数。键入dragOver(ev)
和一个开放的{
,然后通过添加ev.preventDefault()
来调用preventDefault()
函数。函数块应该类似于下面的代码:
function dragOver(ev) { ev.preventDefault();}
我们需要的下一个函数是指示拖动完成的函数。键入function dragEnd(ev)
,然后输入{
。键入return true; }
以完成函数。
键入function dragDrop(ev)
并打开一个{
,然后转到新的一行添加我们的第一个方法。键入var idDrag = ev.dataTransfer.getData("Text")
;创建一个将保存文本字符串的拖动变量,然后键入ev.target.appendChild (document.getElementById(idDrag))
;。最后,键入ev.preventDefault()
;完成函数块应该看起来像以下代码:
function dragDrop(ev) {
var idDrag = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(idDrag));
ev.preventDefault();} </script>
关闭页面的头部部分。键入<body><header>
,然后<h1>拖放井字棋</h1></header>
以完成页面的标题。
</head><body><header><h1>Drag and Drop Tic Tac Toe</h1></header>
接下来,键入<section><h3>将字母从灰色框拖到游戏板上(然后再拖回来!)</h3>
。
创建一个 ID 为"gametilebox"
的 div,并设置ondragover ="dragOver(event)"
和ondrop="dragDrop(event)"
。它应该看起来像以下语句:
<div id="gametilebox" ondragover="dragOver(event)" ondrop="dragDrop(event)">
现在,我们将为每个游戏瓷砖创建一个div
。创建六个"X" 瓷砖和六个"O" 瓷砖,每个都以"lettertile"
开头并以值从1-12
的数字结尾的id
。每个div
将包含类"lettertile"
,每个draggable
属性将包含值"true"
。每个瓷砖还将包含ondragstart="return dragDefine(event)"
和ondragend="dragEnd(event)"
。div
块应该看起来像以下代码:
<div id="lettertile1" class="lettertile" draggable="true" ondragstart="return dragDefine(event)" ondragend="dragEnd(event)">X</div>
<div id="lettertile2" class="lettertile" draggable="true" ondragstart="return dragDefine(event)" ondragend="dragEnd(event)">X</div>
<div id="lettertile3" class="lettertile" draggable="true" ondragstart="return dragDefine(event)" ondragend="dragEnd(event)">X</div>
现在,我们可以为我们在stylesheet.css 中创建的那些块样式创建实际的divs
。首先输入<div id= "gameboard">
。应该有一个div
对应每个块 id,从"blockA"到"blockI"。它们每个都将包含一个ondragover="return dragOver(event)"
和一个ondrop="dragDrop(event)"
。它们应该看起来像以下代码块。
<div id="blockA" ondragover="return dragOver(event)" ondrop="dragDrop(event)"></div>
<div id="blockB" ondragover="return dragOver(event)" ondrop="dragDrop(event)"></div>
<div id="blockC" ondragover="return dragOver(event)" ondrop="dragDrop(event)"></div>
使用body
和html
结束标签关闭页面,将文件命名为"using-drag-drop-api.html"
,然后在浏览器窗口中查看结果。拖动几个字母,结果应该类似于以下截图:
工作原理...
首先,我们创建了一个基本的 HTML5 页面,并使用@fontface
添加了一个草图字体作为标题,以使我们的游戏具有有趣的视觉效果。接下来,我们通过将margin
设置为body
和所有块级元素来设置页面的样式,以更好地控制这些元素的呈现。在设置标题字体样式后,我们为游戏瓷砖框定义了width
和height
。这将是容纳组成游戏瓷砖的字母的容器。
我们通过在 IE 浏览器中键入一个特殊的注释标签来开始我们的脚本,以指向额外的脚本文件来触发 HTML5 元素:<!--[if IE]><script src="img/html5.js"></script><![endif]-->
。这是由 Remy Sharp (http://remysharp.com/html5-enabling-script/ )根据 MIT 许可证提供的,可以让我们在处理 Internet Explorer 时保持理智。
dragDefine()
函数在用户开始拖动物品时被调用。它首先使用dataTransfer.effectAllowed='move'
来检查物品是否可拖动。然后使用dataTransfer.setData("text/plain")
设置要传输的数据类型为text
,并使用target.getAttribute('id'))
来识别目标的id
。该函数返回 true,表示可以拖动对象。
接下来,我们定义了dragOver
函数,当被拖动的物品位于另一个物品上方时调用,接受一个名为ev
的事件参数,然后用它来调用preventDefault()
以允许放置物品。拖放 API 规范明确规定,我们必须取消拖动,然后准备放置。
然后创建了dragEnd()
函数,在拖动完成时返回 true。它还接受一个事件参数。
完成所有拖动功能后,我们准备创建代码来放置物品。dragDrop()
函数接受一个事件参数,并使用该值获取文本对象的值,然后将其传递给一个新变量var idDrag
来保存文本字符串,然后再使用getElementById
来识别正确的元素 ID 进行放置。与dragEnd()
一样,我们必须调用拖放 API 中的preventDefault()
函数来指示可以放置对象。
在关闭页面的头部区域后,我们在正文中放置了内容框来容纳我们的字母瓷砖和游戏板。这些由两个父 div 容器组成,每个容器都包含包含字母瓷砖或游戏板网格部分的子 div。
每当字母瓷砖被拖动到游戏瓷砖框上时,游戏瓷砖框都会调用dragOver()
函数。字母瓷砖 div 本身通过draggable="true"
可拖动,并在拖动时返回dragDefine()
。拖动停止时,它们调用dragEnd()
函数。
因为我们希望字母瓦片在游戏板的特定区域内下落并停留,所以我们为网格上的每个单独块创建了 div,以便在它们被放置到板上时保持我们的字母位置,并在对象被拖动到它们上时返回dragOver
事件,并在对象被放置到它们上时调用dragDrop()
。
为什么要使用块 div?我们本可以在左边设置我们的游戏瓦片框,在右边设置游戏板,然后完成。结果将是,当我们从左边的框拖动瓦片到游戏板时,它们会被放置在上面,并按照它们被放置的顺序排列,而不是我们想要放置它们的位置。当您想要对列表进行排序时,默认行为是可以接受的,但当需要精确控制对象放置位置时,就不行了。
我们需要覆盖对象被放置时产生的默认行为。我们创建了九个游戏板块,都是相同的基本大小。每个块的主要变化是padding
和margin
。
花一些时间阅读www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html
上的拖放规范,你会注意到他们明确表示他们只定义了一个拖放机制,而不是你必须执行的操作。为什么?使用智能手机或其他触摸屏设备的用户可能没有鼠标等指针设备。
还有更多...
拖放 API 的演示可以通过多种方式构建成一个完整的游戏,包括计分;游戏板重置按钮和其他交互元素。
创建基于画布的井字棋游戏
可以使用两个画布,一个用于游戏瓦片框,另一个用于游戏板。可以使用画布动态绘制板和游戏瓦片,然后将分数或消息(如“你赢了”)写入屏幕。
在用户玩游戏时显示响应消息
Remy Sharp 在html5demos.com/drag-anything
上有一个很棒的演示,展示了当对象被放置时如何在屏幕上显示消息。
要放置的对象的源标记可能类似于:
<div id="draggables"><img src="img/picean.png" alt="Fish" data-science-fact="Fish are aquatic vertebrates (animals with backbones) with fins for appendages." /> </div>
当对象被拖动到时,“放置区”框可能看起来像:
<div class="drop" id="dropnames" data-accept="science-fact"> <p>Learn a science fact!</p> </div>
当图像被放置到框中时,您会看到包含“data-science-fact”的文本,而不是图像。
另请参阅
jQuery 的 Packt 书籍,本书中的其他配方,高级 HTML5 Packt 书籍。
使用 vid.ly 和 jQuery 支持跨浏览器的视频
支持大多数浏览器需要将视频编码为多种格式,然后将正确的格式提供给浏览器。在这个示例中,我们将使用一个名为 vid.ly 的在线视频显示库(www.vid.ly
)来在多个浏览器上可靠地准备和分享视频,并使背景颜色随时间变化。
准备工作
您需要一个视频上传到www.vid.ly
。一些浏览器不允许本地提供文件,因此您可能还需要一个可以上传文件并测试页面的位置。
如何做...
键入<!DOCTYPE html> <html lang="en"> <head>
,然后开始添加样式声明,键入<style type="text/css"> h2{color:#303;}
。
样式化一个包含特色内容的 div:#featured {position:relative; padding: 40px; width: 480px; background-color:#000000; outline: #333 solid 10px; }
。
键入video {padding: 3px;background-color:black;}
来创建视频标记的样式,然后添加一个闭合的</style>
标记。
声明页面中使用的脚本。输入<script src="img/jquery.min.js" type="text/javascript" charset="utf-8"></script>
来引用主要 jQuery 库的最小化版本。然后,输入<script type="text/javascript" src="img/jquery-ui.min.js"></script>
来引用用于颜色变化效果的 jQuery UI 库。最后,我们将引用我们自己的脚本,通过在关闭</head>
标签之前输入<script type="text/javascript" src="img/mycolor.js"></script>
。
输入一个开放的<body>
和<section>
标签,然后输入<header> <h2>Featured Video</h2></header>
以显示页面标题。
现在,我们可以创建一个 div 来容纳我们之前设计的特色内容。输入<div id="featured"> <p>此视频已通过<a href="http://vid.ly">vid.ly</a>转换为跨浏览器格式</p>
。
下一步是将视频剪辑上传到vid.ly
进行转换成多个文件格式。当过程完成时,您将收到一封电子邮件,然后可以获取视频的代码片段,如下面的屏幕截图所示:
复制网站上的代码,然后粘贴到您的页面中。视频和脚本标签中的src
值应该是 vid.ly 给出的 URL。代码块应该如下所示:
<video id= "vidly-video" controls="controls" width="480" height="360"> <source src="img/7m5x7w?content=video"/> <script id="vidjs" language="javascript" src="img/html5.js"></script> </video>
为了增加一点额外的乐趣,让我们在页面上添加另一个视频标签。输入以下代码:<p>哎呀,这是一个宝宝视频!</p>
,为视频标签使用不同的 id 并调整大小如下:<video id="tinymovie1" controls="controls" width="190" height="120">
,然后使用相同的源标签:<source src="img/7m5x7w?content=video"/><script id="vidjs" language="javascript" src="img/html5.js"></script></video>
,然后关闭页面:</div> </section></body></html>
。将文件保存为display-videos-using-videly.html
。
我们要做的最后一件事是创建一个 jQuery 脚本来改变#featured
div 的背景颜色。打开您的编辑器,创建一个名为myColor.js
的新文件。
输入$(document).ready(function() {
,然后转到新行并输入将调用动画函数并改变背景颜色的代码:$('#featured').animate({'backgroundColor':'#ff3333', 'color': '#ffffff'}, 6000);})
;。
在浏览器中加载页面,观察主视频加载时颜色的变化。您可以看到以下屏幕截图显示了它应该是什么样子:
它是如何工作的...
首先,我们创建了一个标准的 HTML5 页面,并开始添加样式声明。我们将featured
div 的位置设置为相对位置,以便在将来如果我们决定添加额外的 jQuery 效果时具有更大的灵活性。通过将padding
设置为40px
,将outline
颜色设置为深灰色并设置为10px
的粗细,创建了强烈的视觉效果。默认的背景颜色设置为黑色(#000000)
,以便与最终的红色背景进行高对比度的比较。
接下来,我们对video
标签进行了样式设置,使其在加载时具有黑色的background-color
。我们还可以在这里添加一个背景图像作为海报。
接下来,使用<script src="img/jquery.min.js" type="text/javascript" charset="utf-8"></script>
声明了基本的 jQuery 脚本。因为它不包含animate()
等效果,我们还需要引用用于颜色变化效果的 jQuery UI 库的最小化版本。然后,我们通过输入<script type="text/javascript" src="img/mycolor.js"></script>
来添加对我们自己脚本的引用。进一步减小脚本文件大小的另一种方法是创建一个自定义脚本,其中只包含来自 jQueryUI 库的动画效果。
接下来,我们创建了主页内容,包括指向 vid.ly 上视频的链接。 vid.ly 提供的默认代码会给video
标签应用一个 ID 为'vidley video'
,但如果你想使用自己的样式 ID 或者为每个视频使用不同的 ID,那么可以省略这一部分。另一个选择是给所有视频分配相同的类,然后根据需要分配它们唯一的 ID。
另请参阅
第八章,拥抱音频和视频 更详细地介绍了视频元素。
使用 jQuery 动态显示视频
视频元素使我们能够像处理图像一样处理视频,并以有趣和令人兴奋的方式操纵它们。
准备工作
你需要一个以多种文件格式提供的视频(本书的章节代码中提供了这些格式)。建议将文件上传到服务器,因为并非所有浏览器都能以可预测的方式本地播放文件。
如何做...
首先,我们需要准备一个 HTML5 页面来放置它。输入我们页面的开头标签:<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>Video Explosion</title>
。
打开下载的代码文件中的stylesheet.css
文件,或者创建一个同名的新文件。
为 body 输入以下内容style: body {background: white;color:#333333; }
,然后按照以下方式为 div 标签添加样式:div {float:left; border:1px solid #444444;padding:5px;margin:5px; background:#999999;}
。
我们需要创建和样式化的第一个唯一的 div 是#featured
。输入#featured {position:relative; width: 480px; background-color:#f2f1f1;}
来创建样式。
现在创建一个名为details
的 div 来容纳一个小的信息框。输入#details{ position:relative;display:block;background-color:#6CF;color:#333333; padding:10px;}
来创建一个将显示在featured
div 旁边的 div。
保存css
文件,并在 html 页面的头部使用链接标签引用它,输入<link rel="stylesheet" href="css/stylesheet.css"type="text/css" media="screen" charset="utf-8"/>
。
在样式表链接下方输入以下主 jQuery 库的链接:<script src="img/jquery-latest.js" type="text/javascript" charset="utf-8"></script>
,然后在这个配方的代码文件中链接到 jQuery UI 库,输入<script type="text/javascript" src="img/jquery-ui.min.js"></script>
。最后,通过输入<script type="text/javascript" src="img/explode.js"></script>
来添加对即将创建的脚本的引用,以完成引用的脚本。
创建一个新文件并命名为explode.js
,并将其存储在一个名为js
的新子文件夹中。输入$(document).ready(function(){}
。在两个大括号({})之间输入$('h1').effect('shake', {times:5}, 200)
;创建一个语句,将导致 featured div 标签中包含的内容爆炸。在新的一行上,输入$('#featured').effect('shake', {times:3}, 100).delay(500).hide('explode',{}, 2000).slideDown('fast');)
;以完成脚本。你的代码块应该类似于以下代码块:
$(document).ready(function(){ $('h1').effect('shake', {times:5}, 200); $('#featured').delay(2000).hide('explode', {}, 2000 ).slideDown('fast'); });
保存文件并返回到 html 页面。
在 HTML 文件中添加</head>
的闭合标签和<body>
的开头标签。接下来,输入一个开头的<header>
标签和标题文本:<h1>Featured Moto Video</h1>
,然后输入</header>
标签以完成头部区域。
创建一个开头的<section>
标签,然后输入<div id="featured">
,来容纳我们的视频标签和相关元素。输入<video id="movie" width="480" height="360" preload controls>
,然后为三种视频文件类型添加一个源标签:<source src='motogoggles.ogv' type='video/ogg; codecs="theora, vorbis"'/> <source src='motogoggles.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'/> <source src='motogoggles.webm' type='video/webm; codecs="vp8, vorbis"'/>
,然后关闭</video>
标签和</div>
标签。
最终的内容块包含在details
div 中。要创建它,输入<div id="details">
,然后添加一个带有文本的标题标签<h1>Details</h1>
,最后是一个简短的解释性文字段落:<p>视频将爆炸然后再次出现!</p>
。关闭</div></section> </body></html>
标签。将 HTML 文件保存为exploding-video-dynamically.html
,在浏览器中打开以查看结果。它们应该与以下截图类似,显示视频分成几个部分并爆炸。
它是如何工作的...
stylesheet.css
文件包含了特色 div 的样式,确定了页面上视频对象的定位。首先要注意的是position
被设置为relative
。这使我们能够使用 jQuery 移动视频对象并对其执行其他操作。
我们创建了一个名为details
的 div,其position
也是relative
,但background-color
设置为浅蓝色(#6CF)
。不同的颜色将有助于在视觉上将其与视频对象区分开来。
接下来,我们添加了 jQuery 库脚本。为了能够访问animate
类中包含的方法和函数,需要引用 jQuery UI 库。在这个例子中,我们是在本地引用它,但您也可以像访问主要的 jQuery 库一样链接到它。
最后,我们能够编写自己的脚本来使页面上的元素摇晃和爆炸!我们创建了一个语句来验证页面是否准备好接受我们的代码,方法是输入$(document).ready(function(){}
。这个函数查询 DOM 并询问页面是否已加载并准备好接受脚本。在创建 jQuery 脚本时,使用这个包装函数是最佳实践。我们使用别名符号$
来调用 jQuery 函数,抓取h1
选择器并对其应用包含shake
参数的effect
动作,使元素侧向移动,其中又包含了摇动元素的次数参数。摇动应持续的时间间隔以毫秒定义,本例中为200
。我们使用选择器$('#featured')
来抓取特色 div 元素,并像对h1
标签所做的那样,对其进行shake
操作(只摇动三次以增加变化),每次摇动持续100
毫秒。现在我们添加了一些新的动作。在shakes
和爆炸之间添加了500
毫秒的delay
命令,使用.delay(500)
。然后我们附加了hide
动作,参数为explode
,默认情况下将发生一次,持续时间为2000
毫秒。视频爆炸后,slidedown
动作以fast
参数将其滑回屏幕上。请注意,爆炸所用的时间有点长,这样我们可以更容易地看到它。使用100-500
毫秒的时间间隔会产生更真实的爆炸效果。如果您只想要视频本身而不是特色标签提供的背景或边框,也可以直接使用$('video')
来抓取视频标签。
回到 HTML 文件,我们将视频放在一个名为featured
的容器 div 中,并创建了一个父video
标签,它将preload
并包含默认的controls
。在关闭video
标签之前,我们在其中嵌套了三种视频文件类型的source
标签,以便不同浏览器的用户可以观看视频:我们没有提供 FLASH 回退,但我们可以使用 JavaScript 库,比如Video.js
。然后我们关闭了</video>
标签和特色 div 标签</div>
。
最后,我们创建了一个 div 来保存关于用户可以期待在details
div 中发生的信息。
还有更多...
视频元素、JavaScript 和 canvas 标签还有很多可以做的事情。继续阅读更多实验。
使用视频和画布进行更多交互式爆炸
Sean Christmann 在www.craftymind.com
上有一个令人惊叹的实验,可以让您在视频播放时实时爆炸多个部分,使用多个画布。您可以在这里查看:www.craftymind.com/2010/04/20/blowing-up-html5-video-and-mapping-it-into-3d-space/
,但请注意——在 Firefox 中这会消耗大量资源。
爆炸是怎么回事?
乍一看似乎没有任何真正的实际原因来首先分解视频。然而,这对于模仿独特的过渡效果或对用户在游戏中的操作做出响应可能非常有用。
实时色度键背景替换
Firefox 开发人员一直在尝试操纵视频元素。他们创建了一个教程,解释了他们如何使用画布、JavaScript 和视频元素的属性执行色度键替换。您可以在developer.mozilla.org/En/Manipulating_video_using_canvas
上阅读相关内容并查看演示。
想象一下在网站上显示视频,其中展示了异国情调的背景或者创建了产品和人的互动混搭。
另请参阅
本书的第八章拥抱音频和视频 中深入探讨了视频元素。
使用 jQuery 移动视频广告
我们将在网站上创建一个视频广告,当用户向下滚动页面时,它会移动,使用 jQuery 和视频标签。
准备工作
您将需要多种格式的视频文件,如.ogg/.ogv, .mp4
和.webm
,或者使用视频服务,如www.vid.ly.com
来提供跨浏览器视频。这个例子没有在 Internet Explorer 中进行测试,但应该在 Safari、Google Chrome、Opera 和 Firefox 的最新版本中正常工作。
如何做…
我们将首先创建一个典型的网站页面。在编辑器中打开一个新文件,并将其保存为movable-video-ad.html
。输入<!DOCTYPE html> <html lang="en"><head><meta charset="utf-8" /><title>Movable Video Ad</title>
来放置页面上的第一个标签。
现在,为我们的默认样式表创建一个引用链接<link rel="stylesheet" href="css/main.css" type="text/css" media="screen" charset="utf-8" />
,以及一个名为<link rel="stylesheet" href="css/scroll.css" type="text/css" media="screen" charset="utf-8" />
的辅助样式表。
接下来,为 jQuery 脚本创建引用链接。输入<script src="img/jquery-1.4.min.js" type="text/javascript" charset="utf-8"></script>
来引用核心 jQuery 代码。添加链接语句<script type="text/javascript" src="img/jquery-ui-1.7.2.custom.min.js"></script>
。我们将链接到的最终脚本是我们为名为myAd.js
的配方创建的自己的脚本,它将存储在我们创建的名为"js"的子文件夹中。输入<script type="text/javascript" src="img/myAd.js"></script>
来链接到该文件。
输入</head><body><div id="container">
来开始页面的内容区域。通过输入<header> <h1>Motocross Mania</h1></header>
来显示页面标题。
开始添加页面内容,输入<div id="content"> <h2>No dirt = no fun</h2>
。现在可以通过输入文本<div id="motoad"><h3>Buy this movie!</h3>
,然后在段落元素标签中包含电影标题<p><strong>MotoHelmet</strong></p>
来添加包含广告的 div 到页面中。
然后应该添加一个视频标签<video width="190" height="143" preload controls>
。输入包含每种视频格式的源标签,如下面的代码块所示:
<source src='video/motohelmet.ogv' type='video/ogg; codecs="theora, vorbis"'/> <source src='video/motohelmet.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'/> <source src='video/motohelmet.webm' type='video/webm; codecs="vp8, vorbis"'/></video>
关闭</div>
标签并保存目前的进展。
创建一个带有 id 为 intro 的段落<p id="intro">
来包含文本We review the best motorcross gear ever!!!
。在段落标签和文本后面跟着一个虚拟链接列表:<ul><li><a href="#">Helmets</a></li> <li><a href="#">Gloves</a></li><li><a href="#">Goggles</a></li></ul>
,用</p>
关闭段落,然后创建一个新的 div 来包含一个虚拟新闻内容块,然后是另外两个虚拟 div 块,一个页脚标签和关闭页面元素,如下面的代码块所示:
<div id="news"><h2>Latest News</h2> <p>Trip Ousplat admits he doesn't do his own stunts! "My mom makes
me use a stunt double sometimes," The shy trick-riding sensation explains.</p> <p>Gloria Camshaft smokes the competition for a suprise win at the Hidden Beverage Playoffs</p> <p>Supercross competitors report more injuries; jumps more extreme than ever</p><p>James Steward still polite, reporters bored</p>
</div><div id="filler"><h2>On Location</h2> <p>Grass is not greener as there is no grass on most motorcross trails experts claim </p></div> <p id="disclaimer">Disclaimer! Anything you choose to do is at your own risk. Got it? Good.</p><footer><p>© Copyright 2011 Motocross Extreme Publications, Inc.</p></footer></div></body></html>
现在,我们将在main.css
文件中为页面元素设置样式。第一个关键样式是#container
div。它应该有一个0 auto
的边距和650px
的宽度。接下来,#motoad
div 应该被设置为右浮动
,并包含一个200px
的宽度来容纳视频元素。最后,#intro
div 应该包含一个较短的宽度450px
。这三种样式应该类似于下面显示的代码块:
#container{ margin:0 auto;text-align:left; width: 650px;}
#motoad{ float:right;width:200px;}
#intro{width:450px;}
其余的样式都是对填充和颜色或其他标准声明的微小调整。
现在,打开scroll.css
文件来定义样式,以帮助我们的广告滚动。我们将级联#motoad
的属性,以形成一个可以移动的 div 块。接下来,定义#content
属性的height
,以及段落和h2
元素的宽度。scroll.css
中的样式现在应该如下所示:
#motoad {display:block;position: relative; background-color:#FC0;width:200px;padding:10px;}
#content { height:1000px;}
p {width:450px;}h2 {width:460px;}
保存文件,并准备创建我们的 jQuery 脚本。
打开或创建myAd.js
,并开始输入文档准备函数$(document).ready(function(){}
和花括号。在花括号之间点击 enter,并输入滚动函数$(window).scroll(function() {
。在该函数的开花括号后面输入命令:$('#motoad').stop().animate({top: $(document).scrollTop()},'slow','easeOutBack')
;。用" });});"关闭脚本。我们的 jQuery 脚本现在应该看起来像下面的代码块:
$(document).ready(function(){ $(window).scroll(function() { $('#motoad').stop().animate({top: $(document).scrollTop()},'slow','easeOutBack'); }); });
保存所有文件,并在浏览器窗口中加载 HTML 页面。在开始滚动页面之前,页面应该看起来像下面的截图。
尝试上下滚动页面。广告应该随着页面的上下移动而上下移动。结果应该类似于以下截图:
它是如何工作的...
在创建具有不同内容元素的典型 HTML 页面后,我们准备为 CSS 页面设置样式。我们将 CSS 分为两个文件,main.css
和scroll.css
,这样当我们在 jQuery 脚本中调用滚动函数并积极应用它时,页面上的内容元素会缩小,以便我们的广告可以轻松移动,而不会阻塞页面上的任何信息。
我们希望在调用窗口滚动事件时使#motoad
div 标签移动。为此,我们使用别名符号$
来抓取 DOM 中的window
选择器,并将其应用于包含默认滚动动作参数的scroll
动作。使用这个函数,我们然后创建了控制#motoad
div 块行为的命令。我们给它了stop
的动作,这样它就准备好进行动画了。animate
动作被链接到stop
命令。我们应用到#motoad
div 的animate
的第一个参数使得 div 在文档窗口中的滚动条移动时移动。slow
参数控制了广告上下移动的速度,easeOutBack
参数引用了一个缓动命令,以创建流畅的动画运动,而不是突然开始或停止。
还有更多...
在这个示例中,我们通过使其响应页面上的用户操作来为自定义 HTML 元素添加动画效果。这只是我们可以微妙地添加效果的一种方式,可以用于实际解决方案。
有 HTML 元素,就会旅行
探索 jQuery UI 库,你会被许多可以操纵和样式化任何 HTML 元素的方式所启发。访问jqueryui.com
查看演示和文档。
另请参阅
学习 jQuery:使用简单的 JavaScript 技术实现更好的交互设计和 Web 开发,可从 Packt Publishing 获取。
使用 Easel.js 和 canvas 标签控制图像的显示
JavaScript 库Easel.js
减少了使用canvas
标签创建动画和丰富交互环境的复杂性。在这个示例中,我们将使用一个名为"sprites"的单个文件中的一系列图像,以展示如何使用Easel.js
来控制精灵中选择性显示的图形图像。
准备工作
您需要下载Easel.js
库,或者使用本示例的代码文件中的副本。
如何做...
创建一个 HTML5 文件的开头标签。您的代码应该类似于以下代码块:
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title> Animating images using BitmapSequence and SpriteSheet</title>
接下来,链接到在本示例中使用的主样式表styles.css
:。
接下来,我们将通过插入以下脚本文件的链接来导入Easel.js
框架库:UID.js, SpriteSheetUtils.js, SpriteSheet.js, DisplayObject.js, Container.js, Stage.js, BitmapSequence.js
和Ticks.js
。您可以在这里看到每个脚本文件的路径和链接:
<script src="img/UID.js"></script><script src="img/SpriteSheetUtils.js"></script><script src="img/SpriteSheet.js"></script><script src="img/DisplayObject.js"></script><script src="img/Container.js"></script><script src="img/Stage.js"></script><script src="img/BitmapSequence.js"></script><script src="img/Tick.js"></script>
接下来,创建一个开头的<script>
标签,并声明以下三个变量:var canvas; var stage; var critterSheet = new Image()
;用于我们的脚本。
输入function init(){
开始函数,并跟随canvas = document.getElementById("testCanvas")
;将页面主体中的 canvas 与 canvas 变量绑定。通过输入critterSheet.onload = handleImageLoad
;准备加载一个新的spriteSheet
。critterSheet
变量存储精灵图像的来源。输入critterSheet.src = "images/moles.png"
;加载我们自己的一系列鼹鼠图像。函数块应该像下面的代码块一样:
function init() {
canvas = document.getElementById("testCanvas");
critterSheet.onload = handleImageLoad;
critterSheet.src = "images/moles.png";}
我们将创建的第二个函数是handleImageLoad()
。输入function handleImageLoad() {
然后输入stage = new Stage(canvas)
;创建一个新的 stage 实例。输入var spriteSheet = new SpriteSheet(critterSheet, 76, 80);
创建一个新的spriteSheet
。创建一个名为critter1
的新位图序列变量,并使用 x 和 y 坐标定义其在舞台上的位置,输入:var critter1 = new BitmapSequence(spriteSheet); critter1.y = 85; critter1.x = 85
;。通过输入critter1.gotoAndStop(1)
从我们的精灵表moles.png
中添加一个 critter。然后使用命令stage.addChild(critter1)
将其添加到舞台上。
克隆我们创建的第一个critter1
变量,并通过输入var critter2 = critter1.clone()
将其值传递给一个新的 critter 变量。通过添加critter2.x += 120
将新变量定位到第一个 critter 的右侧。
输入critter2.gotoAndStop(0)
为critter2
变量赋值。克隆 critter 1 和 critter 2 的代码块应该如下所示的代码块:
var critter2 = critter1.clone();
critter2.x += 120;
critter2.gotoAndStop(0);
stage.addChild(critter2);
Tick.setInterval(300)
;和Tick.addListener(stage)
;是我们将添加到脚本的最后两个语句。关闭handleImageLoad()
函数的大括号(}),然后输入一个闭合的脚本标签。
关闭</head>
标签,然后输入带有onload
属性的开头body
标签,调用init()
函数。为内容创建一个名为"description"的 div。添加一个名为canvasHolder
的 div 来包含 canvas 元素。在页面底部显示图像文件moles.png
。
<body onload="init();">
<div class="description">Using <strong>BitmapSequence</strong> to animate images from a <strong>SpriteSheet</strong>.
</div>
<div class="canvasHolder">
<canvas id="testCanvas" width="980" height="280" style="background-color:#096"></canvas> </div> </p><p>The original moles.png spritesheet file with all the images:<br/><img src="img/moles.png"/></p> </body></html>
将文件保存为whack-mole-easel-test-single.html
。结果可以在以下截图中看到:
它是如何工作的...
在设置 HTML5 页面的开头之后,我们准备导入Easel.js
框架并创建我们的主要脚本。
我们创建了一个开头的<script>
标签,并声明了以下全局变量:var canvas; var stage; var critterSheet = new Image()
;用于我们的脚本。
当页面加载时,将调用创建的init()
函数。它包含了canvas
变量,该变量正在被分配选择器testCanvas
,使用document.getElementById("testCanvas")
将页面主体中的画布与画布变量绑定。接下来,我们准备通过输入critterSheet.onload = handleImageLoad
来加载一个新的spriteSheet
。critterSheet
变量存储了精灵图像的来源。输入critterSheet.src = "images/moles.png"
使我们能够访问我们自己的一系列鼹鼠图像。
我们创建的第二个函数是handleImageLoad()
。在这个函数中,我们做了大部分的工作,首先创建了一个舞台的新实例,使用stage = new Stage(canvas)
。接下来,我们使用var spriteSheet = new SpriteSheet(critterSheet, 76, 80)
创建了一个新的spriteSheet
。
现在我们有了一个精灵图实例,我们可以创建一个新的位图序列变量,称为critter1
,并定义其在舞台上的位置,使用 x 和 y 坐标,输入:var critter1 = new BitmapSequence(spriteSheet);critter1.y = 85;critter1.x = 85
。接下来,我们通过数字引用我们想要添加的帧,以便首先将正确的动作应用于 critter,然后应用于舞台。我们通过输入critter1.gotoAndStop(1)
将critter1
变量链接到我们精灵表moles.png
上的第二个图像。我们使用命令stage.addChild(critter1)
将图像添加到舞台上。
我们克隆了我们创建的第一个critter1
变量,并通过输入var critter2 = critter1.clone()
将其值传递给一个新的 critter 变量。我们通过添加到其当前位置值来将新变量定位在第一个 critter 的右侧,使用critter2.x += 120
。我们通过命令BitSequence
去到moles.png
上的第一个图像的位置,并在那里停止,并将其分配给critter2
变量。
我们添加了Tick.setInterval(300)
,在Ticks
之间应用了300
毫秒的时间间隔。Tick 接口充当全局定时设备,使我们能够返回每秒的帧速率(FPS)(如果需要的话)。我们向舞台添加了一个监听器Tick.addListener(stage)
,它像其他类型的监听器一样监听Ticks
。这可以用来在指定的时间重新绘制舞台,或执行其他与时间相关的操作。
我们使用onload
属性在body
标签中调用init()
函数。这会导致init()
函数在页面加载时被调用。
另请参阅
制作图像序列 教程。
使用 Easel.js 和 canvas 标签来制作图像序列动画
我们可以通过使用Easel.js
JavaScript 库创建数组和函数来操纵canvas
元素,从而制作称为精灵的图像条的动画。在本教程中,我们将制作相同的图像条动画,但显示两个不同时间序列。
准备工作
下载本教程的代码文件,使用Easel.js
框架库以及支持文件。您需要一个能够正确显示 HTML5 元素并测试本教程中使用的代码的最新浏览器。
如何做...
创建一个 HTML5 文件的开头标签。您的代码应该类似于以下代码块:
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title> Animating images using BitmapSequence and SpriteSheet</title>
链接到本教程中使用的主样式表styles.css
:<link href="styles.css" rel="stylesheet" type="text/css" />
。
通过插入以下脚本文件的链接来导入Easel.js
框架库:UID.js, SpriteSheetUtils.js, SpriteSheet.js, DisplayObject.js, Container.js, Stage.js, BitmapSequence.js
和Ticks.js
。参考前面的示例,了解框架块应该是什么样子。
创建一个开头的<script>
标签,并声明以下三个变量:var canvas;var stage;var critterSheet = new Image()
;用于我们的脚本。
输入function init(){
开始函数,然后跟上canvas = document.getElementById("testCanvas")
。
准备加载一个新的spriteSheet
,键入critterSheet.onload = handleImageLoad
;。键入critterSheet.src = "images/moles.png"
;加载我们自己的一系列鼹鼠图像。函数块应如下所示:
function init() {
canvas = document.getElementById("testCanvas");
critterSheet.onload = handleImageLoad;
critterSheet.src = "images/moles.png";}
我们将创建的第二个函数是handleImageLoad()
。键入函数handleImageLoad() {
然后stage = new Stage(canvas)
;创建一个新的舞台实例。键入var spriteSheet = new SpriteSheet(critterSheet, 80, 80)
;创建一个新的spriteSheet
。现在我们有了一个精灵表,创建一个新的位图序列变量名为critter1
,并使用 x 和 y 坐标定义其在舞台上的位置,键入:var critter1 = new BitmapSequence(spriteSheet)
;然后critter1.y = 100;critter1.x = 90
;。接下来,我们将创建一个数组,将其映射到原始spritesheet
文件上的每个图像,输入var frameData = {shymole:0, upmole:1, downmole:2, whacked:3, whackedow:4, clouds:5,tinycloud:6, cloudgroup:7}
;这样我们就有了八个名称值,每个名称值都与一个数组 id 相关联。
到目前为止,handleImageLoad()
的代码块应如下所示:
function handleImageLoad() {
stage = new Stage(canvas);
var spriteSheet = new SpriteSheet(critterSheet, 80, 80);
var critter1 = new BitmapSequence(spriteSheet);
critter1.y = 100;
critter1.x = 90;
var frameData = {shymole:0, upmole:1, downmole:2, whacked:3, whackedow:4, clouds:5,tinycloud:6, cloudgroup:7};
通过键入spriteSheet = new SpriteSheet(critterSheet, 80, 80, frameData)
;使用它作为参数创建一个新的spriteSheet
。
创建一个新的位图序列变量名为critter1
,并应用图像精灵,键入:critter1gotoAndStop(0)
;。使用stage.addchild(critter1)
;将critter1
添加到stage
中。
通过键入克隆第一个critter1
变量,并将其值传递给一个新的 critter 变量:var critter2 = critter1.clone()
;。使用critter2.x += 120
;定义新变量的x
值。通过键入critter2.gotoAndStop(5)
;为critter
分配其自己的图像。添加新的spriteSheet
,创建critter 1
和克隆critter 2
的代码块应如下所示:
spriteSheet = new SpriteSheet(critterSheet, 80, 80, frameData);
critter1.gotoAndStop(0);
stage.addChild(critter1);
var critter2 = critter1.clone();
critter2.x += 120;critter2.gotoAndStop(5);
键入:var critter3 = critter2.clone(); critter3.spriteSheet = spriteSheet
;。就像我们之前创建的其他 critter 变量一样,通过将10
添加到其当前值来重新定义critter3
的x
值:critter3.x += 10
;。以下代码块显示了我们所做的事情:
var critter3 = critter2.clone();
critter3.spriteSheet = spriteSheet;
critter3.x += 10;
通过名称引用moles.png
中的图像frames
,键入critter3.gotoAndStop("upmole")
;。通过克隆一个新变量并引用一个新帧,将当前的upmole
帧图像替换为不同的帧:var critter4 = critter3.clone(); critter4.gotoAndStop("downmole")
;。通过键入将该帧向右移动10
像素:critter4.x += 10
;。
再次交换帧并将我们的新帧向右移动10
像素:var critter5 = critter4.clone(); critter5.gotoAndStop("shymole"); critter5.x += 10
;。让我们看一下到目前为止我们应该有的代码块:
critter3.gotoAndStop("upmole");
var critter4 = critter3.clone();
critter4.gotoAndStop("downmole");
critter4.x += 10;
var critter5 = critter4.clone();
critter5.gotoAndStop("shymole");
critter5.x += 10;
通过键入循环遍历我们的moles.png
文件中的帧:
var critter6 = critter1.clone(); critter6.x = critter5.x + 100; critter6.gotoAndPlay(3);stage.addChild(critter6);.
向舞台添加第二个动画序列,当新的 critter 精灵添加到舞台时,通过引用不同的起始帧来改变动画的时间:var critter7 = critter1.clone(); critter7.x = critter6.x + 100; critter7.gotoAndPlay(1); stage.addChild(critter7)
;。
我们的两个动画序列现在应包含以下代码:
var critter6 = critter1.clone();
critter6.x = critter5.x + 100;
critter6.gotoAndPlay(3);
stage.addChild(critter6);
var critter7 = critter1.clone();
critter7.x = critter6.x + 100;
critter7.gotoAndPlay(1);
stage.addChild(critter7);
Tick.setInterval(200)
;和Tick.addListener(stage)
;是我们将添加到脚本的最后两个语句。关闭handleImageLoad()
函数的大括号(}),然后键入一个闭合的脚本标签。
键入</head>
,然后<body onload="init()">
。创建一个名为"description"
的 div 来容纳内容。最后一个 div 是canvasHolder
,包含 canvas 元素。将宽度设置为600
,高度设置为280
,背景颜色设置为浅灰色(#ccc)
。添加指向图像文件moles.png
的链接,以便用户可以查看moles.png
中引用的图像精灵。
保存文件,并在浏览器窗口中打开。您应该在屏幕左侧看到一个静止的画面(闭着眼睛的鼹鼠头像),以及屏幕右侧循环播放的两个动画序列。以下截图显示了这两个序列如何加载相同的帧,但时间不同。
工作原理...
创建 HTML 页面和引用 canvas 的第一步与上一个步骤相同。
创建spriteSheet
后,我们创建了一个新变量来保存我们的精灵帧,名为critter1
,并通过输入以下内容定义了帧位置的x
和y
坐标:var critter1 = new BitmapSequence(spriteSheet); critter1.y = 100;critter1.x = 90
。
我们创建了数组var frameData
来声明八个键值对。然后,我们能够创建一个新的spriteSheet
,它接受了spriteSheet
名称、每个帧的默认高度和宽度的参数,并使用frameData
一次性将所有帧从moles.png
加载到spriteSheet
中。
接下来,我们尝试使用frameData
通过数字值和名称键引用帧,创建一系列位图序列,然后用它们的克隆替换它们。
我们对序列进行了动画处理,并将它们放置在舞台上。它们都遵循相同的格式,但通过改变gotoAndPlay
操作中的数字参数,它们在不同的帧上开始它们的动画序列。
最后,我们添加了Tick.setInterval(200)
;,它在 Ticks 之间应用了 200 毫秒的时间间隔。Tick 接口充当全局定时设备,使我们能够返回每秒的帧速率(FPS)(如果需要的话)。我们向舞台添加了一个监听器Tick.addListener(stage)
;,它像其他类型的监听器一样监听 Ticks。这可以用来在指定的时间重新绘制舞台,或执行其他与时间相关的操作。我们使用onload
属性在body
标签中调用init()
函数。这会导致在页面加载时调用init()
函数。
还有更多...
Easel.js
和其他类似的库使得控制 HTML5 元素变得更加容易。但是要小心使用它们,因为有些可能不够稳定,无法在生产环境中使用。
海盗喜欢雏菊,你也应该喜欢
Easel.js
的创建者被微软要求创建一个名为"Pirates love daisies"的概念性网络游戏(www.pirateslovedaisies.com
),完全使用 HTML5 和 JavaScript,并且大量依赖Easel.js
库来操作canvas
元素。您可以在任何网络浏览器中玩这个游戏,或许具有讽刺意味的是,它还为使用 Internet Explorer 9 浏览器的访问者提供了特殊功能。
老派计算机动画技术的回归
当我第一次在计算机上玩游戏时,游戏屏幕上有 256 种颜色和 8 位动画是一件大事。计算机动画师使用了许多技巧来复制水流动等效果。重温那些日子(或者第一次通过来自 effect games 的演示发现它们:www.effectgames.com/demos/canvascycle/
)。
另请参阅
本书中有一个完整的章节充满了 canvas 的示例。如果你跳过了它们,现在去看看吧。
使用 canvas 标签和 JavaScript 进行随机动画和音频
在这个示例中,我们将使用 canvas 标签来绘制和动画一系列形状。我们还将使用音频标签循环播放音频文件,同时显示动画。我们正在改编 Michael Nutt 创建的原始动画。我们将创建一个更慢、更轻松的动画,看起来像是摇曳的草。
准备工作
您将需要一个最近更新的浏览器,如 Firefox 3.6 或 Google Chrome,以及多种格式的音频文件。在 Opera 浏览器 9 和 10 中显示的大小不同(较小)。音频也不会在这些版本的 Opera 中播放。
如何做...
首先,打开一个新的 HTML5 页面,并将其命名为random-animation-with-audio.html
。输入 HTML5 页面的开头,包括页面标题:
<!DOCTYPE html> <html lang="en"> <head><meta charset="utf-8" /> <title>Canvas Reggae</title>.
然后,添加链接到将在页面加载时导入的 JavaScript 和 CSS 文件:<script type="text/javascript" src="img/animatedlines.js"></script><link rel="stylesheet" href="css/stylesheet.css" type="text/css" media="screen" charset="utf-8" />
,并使用</head>
关闭 head 标签。
输入<body onLoad="init();">
以在页面加载时激活init()
函数。
接下来,创建页面的标题<header><h1>CANVAS Reggae</h1></header>
,然后通过输入<canvas id="tutorial" width="480" height="360"></canvas>
添加 canvas 元素。
创建一个新的 div,其中id
为 credits,用于保存指向 Michael 网站的链接:<div id="credits">Based on Canvas Party by <a href="http://nuttnet.net/">Michael Nutt</a>
。然后向 div 添加一个链接,以获取音频元素,并在单击链接时应用pause()
函数来暂停音乐:<a href="#" onClick="document.getElementsByTagName('audio')[0].pause();">[OFF]</a></div>
。
现在,输入音频标签,并将 autoplay 设置为 true,loop 设置为 loop:<audio autoplay="true" loop="loop">
创建两个 source 标签来包含音频格式:<source type="audio/ogg" src="img/randomreggae.ogg" /><source type="audio/mpeg" src="img/randomreggae.mp3" />
。
在关闭音频标签之前,我们将添加一段文本,如果不支持音频标签,将显示:您的浏览器不识别 HTML5 音频标签
。
关闭音频、body 和 html 标签,并保存页面。
在创建脚本之前,打开stylesheet.css
页面,并输入以下内容:
body { margin: 0; background-color: #000; color: #FFF; font-family: Helvetica, sans-serif; }
a { color: #FFF; }
h1 { position: absolute; top: 0; margin: auto; z-index: 50; padding: 10px; background-color: #000; color: #FFF; }
div#credits { position: absolute; bottom: 0; right: 0; padding: 10px; }
audio { position: absolute; visibility: hidden; }
现在 HTML 和 CSS 页面都已构建,我们将着手处理动画脚本。创建一个新的 JavaScript 文件,并将其命名为animatedLines.js
。我们将把它放在一个名为js
的新子文件夹中。
首先,我们将声明 flatten 变量并创建一个新的数组函数:var flatten = function(array) { var r = [];
。接下来,在函数内部,我们将创建一个for
语句来声明一个以一个对象开始的数组(var i = 0
),然后在数组长度大于i
时增加数组的大小。通过使用push
函数,我们将输入新值到数组中:r.push.apply(r, array[i]);}
,最后通过返回数组来结束函数:return r; }
。
到目前为止,我们的脚本应该看起来像以下代码块:
var flatten = function(array) { var r = [];
for(var i = 0; i < array.length; i++) {
r.push.apply(r, array[i]); }
return r; }
接下来,我们将创建一个名为 shuffle 的函数,该函数接受一个数组作为参数。输入function shuffle(array) { var tmp, current, top = array.length;
。在函数内部,我们有一个 if/while 循环来遍历数组中的值。通过输入以下代码将其添加到脚本中:var tmp, current, top = array.length; if(top) while(--top) { current = Math.floor(Math.random() * (top + 1)); tmp = array[current]; array[current] = array[top]; array[top] = tmp; }
。在函数末尾返回array
值。我们的随机打乱数组值的函数现在应该看起来像以下代码块:
function shuffle(array) {
var tmp, current, top = array.length;
if(top) while(--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp; }
return array; }
现在,我们准备创建一个全局的canvas
变量和一个context
变量,输入:var canvas;
和var ctx;
。
创建了这些变量后,我们可以将init()
函数添加到脚本中,所有操作都从这里开始。输入function init() {
然后输入语句将我们的 canvas 变量与 canvas 元素关联起来:canvas = document.getElementById('tutorial');
。
现在,我们将创建一个if
语句来设置我们的 canvas 变量的宽度和高度属性:if (canvas.getContext) {canvas.width = window.innerWidth; canvas.height = window.innerHeight - 100; ctx = canvas.getContext('2d'); ctx.lineJoin = "round"; setInterval("draw()", 300); }。这
完成了init()
函数。
接下来,我们为浏览器窗口添加一个监听器,以便在调整大小时检测:window.addEventListener('resize', function() {canvas.width = window.innerWidth;canvas.height = window.innerHeight - 100; });}
。
我们脚本的最新添加现在应该看起来像:
function init() {
canvas = document.getElementById('tutorial');
if (canvas.getContext) {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight - 100;
ctx = canvas.getContext('2d');
ctx.lineJoin = "round";
setInterval("draw()", 300); }
window.addEventListener('resize', function() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight - 100; }); }
我们终于准备好创建一个函数来在画布上绘制形状。这个函数将包含大部分驱动形状动画的脚本。键入function draw(){ctx.globalCompositeOperation = "darker"; ctx.fillStyle = '#000'; ctx.fillRect(0, 0, canvas.width, canvas.height);ctx.globalCompositeOperation = "lighter";to
设置画布背景的外观。
现在,我们将输入用于动画的颜色。我们将创建一个包含rgba
值的数组数组。键入:var colors = ["rgba(134, 154, 67, 0.8)", "rgba(196, 187, 72, 0.8)", "rgba(247, 210, 82, 1)", "rgba(225, 124, 20, 0.8)"];。我们
已经定义了颜色,现在我们将使用一个包含宽度和高度值的数组来设置形状的宽度和高度:var data = [ [ [5, 20], [15, 2] ], [ [50, 12], [10, 14], [3, 21] ], [ [60, 8]], [ [30, 24], [15, 4], [10, 17] ], [ [5, 10] ], [ [60, 5], [10, 6], [3, 26] ], [ [20, 18] ], [ [90, 11], [40, 13], [15, 10] ], [ [70, 19] ], ]
。
现在我们可以通过使用data = shuffle(data)
来改变它们的宽度和高度来使形状动起来。
为了使形状上下以及左右移动,我们需要"压扁"或压缩它们的高度。创建一个新变量来包含var flatData = flatten(data)
;
现在我们将扭曲线条,使它们看起来像是在不同方向上拉动,并使用bezierCurve
。这是一个大的函数块,包含在我们之前创建的draw()
函数中,所以输入link()
函数如下所示:
link(topPos, bottomPos, width) {
var padding = 100;
ctx.lineWidth = width;
ctx.beginPath();
var height = parseInt(canvas.height - padding);
var pull = 100;
var topLeft = topPos + (width / 2) + padding;
var bottomLeft = bottomPos + (width / 2) + padding;
ctx.moveTo(topLeft, padding);
ctx.bezierCurveTo(topLeft, pull, bottomLeft, height - pull, bottomLeft, height);
ctx.stroke(); }
现在,当我们仍然在draw()
函数中时,让我们添加一个新变量来表示形状的起点,然后添加一个for
循环来创建一个可以容纳数据值集合数组的新变量。以下是变量和循环代码:Var topStartingPoint = 0; for(var i in data) { var group = data[i]; var color = colors[ i % colors.length ];ctx.strokeStyle = color
。
通过创建一个嵌套的for
循环,将一组数据值传递给一个名为line
的新变量,进一步进行。for(var j in group) { var line = group[j]
;然后我们可以在创建一个初始值为零的bottomStartingPoint
变量后进行操作:var bottomStartingPoint = 0
。
第三个嵌套的for
循环将允许我们进一步控制形状的定位和移动:for(var k in flatData) { if(flatData[k][1] < line[1]) { bottomStartingPoint += flatData[k][0] + 11;} }
。
最后,我们使用 link 来设置线条的顶部和底部起点,link(topStartingPoint, bottomStartingPoint, line[0])
;然后将topStartingPoint
赋值为其当前值加上线条数组。最后一条语句将topStartingPoint
的值设置为其当前值加上五:topStartingPoint += line[0]; } topStartingPoint += 5; }}
。保存脚本文件。
在浏览器中打开文件random-animation-with-audio.html
,您应该看到线条来回摆动,类似于以下截图所示:
它是如何工作的...
首先,我们创建了一个 HTML5 页面,其中包含对在页面加载时导入的 JavaScript 和 CSS 文件的链接:<script type="text/javascript" src="img/animatedlines.js"></script><link rel="stylesheet" href="css/stylesheet.css" type="text/css" media="screen" charset="utf-8" />
。为了激活我们的动画序列,我们将init()
函数放在 HTML 页面的 body 标签中。当页面加载时,animatedLines.js
JavaScript 文件中的init()
函数将通过<body onLoad="init();">
进行初始化。
我们使用body
样式设置了全局默认的margin
为0
,页面的background-color
,字体color
和font-family
。我们为基本链接颜色设置了样式,然后为h1
标题标签设置了样式,使其以position: absolute; top: 0
的方式显示在top
位置,并通过将z-index
设置为50
始终显示在大多数其他内容块的上方。#credits
div 被定位在页面的右下角,音频标签使用visibility: hidden
进行隐藏。
我们创建了一个名为animatedLines.js
的新脚本,并首先定义了一系列变量和函数来控制形状的行为。
我们设置了一个名为flatten
的数组,它会向自身添加新值。接下来,我们需要一个函数来随机遍历数组值。我们使用Math.floor(Math.random()
语句来计算一个随机数,并将结果乘以变量top + 1
的当前值的总和。然后我们将一个整数值返回给变量current
。
我们通过使用document.getElementById
在页面加载时抓取canvas
元素的 ID 来定义了canvas
变量的尺寸值。我们使用 DOM 设置了canvas
变量的width
和height
属性:canvas.height = window.innerHeight - 100; ctx = canvas.getContext('2d')
;然后创建了一个语句来将lineJoin
应用到canvas
的2d
上下文中,并设置参数为round
。我们使用setInterval()
函数将画布上的线条绘制速度设置为300
毫秒。数字越大,动画看起来越慢。我们为浏览器窗口添加了一个监听器,以便检测调整大小时使用window.addEventListener
,其中包含了浏览器窗口和画布的尺寸参数。
然后使用draw()
函数将形状绘制到画布上。使用globalCompositeOperation = "darker"
来使线条在相互交叠时变暗。线条在画布舞台前部重叠时,使用globalCompositeOperation = "lighter"
来设置画布背景的外观。
用于装饰线条的颜色需要以rgba
格式。rgba
中的'a'指的是 alpha 值,控制每种颜色的可见性。每个rgba
值设置都包含在一个数组中,然后成为数组列表。我们需要相匹配的宽度和高度值集合用于线条。这些存储在数组var data
中。
接下来,我们将data
数组分配给从我们的shuffle()
函数返回的值,以便我们可以随机化屏幕上线条的外观。然后,我们将flatData
变量分配给从flatten()
函数返回的值。为每条线分配一个拉动值使我们能够将其移动一定数量的像素。我们将这个与bezierCurve
结合起来使线条弯曲。
还有更多...
结合音频标签、画布动画和 JavaScript 听起来是创建酷炫可视化效果的有趣方式。然而,这些效果在很大程度上依赖于浏览器的支持,因此目前许多网络浏览器用户无法正确查看它们。我的意思是,大多数标准浏览器在一两年内都无法播放它们。
使用尖端浏览器可视化您的音频
如果你已经下载了 beta 版的 Firefox 4,你就可以访问 Firefox 音频和视频 API。你将能够使用类似 Spectrum Visualizer 的工具查看和创建自己的音频可视化:
www.storiesinflight.com/jsfft/visualizer/index.html
在 HTML5 中推动音频的实现
Alexander Chen 一直在尝试通过移植基于 Flash 的应用程序来实验音频和画布。他在使用多个音频文件时遇到了一些问题,这些问题在他的博客上有详细介绍:
blog.chenalexander.com/2011/limitations-of-layering-html5-audio/
另请参阅
画布和
第八章:拥抱音频和视频
在本章中,我们将涵盖:
对 Flash 说不
理解“音频”和“视频”文件格式
为所有人显示“视频”
创建可访问的“音频”和“视频”
打造时髦的“音频”播放器
为移动设备嵌入“音频”和“视频”
介绍
“Flash 是在 PC 时代创建的-为 PC 和鼠标。Flash 对 Adobe 来说是一个成功的业务,我们可以理解他们为什么想将其推广到 PC 之外。但移动时代是关于低功耗设备、触摸界面和开放的网络标准,所有这些领域 Flash 都做得不够好。提供其内容给苹果移动设备的媒体机构的大量增加表明,Flash 不再是观看视频或消费任何类型网络内容的必要条件。”- 史蒂夫·乔布斯
与我们已经看过的许多其他新技术一样,在开源 HTML5 标准中,新的“音频”和“视频”元素比以往任何时候都更加成熟和可用。这是一件好事,因为用户对多媒体的期望比以往任何时候都要高。在过去,我们使用需要 10 分钟才能下载一张照片的 300 波特调制解调器。后来,我们使用 Napster 非法下载 MP3“音频”文件。现在,我们在移动设备上播放电视和色情内容。由于带宽管道变得越来越宽,我们对互动娱乐的需求几乎变得无法满足。现在是展示成果的时候了。
多年来,视频播放在网页上一直是 QuickTime、RealPlayer 和 Flash 之间的战斗。这些浏览器插件安装起来很容易,通常 能产生预期的结果。
随着时间的推移,QuickTime 和 RealPlayer 继续作为播放平台,但专有 Flash 工具的制造商也创建了一个强大的开发环境,使设计师和开发人员都认为它是一个可行的平台。
虽然 QuickTime 和 RealPlayer 仍然存在,但 Flash 赢得了这场战争。对于动画和卡通来说,Flash 是理想的工具。但它是否仍然是最好的“音频”和“视频”播放工具呢?史蒂夫·乔布斯肯定不这么认为。
2010 年,苹果电脑的负责人乔布斯划定了界限,并表示 Flash 永远不会出现在他最畅销的 iPhone 和 iPad 上。相反,他坚定地支持开放的 HTML5 标准,并引发了一场在线圣战。
不久之后,“Flash 的死亡”宣言成为媒体头条和博客圈的热门话题。有些人写得如此恶毒,好像一道堤坝决堤,所有积累的污秽和淤泥都被允许淹没我们的多媒体对话。
很快,即使非网页设计师和开发人员也开始注意到,比如 C.C. Chapman,著名书籍《内容规则 》的作者,表达了他对《今日秀》无法在 iPad 上观看的不满:
这个问题迅速渗透到我们的在线娱乐讨论中。你不再需要成为网页设计师或开发人员才知道这里存在真正的问题。
C.C.说得简单明了,但作者知道他在谈论史蒂夫制造的 Flash/HTML5“视频”战争时,他已经说错了话。有时他争论得太过激和傲慢,但事实是,像网页设计师杰西卡·邦恩这样头脑清晰的人在提醒我们,Flash 和 HTML5“视频”可以和平共存。
自从史蒂夫做出上述宣言以来不到一年的时间,像 ABC、CBS、CNN、ESPN、Facebook、Fox News、MSNBC、National Geographic、Netflix、《纽约时报》、NPR、People、《体育画报》、《时代》、Vimeo、《华尔街日报》、YouTube 等网站都采用了新的 HTML5“音频”和“视频”元素。截至目前,超过 60%的网络“视频”现在都已经准备好使用 HTML5。可以说,新的 HTML5“音频”和“视频”功能是一些最令人兴奋和期待的新发展!
支持新的 HTML5“音频”和“视频”元素的浏览器包括:
在这一章中,我们将看一些现实生活中的例子,比如对 Flash 说不,理解新的video
和audio
文件格式,为所有人显示video
,创建可访问的audio
和video
,打造时尚的audio
播放器,以及为移动设备嵌入audio
和video
。
现在,让我们开始吧!
对 Flash 说不
作者的妈妈过去常说,万事都有其时机和地点,我们相信 Flash 也有其时机和地点。只是现在,随着技术的成熟,作者认为 Flash 的时间和地点越来越少。
在那些糟糕的旧日子里,如果我们想在网页中使用 YouTube 视频,比如“Neutraface”,这是排版界对 Lady Gaga 的“Pokerface”的回应,我们就不得不使用一些丑陋的代码,比如这样:
<object width="640" height="390">
<param name="movie" value="http://www.youtube.com/v/xHCu28bfxSI?fs=1&hl=en_US"> </param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always"></param>
<embed src="img/xHCu28bfxSI?fs=1&hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="390"></embed>
</object>
那段代码又长又丑陋,而且复杂,无法通过验证测试。它还依赖于第三方插件。呃。
多年来,我们忍受了那些垃圾,但不再。现在我们可以重建它——我们有技术了。
如何做...
现在,我们可以使用更加优雅的东西,而不是臃肿的object
代码:
<video src="img/videosource.ogv"></video>
这就是所需的全部。它简短、漂亮,而且验证通过。最重要的是,它不需要插件。再告诉我,为什么我们认为 Flash 是个好主意。
为了增加一些样式和功能,让我们再加入一点代码。
<video src="img/videosource.ogv" controls height="390" width="640"></video>
它是如何工作的...
那段代码应该很简单。你可能已经猜到,src
指的是源video
文件,controls
表示video
应该使用标准的播放和音量控件,height
和width
是不言自明的。
现代浏览器现在有了自己的原生 HTML5audio
和video
播放控件。让我们来看看每一个,从苹果 Safari 开始:
这是谷歌 Chrome 显示播放控件的方式:
微软 Internet Explorer 9 以不同的方式显示它:
然后,Mozilla Firefox 以不同的方式做到了:
不足为奇的是,Opera 以另一种方式显示播放控件:
所有这些看起来都不一样。如果每一个不同的外观都满足你的需求,太好了!如果不是,那肯定需要更多的工作来让它们行为和外观相似。
还有更多...
还有一些可选的属性我们可以包括。它们是:
autobuffer
- 这个布尔属性告诉浏览器在用户点击播放按钮之前就开始下载歌曲或电影。
autoplay
- 你可能已经猜到,这告诉浏览器自动播放 HTML5audio
或video
。
loop
- 也是一个布尔属性,它会一遍又一遍地播放 HTML5audio
或video
文件。
preload - preload 属性在播放之前开始加载文件。
poster
- poster
属性是在新的 HTML5video
加载时显示的静态占位图像。显然,这个属性不适用于 HTML5audio
文件。
无论你包括了这些可选属性中的哪些,你最终都会得到一种更漂亮、更语义化、更可访问的显示audio
和video
的方法,比起依赖 Flash 为你提供它们。
一些好消息
与canvas
章节不同,关于新的 HTML5audio
和video
元素的好消息是它们是可访问的。新的 HTML5audio
和video
元素具有键盘可访问性。由于浏览器现在原生地处理新的 HTML5audio
和video
元素,它可以像按钮一样支持你的键盘。这一点单独就足以推动这项新技术的接受。
带样式的视频
新的 HTML5 audio
和video
元素可以使用 CSS 进行视觉样式设置。我们可以使用 CSS 不仅控制播放器的大小,还可以添加:hover
和:transform
效果。此外,我们可以使用 JavaScript 来控制新的 HTML5 audio
和video
的行为。很酷!
保护你的资产
Flash 确实提供优势的一个领域是保护你的音频
和视频
内容。请记住,新的 HTML5 audio
和video
元素天生是开源的,没有数字版权管理。如果保护你的音频
或视频
文件不被下载对你来说很重要,那么新的 HTML5 audio
和video
元素不适合你 - Flash 可能仍然适合。这并不是说 Flash 能够终极保护不被盗用 - 只是说,Flash 默认隐藏了媒体轨道的能力,而新的 HTML5 <audio>
和<video>
元素则默认将这些文件完全暴露给任何人。然而,Flash Media Server 可以完全保护你的资产。
仍然不确定是选择 HTML5 音频和视频还是 Flash?试试这个方便的提示列表。
HTML5 的好处包括:
可访问性: 如果可访问性对你很重要(应该是的),那么新的 HTML5 audio
和video
元素是你最好的选择。
iOS: 如果你希望你的音频
和视频
能在 iPhone 或 iPad 上显示,HTML5 是你唯一的选择。
移动设备: 除了苹果的移动设备外,其他移动设备对新的 HTML5 audio
和video
元素有很好的支持。
视频/音频
流媒体: 如果你正在流媒体的内容不是专有的,也不需要版权管理,HTML5 是你的完美选择。
Flash 的好处包括:
可访问性: 如果你不在乎盲人或聋人,也不支持他们。谁在乎你是否被起诉呢?
动画: 毫无疑问,使用 Flash 的最好理由是如果你的网站有复杂的动画。像jibjab.com
这样的网站如果没有 Flash 就无法存在。
仅桌面开发: 如果你不需要支持移动用户。那只是一个时尚。
视频/音频
流媒体: 如果你不喜欢分享并且必须锁定你的音频
或视频
,使其不容易被人下载,那就坚持使用 Flash。
网络摄像头: 如果你使用网络摄像头(除了chatroulette.com
之外,还有谁在用?),那么 Flash 就是最好的选择。
这真的是使用 Flash 的最具说服力的理由吗?
另请参阅
想要能够在所有主要浏览器中播放新的 HTML5 audio
和video
元素,甚至包括远至 Internet Explorer 6?谁不想呢?如果是这样,那就去看看免费的开源 Projekktor 项目,网址是projekktor.com
。Projekktor 是 Sascha Kluger 的创意,它使用 JavaScript 来确保各种支持的浏览器都能正确解释和显示特定的 HTML5 video
文件格式。
了解音频和视频文件格式
有很多不同的音频
和视频
文件格式。这些文件不仅可能包括视频
,还可能包括音频
和元数据 - 都在一个文件中。这些文件类型包括:
.avi
- 一个来自过去的冲击,音频视频交错文件格式是由微软发明的。不支持今天大多数现代的音频
和视频
编解码器。
.flv
- Flash 视频
。这曾经是 Flash 完全支持的唯一视频
文件格式。现在它还包括对.mp4
的支持。
.mp4
或.mpv
- MPEG4 基于苹果的 QuickTime 播放器,并需要该软件进行播放。
它是如何工作的...
前面提到的每种视频
文件格式都需要浏览器插件或某种独立软件进行播放。接下来,我们将看看不需要插件或特殊软件以及支持它们的浏览器的新开源音频
和视频
文件格式。
H.264 已经成为最常用的高清视频格式之一。它被用于蓝光光盘以及许多互联网视频流网站,包括 Flash、iTunes 音乐商店、Silverlight、Vimeo、YouTube、有线电视广播和实时视频会议。此外,H.264 有专利,因此从定义上来说,它不是开源的。支持 H.264 视频文件格式的浏览器包括:
提示
谷歌现在部分地拒绝了 H.264 格式,更倾向于支持新的 WebM 视频文件格式。
Ogg 可能听起来有点滑稽,但它的潜力是非常严肃的,我向你保证。Ogg 实际上是两种东西:Ogg Theora 是一种视频文件格式;Ogg Vorbis 是一种音频文件格式。Theora 实际上更多地是一种视频文件压缩格式,而不是播放文件格式,尽管它也可以用于播放。它没有专利,因此被视为开源。我们将在下一节讨论 Ogg Vorbis。
提示
有趣的事实:根据维基百科,“Theora 是以 Max Headroom 电视节目中 Edison Carter 的控制器 Theora Jones 的名字命名的。”
支持 Ogg 视频文件格式的浏览器包括:
WebM 是在线视频文件格式竞赛中最新的参与者。这种开源音频/视频文件格式的开发由谷歌赞助。WebM 文件包含 Ogg Vorbis 音频流和 VP8 视频流。它得到了许多媒体播放器的支持,包括 Miro、Moovidia、VLC、Winamp 等,YouTube 也有初步支持。Flash 的制造商表示未来将支持 WebM,Internet Explorer 9 也将支持。目前支持 WebM 的浏览器包括:
还有更多...
到目前为止,这似乎是一长串音频和视频文件格式,最多只有零星的浏览器支持。如果你开始有这种感觉,那么你是对的。
事实上,没有一个音频或视频文件格式能够成为统治它们所有的真正格式。相反,我们开发人员通常必须以多种格式提供新的音频和视频文件,让浏览器决定它最舒适和能够播放的格式。目前这有点麻烦,但希望未来我们能够选择更少的格式,获得更一致的结果。
音频文件格式
还有一些音频文件格式。让我们来看看这些。
AAC - 高级音频编码文件更为人所知的是 AAC。这种音频文件格式被设计成在相同比特率下比 MP3 更好听。苹果使用这种音频文件格式来制作 iTunes 音乐商店的音频文件。由于 AAC 音频文件格式支持 DRM,苹果提供受保护和非受保护格式的文件。AAC 有专利,因此从定义上来说,我们也不能完全称其为开源音频文件格式。所有苹果硬件产品,包括他们的 iPhone 和 iPad 移动设备以及 Flash,都支持 AAC 音频文件格式。支持 AAC 的浏览器包括:
MP3 - MPEG-1 音频层 3 文件更为人所知的是 MP3。除非你一直躲在石头下,你知道 MP3 是当今最普遍使用的音频文件格式。这些文件可以播放两个声道的声音,并且可以使用多种比特率进行编码,最高可达 320。一般来说,比特率越高,音频文件的音质就越好。这也意味着文件大小更大,因此下载速度更慢。MP3 有专利,因此从定义上来说,我们也不能完全称其为开源音频文件格式。支持 MP3 的浏览器包括:
Ogg - 我们之前讨论过 Ogg Theora 视频文件格式。现在,让我们来看看 Ogg Vorbis 音频格式。正如之前提到的,Ogg 文件没有专利,因此被视为开源。
提示
另一个有趣的事实是:根据维基百科,“Vorbis 是以《小神》中的 Exquisitor Vorbis 角色命名的。”
文件格式不可知。
我们花了很多时间来检查这些不同的视频和音频文件格式。每种格式都有其优点和缺点,并且受到各种浏览器的支持(或不支持)。有些比其他的效果更好,有些听起来和看起来比其他的更好。但好消息是:新的 HTML5 <video>
和<audio>
元素本身是文件格式不可知的!这些新元素不在乎您引用的视频或音频文件的类型。相反,它们提供您指定的内容,并让每个浏览器做它最舒服的事情。
有一天我们能停止这种疯狂吗?
最重要的是,直到一个新的 HTML5 音频和一个新的 HTML5 视频文件格式成为所有浏览器和设备的明确选择,音频和视频文件将不得不被编码多次进行播放。不要指望这种情况很快会改变。
为所有人显示视频
根据作者 Mark Pilgrim 的说法,您的 HTML5 网络视频工作流程将如下所示:
制作一个使用 WebM(VP8 和 Vorbis)的版本。
制作另一个版本,该版本在 MP4 容器中使用 H.264 基线视频和 AAC“低复杂度”音频。
制作另一个版本,该版本在 Ogg 容器中使用 Theora 视频和 Vorbis 音频。
从单个<video>
元素链接到所有三个视频文件,并回退到基于 Flash 的视频播放器。
Kroc Camen 在创建“面向所有人的视频”时确实做到了这一点,这是一段 HTML 代码,如果用户的浏览器可以处理它,就会显示新的 HTML5 视频元素,如果不能,就会显示 Flash 电影 —— 而无需 JavaScript。让我们看看 Kroc 是如何做到的:camendesign.com/code/video_for_everybody
。
如何做...
<video controls height="360" width="640">
<source src="img/__VIDEO__.MP4" type="video/mp4" />
<source src="img/__VIDEO__.OGV" type="video/ogg" />
<object width="640" height="360" type="application/ x-shockwave-flash" data="__FLASH__.SWF">
<param name="movie" value="__FLASH__.SWF" />
<param name="flashvars" value="controlbar=over& image=__POSTER__.JPG&file=__VIDEO__.MP4" />
<img src="img/__VIDEO__.JPG" width="640" height="360" alt="__TITLE__" title="No video playback capabilities, please download the video below" />
</object>
</video>
<p><strong>Download Video:</strong>
Closed Format: <a href="__VIDEO__.MP4">"MP4"</a>
Open Format: <a href="__VIDEO__.OGV">"Ogg"</a>
</p>
仔细观察,很容易看出 Kroc 做了什么。首先,他调用了浏览器本地播放控件,以及新的 HTML5 视频元素的相关高度和宽度。
<video controls height="360" width="640">
接下来,Kroc 依次调用每个新的 HTML5 视频源,从 MP4 文件开始。桌面浏览器不太在乎 HTML5 视频文件的顺序,但 iPad 对于想要首先指定 MP4 文件很挑剔,所以好吧。又是你赢了,史蒂夫·乔布斯。
<source src="img/__VIDEO__.MP4" type="video/mp4" />
<source src="img/__VIDEO__.OGV" type="video/ogg" />
然后,Kroc 通过调用相同文件的 Flash 视频版本来保险,以应对无法处理新的 HTML5 视频元素的软弱浏览器。
<object width="640" height="360" type="application/x-shockwave-flash" data="__FLASH__.SWF">
<param name="movie" value="__FLASH__.SWF" />
<param name="flashvars" value="controlbar=over& image=__POSTER__.JPG&file=__VIDEO__.MP4" />
<img src="img/__VIDEO__.JPG" width="640" height="360" alt="__TITLE__" title="No video playback capabilities, please download the video below" />
</object>
最后,Kroc 通过提示用户选择性地下载新的 HTML5 视频文件本身,以封闭(MP4)和开放(Ogg)格式进行了精心的处理。分享就是关怀。
<p><strong>Download Video:</strong>
Closed Format: <a href="__VIDEO__.MP4">"MP4"</a>
Open Format: <a href="__VIDEO__.OGV">"Ogg"</a>
</p>
提示
当然,您可以用自己文件的路径替换“VIDEO .MP4”之类的东西。
这种方法非常成功,因为无论您使用什么网络浏览器,您都可以看到某些东西 —— 而无需使用 JavaScript 或下载 Flash。
它是如何工作的...
这个概念实际上非常简单:如果您的浏览器能够播放新的 HTML5 视频元素文件,那么您将看到它。如果它不能做到,代码堆栈中还包括了一个 Flash 电影,所以您应该会看到它。如果由于某种原因,您的浏览器无法原生支持新的 HTML5 视频元素,Flash 播放器崩溃或不可用,您将看到一个静态图像。每个人都有保障。
使用此方法将显示新的 HTML5 视频元素的浏览器包括:
使用此方法将显示 Flash 视频的浏览器包括:
还有更多...
所有其他 Flash 视频嵌入方法都会提示用户下载 Flash(如果尚未安装)。《面向所有人的视频》独特之处在于它不会这样做。作者 Kroc Camen 是有意为之,他说:
“用户已经有足够的安全问题了,而不需要随机的网站提示他们安装东西-对于那些不想要或无法使用 Flash 的人来说,这更加恼人。”
浪费 mime 是一件可怕的事情
Kroc 提醒我们确保我们的服务器使用正确的mime-types
并建议将这些行放在你的.htaccess
文件中:
AddType video/ogg .ogv
AddType video/mp4 .mp4
AddType video/webm .webm
外部“Video for Everybody”
现在 WordPress 有一个“Video for Everybody”插件,网址是wordpress.org/extend/plugins/external-video-for-everybody
。现在你也可以在你的博客上轻松使用 Kroc 的方法。
灵活地处理你的方法
稍后我们将看一种方法,它实现了与 Kroc 的方法几乎相同的功能,但这次是用 JavaScript。记住:做对你、你的项目和最重要的是你的客户最有意义的事情。
另见
Humanstxt.org 是一个让网站开发者更加知名的项目。该网站鼓励开发者包含一个小文本文件,其中包含每个贡献创建和构建网站的团队成员的信息。请访问:humanstxt.org
。
创建无障碍音频和视频
我们已经非常广泛地研究了如何向人们提供在线 HTML5 video
,而不管他们的浏览器是什么,但对于依赖辅助技术的人,我们并没有给予太多关注。现在结束了。
如何做到...
首先,我们将从 Kroc Camen 的“Video for Everybody”代码块开始,然后检查如何使其对辅助功能友好,最终看起来像这样:
<div id="videowrapper">
<video controls height="360" width="640">
<source src="img/__VIDEO__.MP4" type="video/mp4" />
<source src="img/__VIDEO__.OGV" type="video/ogg" />
<object width="640" height="360" type="application/ x-shockwave-flash" data="__FLASH__.SWF">
<param name="movie" value="__FLASH__.SWF" />
<param name="flashvars" value="controlbar=over& image=__POSTER__.JPG&file=__VIDEO__.MP4" />
<img src="img/__VIDEO__.JPG" width="640" height="360" alt="__TITLE__" title="No video playback capabilities, please download the video below" />
</object>
<track kind="captions" src="img/videocaptions.srt" srclang="en" />
<p>Final fallback content</p>
</video>
<div id="captions"></div>
<p><strong>Download Video:</strong>
Closed Format: <a href="__VIDEO__.MP4">"MP4"</a>
Open Format: <a href="__VIDEO__.OGV">"Ogg"</a>
</p>
</div>
它是如何工作的...
你会注意到的第一件事是,我们将新的 HTML5 video
元素包装在一个div
包装器中。虽然从语义上讲这并不是严格必要的,但它将为我们的 CSS 提供一个很好的“钩子”。
<div id="videowrapper">
下一部分的大部分内容应该是从前一部分中可以识别出来的。这里没有改变:
<video controls height="360" width="640">
<source src="img/__VIDEO__.MP4" type="video/mp4" />
<source src="img/__VIDEO__.OGV" type="video/ogg" />
<object width="640" height="360" type="application/ x-shockwave-flash" data="__FLASH__.SWF">
<param name="movie" value="__FLASH__.SWF" />
<param name="flashvars" value="controlbar=over&
image=__POSTER__.JPG&file=__VIDEO__.MP4" />
<img src="img/__VIDEO__.JPG" width="640" height="360" alt="__TITLE__" title="No video playback capabilities, please download the video below" />
</object>
到目前为止,我们仍然使用的是向能够处理它的浏览器提供新的 HTML5 video
元素的方法,并将 Flash 作为我们的第一个备用选项。但是如果 Flash 不是一个选择,接下来会发生什么就变得有趣起来:
<track kind="captions" src="img/videocaptions.srt" srclang="en" />
你可能会想,那是什么鬼。
“track
元素允许作者为媒体元素指定显式外部定时文本轨道。它本身不代表任何东西。”- W3C HTML5 规范
现在我们有机会使用 HTML5 规范的另一个新部分:新的<track>
元素。现在,我们可以引用kind="captions"
中指定的外部文件类型。你可以猜到,kind="captions"
是用于字幕文件,而kind="descriptions"
是用于audio
描述。当然,src
调用特定的文件,srclang
设置新的 HTML5 track
元素的源语言。在这种情况下,en
代表英语。不幸的是,目前没有浏览器支持新的track
元素。
最后,我们允许最后一点备用内容,以防用户无法使用新的 HTML5 video
元素或 Flash 时,我们会给他们一些纯文本内容。
<p>Final fallback content</p>
现在,即使用户看不到图像,他们至少会得到一些描述性内容。
接下来,我们将创建一个容器div
来容纳我们基于文本的字幕。因此,目前没有浏览器支持新的 HTML5 audio
或video
元素的闭合字幕,我们将留出空间来包含我们自己的字幕:
<div id="captions"></div>
最后,我们将包括 Kroc 的文本提示,以下载 HTML5 video
的封闭或开放文件格式:
<p><strong>Download Video:</strong>
Closed Format: <a href="__VIDEO__.MP4">"MP4"</a>
Open Format: <a href="__VIDEO__.OGV">"Ogg"</a>
</p>
还有更多...
除了新的 HTML5 audio
和video
元素的可选controls
属性之外,还有可选的loop
属性。你可能会猜到,这个例子将允许 HTML5 video
一直播放:
<video controls height="360" loop width="640">
始终考虑无障碍。
我们默认提供的最终描述性内容可能是为使用辅助技术的人提供可下载链接的替代位置。这将使能够看到或听到的人无法下载,因此你应该确定这种方法是否适合你。
浏览器支持
对新的 HTML5 audio
和video
元素具有最佳辅助功能支持的网络浏览器包括:
查看更多
你可以在html5accessibility.com
上跟踪 HTML5 的可访问性。该网站跟踪新的 HTML5 功能,如audio
和video
在哪些浏览器中可用。你可能会惊讶地发现,截至目前,Opera 是最不友好的可访问性的网络浏览器,甚至低于微软 Internet Explorer 9。惊喜吧。
另请参阅
Video.Js 是另一个免费的开源 HTML5 视频播放器。它很轻量,不使用任何图像,但通过 CSS 完全可定制。它看起来很棒,并支持苹果 Safari、Google Chrome、微软 Internet Explorer 9、Mozilla Firefox 和 Opera,同时还支持 IE 6-8 的回退。它甚至适用于 iPhone、iPad 和 Android 等移动设备。请访问videojs.com
查看。
打造流畅的音频播放器
Neutron Creations 的负责人和联合创始人兼前端开发人员本·博迪恩为 Tim Van Damme 的 The Box 播客创建了一个定制的 HTML5 audio
播放器,网址为thebox.maxvoltar.com
。本的创作快速、直观且流畅。让我们深入了解他是如何做到的。
本的自定义 HTML5 audio
播放器具有被采访者(在这种情况下是 Shaun Inman)的吸引人照片,一个播放/暂停按钮,指示播放进度的轨道,以及如果你愿意,将 HTML5 audio
播放器弹出到一个单独的窗口的能力。就是这样。没有更多的需要。作为一个额外的触摸,注意 HTML5 audio
播放器条的轻微透明度细节。平滑。
如何做到这一点...
起初,本的标记似乎看起来非常简单:
<p class="player">
<span id="playtoggle" />
<span id="gutter">
<span id="loading" />
<span id="handle" class="ui-slider-handle" />
</span>
<span id="timeleft" />
</p>
等一下,我听到你在想,“HTML5 audio
标签在哪里?!”别担心。本是个聪明人,对此有计划。但首先让我们看看他到目前为止做了什么。
<p class="player">
到目前为止,这很简单。本创建了一个包装元素(在这种情况下是<p>
)来放置他的播放器。他可以使用<div>
吗?也许。做对你和你的项目最有意义的事情。
<span id="playtoggle" />
然后,本使用这个自闭合的(注意末尾的斜杠)span
来进行播放/暂停切换按钮。
<span id="gutter">
<span id="loading" />
<span id="handle" class="ui-slider-handle" />
</span>
现在,事情变得有趣起来。本的“排水沟”span
包含了时间轴轨道,显示 HTML5 audio
文件的加载或缓冲进度的条形元素,以及指示播放头的圆形元素,如果你选择,可以来回“擦洗”。
<span id="timeleft" />
最后,本使用另一个自闭合的span
来显示剩余的时间,以分钟和秒为单位。
提示
<span>
元素可以胜任,但它并不是非常语义化,是吗?Patrick H. Lauke 迅速指出,使用可聚焦元素将大大提高这种方法对依赖辅助技术的人的可访问性。
它是如何工作的...
本使用 jQuery 来检测对 HTML5 audio
的支持。
if(!!document.createElement('audio').canPlayType) {
var player = '<p class="player"> ... </p>\
<audio>\
<source src="img/episode1.ogg" type="audio/ogg"></source>\
<source src="img/episode1.mp3"
type="audio/mpeg"></source>\
<source src="img/episode1.wav" type="audio/ x-wav"></source>\
</audio>';
$(player).insertAfter("#listen .photo");
}
在这段代码中,我们可以看到如果浏览器支持 HTML5 audio
,它将提供完整的 HTML5 <audio>
标签,包括对.ogg, .mp3
和.wav
的回退,这是我们尚未使用过的文件格式。由于新的 HTML5 <audio>
和<video>
元素是文件格式不可知的,.wav
文件也应该可以正常工作。
本已经创建了一个简单的 JavaScript 代码片段,允许浏览器做他们感觉最舒服的事情。如果这对你和你的项目有意义,考虑这种方法,但记住,你依赖 JavaScript 来完成大部分工作,而不是我们已经看过的其他方法,这些方法不依赖于它。
提示
请注意,如果您使用<div>
来包含 HTML5“视频”播放器,那么 JavaScript 也必须进行调整。简而言之,<p class="player">
...</p>
将被更改为<div class="player">
...</div>
。
还有更多...
到目前为止,我们已经为播放器设置了标记,并“嗅探”以查看任何特定浏览器想要的文件格式。现在,我们需要添加一些功能。
audio = $('.player audio').get(0);
loadingIndicator = $('.player #loading');
positionIndicator = $('.player #handle');
timeleft = $('.player #timeleft');
if ((audio.buffered != undefined) && (audio.buffered.length != 0)) {
$(audio).bind('progress', function() {
var loaded = parseInt(((audio.buffered.end(0) / audio.duration) * 100), 10);
loadingIndicator.css({width: loaded + '%'});
});
}
else {
loadingIndicator.remove();
}
然后添加一个函数来计算播放头的位置,以确定剩余时间,要小心包括前导零(如果需要的话)。
$(audio).bind('timeupdate', function() {
var rem = parseInt(audio.duration - audio.currentTime, 10),
pos = (audio.currentTime / audio.duration) * 100,
mins = Math.floor(rem/60,10),
secs = rem - mins*60;
timeleft.text('-' + mins + ':' + (secs > 9 ? secs : '0' + secs));
if (!manualSeek) { positionIndicator.css({left: pos + '%'}); }
if (!loaded) {
loaded = true;
$('.player #gutter').slider({
value: 0,
step: 0.01,
orientation: "horizontal",
range: "min",
max: audio.duration,
animate: true,
slide: function() {
manualSeek = true;
},
stop:function(e,ui) {
manualSeek = false;
audio.currentTime = ui.value;
}
});
}
});
唯一剩下的就是调用播放/暂停按钮功能。
$(audio).bind('play',function() {
$("#playtoggle").addClass('playing');
}).bind('pause ended', function() {
$("#playtoggle").removeClass('playing');
});
$("#playtoggle").click(function() {
if (audio.paused) { audio.play(); }
else { audio.pause(); }
});
风格和内容
在创建了简单的标记和详细的 JavaScript 来创建 Ben 定制的 HTML5“音频”播放器之后,唯一剩下的就是对其进行样式设置:
.player {
display: block;
height: 48px;
width: 400px;
position: absolute;
top: 349px;
left: -1px;
-webkit-box-shadow: 0 -1px 0 rgba(20, 30, 40, .75);
-moz-box-shadow: 0 -1px 0 rgba(20, 30, 40, .75);
-o-box-shadow: 0 -1px 0 rgba(20, 30, 40, .75);
box-shadow: 0 -1px 0 rgba(20, 30, 40, .75);
border-top: 1px solid #c2cbd4;
border-bottom: 1px solid #283541;
background: #939eaa;
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgba(174, 185, 196, .9)), to(rgba(110, 124, 140, .9)), color-stop(.5, rgba(152, 164, 176, .9)), color-stop(.501, rgba(132, 145, 159, .9)));
background: -moz-linear-gradient(top, rgba(174, 185, 196, .9), rgba(152, 164, 176, .9) 50%, rgba(132, 145, 159, .9) 50.1%, rgba(110, 124, 140, .9));
background: linear-gradient(top, rgba(174, 185, 196, .9), rgba(152, 164, 176, .9) 50%, rgba(132, 145, 159, .9) 50.1%, rgba(110, 124, 140, .9));
cursor: default;
}
#playtoggle {
position: absolute;
top: 9px;
left: 10px;
width: 30px;
height: 30px;
background: url(../img/player.png) no-repeat -30px 0;
cursor: pointer;
}
#playtoggle.playing {background-position: 0 0;}
#playtoggle:active {top: 10px;}
#timeleft {
line-height: 48px;
position: absolute;
top: 0;
right: 0;
width: 50px;
text-align: center;
font-size: 11px;
font-weight: bold;
color: #fff;
text-shadow: 0 1px 0 #546374;
}
#wrapper #timeleft {right: 40px;}
#gutter {
position: absolute;
top: 19px;
left: 50px;
right: 50px;
height: 6px;
padding: 2px;
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
background: #546374;
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#242f3b), to(#516070));
background: -moz-linear-gradient(top, #242f3b, #516070);
background: linear-gradient(top, #242f3b, #516070);
-webkit-box-shadow: 0 1px 4px rgba(20, 30, 40, .75) inset, 0 1px 0 rgba(176, 187, 198, .5);
-moz-box-shadow: 0 1px 4px rgba(20, 30, 40, .75) inset, 0 1px 0 rgba(176, 187, 198, .5);
-o-box-shadow: 0 1px 4px rgba(20, 30, 40, .75) inset, 0 1px 0 rgba(176, 187, 198, .5);
box-shadow: 0 1px 4px rgba(20, 30, 40, .75) inset, 0 1px 0 rgba(176, 187, 198, .5);
}
#wrapper #gutter {right: 90px;}
#loading {
background: #fff;
background: #939eaa;
background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#eaeef1), to(#c7cfd8));
background: -moz-linear-gradient(top, #eaeef1, #c7cfd8);
background: linear-gradient(top, #eaeef1, #c7cfd8);
-webkit-box-shadow: 0 1px 0 #fff inset, 0 1px 0 #141e28;
-moz-box-shadow: 0 1px 0 #fff inset, 0 1px 0 #141e28;
-o-box-shadow: 0 1px 0 #fff inset, 0 1px 0 #141e28;
box-shadow: 0 1px 0 #fff inset, 0 1px 0 #141e28;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
display: block;
float: left;
min-width: 6px;
height: 6px;
}
#handle {
position: absolute;
top: -5px;
left: 0;
width: 20px;
height: 20px;
margin-left: -10px;
background: url(../img/player.png) no-repeat -65px -5px;
cursor: pointer;
}
.player a.popup {
position: absolute;
top: 9px;
right: 8px;
width: 32px;
height: 30px;
overflow: hidden;
text-indent: -999px;
background: url(../img/player.png) no-repeat -90px 0;
}
.player a.popup:active {background-position: -90px 1px;}Content matters
当包装内容引人入胜时,花时间创造有趣的东西会更容易和更有回报。The Box 音频采访总是很有趣——只是可惜作者 Tim Van Damme 不经常发布它们。希望将来会有所改变。在thebox.maxvoltar.com
上查看。
注意细节
当页面上一次只有一个新的 HTML5“音频”或“视频”元素时,这种方法效果很好。如果您需要多个,您将不得不修改 JavaScript 以连接到标记中的多个“挂钩”。
另请参阅
SublimeVideo 采用了一种不同的方法来进行 HTML5 在线视频播放:在这种情况下,播放器不是由您创建或托管的,而是由云中播放器的制造商创建的。好处是您始终拥有可能的最新、最新鲜的播放器版本。这样,当新功能可用或错误被修复时,您无需做任何事情。您自动拥有最新的功能。在sublimevideo.net
上查看。
为移动设备嵌入音频和视频
到目前为止,我们只是触及了移动体验,但随着越来越智能的移动设备的开发增加,我们需要将注意力转向如何在这些设备上显示我们的新 HTML5“音频”和“视频”。以下是方法。
如何做...
现在我们知道如何为我们的目标受众选择 HTML5“音频”或“视频”文件格式,我们现在可以将注意力转向确保他们不仅可以在台式电脑和笔记本电脑上听到或观看,还可以在移动设备上听到或观看。
我们将首先在vimeo.com
上创建一个免费帐户。注册完成后,选择主菜单中的上传|视频功能。您将选择要上传的文件,添加可选的元数据,然后让 Vimeo 服务器设置您的文件。接下来真正的激动时刻开始了:嵌入“视频”。从 Vimeo 主菜单中选择工具 |嵌入此视频 。
它是如何工作的...
Vimeo 过去使用我们之前看过的老式 Flash 嵌入方法。现在它使用基于 iFrame 的方法,可以在 iPhone、iPad 和其他移动设备上播放 HTML5“视频”。以下是一个示例,基于作者上传的一个“视频”:
<iframe src="img/20958090" width="400" height="300" frameborder="0"></iframe><p><a href="http://vimeo.com/20958090">Untitled</a> from <a href="http://vimeo.com/user6281288">Dale Cruse</a> on <a href="http://vimeo.com">Vimeo</a>.</p>
还有更多...
一旦您将基于 iFrame 的代码片段复制并粘贴到网页上,并在 iPhone 或 iPad 上查看它,您应该会看到一个移动友好的 HTML5“视频”,您可以像这样使其全屏:
Vimeo 提供了更多
Vimeo 还允许您从电子邮件联系人列表中添加朋友,创建“视频”订阅,制作小部件等等。他们现在甚至提供视频学校,以帮助用户了解捕捉、编辑和分享视频的最有效方法。
循环回来。
YouTube,世界上最受欢迎的在线视频观看网站,现在也采用基于 iFrame 的嵌入视频的方法。我们可以采用本章开头使用的“Neutraface”视频,使用新的基于 iFrame 的嵌入方法,得到更语义化和友好的结果。它也通过了验证!
<iframe title="YouTube video player" width="1280" height="750" src="img/xHCu28bfxSI?rel=0&hd=1" frameborder="0" allowfullscreen></iframe>
看看这有多漂亮!
我们已经完全转变了我们的视频捕捉、编辑和播放能力,以在现代浏览器中运行,同时支持依赖辅助技术和移动设备的用户。这是一个不断发展的过程。
另请参阅
Adobe 是否在自掘坟墓?并非如此。2011 年初,Adobe 推出了一个免费的 Flash 转 HTML5 转换器,代号“Wallaby”。不幸的是,许多设计师和开发人员认为 Adobe 在声称 Wallaby 可以使用 Web 标准将 Flash 转换为 HTML5 时过于夸大其词。事实上,它只是将 Flash CS5 或更高版本中创建的最简单的动画转换为简单的标记和样式。它没有能力将 ActionScript 转换为 JavaScript,这种能力才真正使该工具有价值。请查看 John Nack 的博客上关于 Wallaby 发布的公告blogs.adobe.com/jnack/2011/03/wallaby-flash-to-html5-conversion-tool-now-available.html
。
第九章:数据存储
在本章中,我们将涵盖:
测试浏览器是否支持数据存储
使用浏览器开发者工具来监视 web 存储
设置和获取会话存储变量
设置和获取本地存储变量
将本地存储字符串转换为数字使用parseInt
创建一个 web SQL 数据库
使用 web SQL 数据库
创建一个缓存清单并离线使用站点
使用地理位置 API 和geo.js
显示当前位置
介绍
HTML5 引入了一种新的存储信息的方式,而不使用 cookies。这使得设计师和开发人员在处理和显示动态内容时具有更大的灵活性。我们将从测试浏览器是否支持三种主要的数据存储方法开始,最后创建一个使用本地存储来存储和访问视频的 HTML5 页面。虽然这些配方都是基于彼此构建的,但你不必按照它们呈现的顺序完成它们。本章的示例文件可在www.packtpub.com/support?nid=7940
下载。
测试浏览器是否支持数据存储
知道如何快速测试浏览器是否支持你想要使用的数据存储方法将使开发页面和应用程序变得更容易。在这个配方中,我们将创建一个脚本,查询浏览器的 DOM,以测试不同数据存储方法的支持。
准备工作
你需要访问一个现代浏览器,如 Firefox 3.6,或者流行浏览器的最新版本,如 Google Chrome,Opera,Safari 或 Internet Explorer。
如何做...
首先,我们将创建一个简单的 html 页面。打开一个 HTML 编辑程序或文本编辑器,并输入一个基本的 HTML5 页面的起始代码:
<!doctype html><html lang="en"><head><title>Client-side Storage Test for HTML5</title>
<meta charset="utf-8">
现在测试页面的外观需要进行样式设置。我们将在 HTML 页面的<head>
标签中使用<style>
标签,但你也可以将它们放在一个单独的 CSS 文件中。
<style>
#results { background-color: #ffcc99; border: 1px #ff6600 solid; color: #ff6600; padding: 5px 20px; margin-bottom: 10px; }
#results .value { font-weight: bold; }
#results h3 { color: #333333; }
</style>
输入一个闭合的head
标签,然后创建一个如下所示的body
标签。注意,一个很大的区别是我们在页面加载时调用了一个RunTest()
函数来激活。
</head><body onload="RunTest();">
创建一个带有类似下面所示的描述性文本的段落标签。关闭标签,并创建一个包含结果标题的<h3>
标题标签。
<p>Does your browser support all storage methods?</p>
<div id="results"><h3>Browser Data Storage Support Results</h3>
现在,输入每种存储方法,后面跟一个由类值样式化的 span 标签。输入存储方法的 ID 和文本“不支持”。关闭 span 标签,并添加一个换行标签,以便在浏览器窗口中将结果分开显示在单独的行上。结果的显示区域应该如下所示的代码块:
Session Storage: <span class="value" id="session">not supported</span><br/>
Local Storage: <span class="value" id="local">not supported</span> <br />
Database Storage: <span class="value" id="db">not supported</span> <br /></div>
我们几乎完成了创建我们的测试页面。创建一个段落来解释测试的目的。用一个<footer>
标签来包含我们接下来要添加的脚本块。描述性文本应该如下所示的代码:
<p>The test above shows whether the browser you are currently using supports a data storage method.</p> <footer>
现在,我们将添加script
标签,以便浏览器处理一个小的测试程序:
<script language="javascript">
function RunTest() {
for (var mydata in window)
{
接下来,我们将创建一个包含每种数据存储方法的代码块的 case 语句,我们将要测试:
switch (mydata) {
case "sessionStorage": document.getElementById("session").innerHTML = "supported";
break;
case "localStorage": document.getElementById("local").innerHTML = "supported";
break;
case "openDatabase": document.getElementById("db").innerHTML = "supported";
break;
} }} </script> </footer> </body> </html>
将文件保存为data-storage-support-test.html
,并在浏览器窗口中打开它。你应该看到类似以下截图的结果:
它是如何工作的...
我们创建的 HTML5 测试页面使用了一小段 JavaScript 代码来查询浏览器是否支持特定的存储方法。我们首先编写了一个标准的 HTML5 页面,包括适当的<html>
、<head>
和其他文档标签。如果需要复习它们,可以在本书的早期章节中找到。接下来,我们使用简化的<script>
标签设置了 JavaScript 代码片段的开头块。HTML5 JavaScript API 在本书的其他地方有更详细的介绍。我们创建了一个名为RunTest()
的函数来包含变量和代码。然后创建了两个变量。变量 supp 被赋予了一个空字符串的值。这将包含每种存储方法的最终支持结果。我们正在循环遍历 window 对象的属性。在每次迭代中,当前属性暂时存储在mydata
变量中。这使我们能够测试属性是否符合三种情况。
接下来,我们使用 switch 语句来测试mydata
变量与我们感兴趣的特定属性。因为我们一次只测试一个值,而且列表很短,这是测试每种存储方法支持的好方法。switch 语句的主体包含三种情况,每种情况都包含一个必须评估的表达式。如果支持存储方法,则每种情况的最终操作是,如果表达式评估为 true,则将文档主体中结果文本的值从“不支持”更改为“支持”。如果情况评估为 false,则页面结果部分显示的文本将保持不变。
创建代码后,我们使用 CSS 样式控制了结果的呈现。使用名为 results 的 div 标签创建了一个显示框的容器,并指定了背景颜色、字体颜色和字体粗细。这是 html 页面头部的最后一块代码。
然后创建了页面的主体部分。测试被设置为在浏览器中加载页面时激活,使用onload
命令。编写了结果框的开头文本和标题,并将每个结果的显示文本与唯一的 ID 绑定。然后输入了闭合标签以完成页面。保存页面后,在浏览器窗口中查看测试页面时,结果就会显示在屏幕上。截图中使用的浏览器是 Firefox 3.6.13。我们看到的结果反映了 Firefox 在 3.6 和 4.0.3 版本中提供的当前支持。这帮助我们确定,我们可以期望 Firefox 访问者在依赖本地存储和会话存储方法的网页上轻松查看和使用任何功能。他们将无法利用任何依赖于 WebSQL 的功能。
还有更多...
测试网站和在线应用程序从未如此简单。有许多可用的工具和服务,可用于在不同平台和各种浏览器上进行测试。
移动测试
您可以在智能设备上下载多个浏览器,如 iPod Touch 或 iPad,从而可以测试富媒体内容在移动设备和不同浏览器上的响应性。
Adobe 浏览器实验室
不需要 Adobe CS5 即可尝试 Adobe BrowserLab,这是一个与 Adobe CS5 产品集成的在线跨浏览器测试工具。访问browserlab.adobe.com
了解更多信息。
使用 BrowserShots 进行免费的跨浏览器和操作系统测试
对于预算有限且有时间的人来说,BrowserShots.org 是一个替代选择。该网站允许访问者输入其网站的 URL,然后从大量的浏览器和操作系统中进行选择。在免费版本的服务中,结果可能需要几分钟才能出现。
使用浏览器开发者工具监视 Web 存储
Web 存储可能很具有挑战性。使用浏览器中的开发人员工具,如 Safari 或 Firefox 附加组件,如 Firebug,可以更容易地诊断问题并跟踪变量的值。在本教程中,我们将使用 Google Chrome 浏览器中的本机开发人员工具来探索浏览器本地存储区域中存储的键/值对。
准备工作
您需要一个最新版本的 Google Chrome 浏览器和本章的一个本地存储代码文件。
如何做...
在 Google Chrome 浏览器窗口中打开本章中的一个本地存储练习文件。
单击查看 ,从查看 菜单中选择开发人员 ,然后从开发人员 弹出菜单中选择开发人员工具 。
当开发人员 窗口出现在当前页面上时,选择资源 选项卡,单击 Google Chrome 开发人员工具窗口导航区域中的本地存储 ,然后单击其中的子菜单。您应该看到类似以下截图的结果:
Google 开发人员工具窗口的资源选项卡下的本地存储部分为我们提供了对每个页面的本地存储区域的访问。它在屏幕右侧显示键和它们对应的值。如果您右键单击一个对象,您将有删除它的选项。
它是如何工作的...
我们加载了一个我们知道使用本地存储的页面,以测试 Google Chrome 浏览器中的 Google 开发人员工具窗口如何显示键/值对。
当我们在开发人员工具的左侧菜单中导航时,我们可以选择不同的 Web 存储方法和其他资源。
还有更多...
有许多免费的插件和本机浏览器工具,开发人员可以利用。
即使您不使用 Firefox,也可以使用 Firebug 附加组件
Firefox 用户长期以来一直在使用 Firebug 附加组件(getfirebug.com/downloads
)来调试和浏览网站和其他在线应用程序。Opera、Google Chrome、Safari 和 IE 6+的用户可以使用 Firebug Lite(getfirebug.com/firebuglite
),并通过轻量级的书签工具体验类似的功能。
Safari 开发人员工具是 Safari 浏览器的本机工具
打开 Safari 浏览器,单击Safari ,选择首选项 ,然后单击高级 选项卡。点击“在菜单栏中显示开发菜单 ”旁边的复选框,开始使用本机开发人员工具。
设置和获取会话存储变量
会话存储和本地存储都共享 Web 存储 API。在本教程中,我们将定义两个会话存储变量,然后在屏幕上显示它们。
准备工作
您需要一个支持会话存储的最新浏览器。如果您在本地计算机上测试文件,Safari 和 Google Chrome 会有最佳响应。
如何做...
首先,我们将创建一个 HTML5 页面的头部区域和一个开放的body
标签:
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Show me the session storage</title></head><body>
添加一个section
和一个article
标签。给文章标签一个 ID 为"aboutyou"。
<section><article id="aboutyou"><p></p></section>
接下来,我们将使用setItem
方法创建两个会话存储变量,如下面的代码块所示:
<footer><script>sessionStorage.setItem('nickname', 'Jumpin Joseph'); sessionStorage.setItem('interest', 'bike ramps and bmx racing');
现在我们将使用getElementByID
和getItem
方法在屏幕上显示我们刚刚设置的会话存储变量:
document.getElementById('aboutyou').innerHTML = ("Your nickname is: " + sessionStorage.getItem('nickname') + "." + " You are interested in: " + sessionStorage.getItem('interest') + "."); </script></footer></body></html>
结果应该在浏览器的 HTML 页面上显示,类似于以下截图中显示的方式:
它是如何工作的...
在这个例子中,我们为两个会话变量设置了唯一的值。会话存储使用键/值对,因此每个变量在创建时必须设置一个值。默认情况下,这些值是字符串。
我们通过输入sessionStorage.setItem('
为人的昵称定义了一个会话变量,然后为我们的变量添加了一个名称。
我们为变量"nickname"
命名,并赋予它值"Jumpin Joseph": 'nickname', 'Jumpin Joseph')
;。
当我们创建第二个会话变量来包含名为"interest"
的变量及其值时,我们使用了与设置第一个会话变量时相同的语法格式。
尽管通常这些变量将由表单中的值填充,但在示例中我们专注于使用正确的语法。sessionStorage
关键字标识了存储方法的类型。然后我们跟着一个句号,将setItem
动作附加到关键字上。然后声明了变量nickname
并赋予了Jumpin Joseph
的值。当使用时,这将告诉浏览器创建一个名为nickname
的新会话存储变量,并将Jumpin Joseph
的值存储在其中。然后我们创建了第二个会话存储变量,只是因为我们可以。在本章的本地存储示例中,我们将使用表单来获取变量值,以完整地展示存储方法的创建、使用和销毁的生命周期视图。
还有更多...
会话存储为我们提供了一种更强大的方式来提供短期客户端存储。
一个浏览器,一个会话
会话存储最适用于不需要访问者使用多个浏览器标签来浏览网站的情况,以及存储是临时的情况。虽然 HTML5 规范的数据存储区域仍在不断发展,安全性在金融机构或其他需要高度安全信息的网站中并没有长期的使用记录,但仍然有许多有用的方法可以利用会话存储。
另请参阅
设置和获取本地存储变量的教程 。
设置和获取本地存储变量
尽管会话存储是临时的,只在浏览器会话处于活动状态时持续。本地存储甚至在关闭浏览器后仍然存在。在这个教程中,我们将使用 HTML5 的contenteditable
属性和本地存储来创建一个写故事的应用程序。
准备工作
您应该使用最近更新的浏览器。这个教程在 Google Chrome 和 Safari 中效果最好,但在 Firefox 中也可以正常使用。
如何做...
首先创建一个基本的 HTML5 页面,然后在打开和关闭head
标签之间添加一个脚本标记。脚本应链接到ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js
上的 1.5.2 最小化的 jQuery 库。您的代码现在应该类似于以下代码块:
<!DOCTYPE html><html lang="en"><head><script src="img/ jquery.min.js"></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Local Storage: Storywriter</title>
接下来,我们将添加 CSS 样式来设置文章标记的background-color
和文本color
,以及font-family
。
<style> article{background-color: #9F6;color:#333; font-family:Verdana, Geneva, sans-serif} p{} </style>
关闭head
标记并为body
和header
元素创建开放标记。添加一个h1
标记来显示页面标题为Storywriter
,然后关闭header
标记。
</head><body> <header> <h1>Storywriter</h1> </header>
为section
和article
元素创建开放标记。将article
元素的 id 设置为“mypage”,并将contenteditable
属性设置为“true”。
<section><article id="mypage" contenteditable="true">
接下来,创建一个包含占位文本type something
的段落标记,然后关闭段落、article
和section
标记。在两个em
标记之间添加描述性的指令文本。您刚刚输入的内容应该看起来像以下代码:
<p>type something</p> </article> </section><em>And then what happened? I'll remember next time you open this browser. </em>
创建一个script
标记,然后键入$(function(){
声明 jQuery 函数。
使用参数字符串“mypage”调用document.getElementById
方法,并将其分配给变量'edit'。
接下来,我们需要添加一个事件处理程序,该处理程序由“edit”元素上的模糊事件触发。键入$(edit).blur(function(){
,然后键入localStorage.setItem('storyData", this.innerHTML);})
; 完成函数。
现在本地存储可以使用setItem
存储字符串,我们可以使用getItem
将存储的字符串内容推送回页面,方法是键入if ( localStorage.getItem('storyData') ) { edit.innerHTML = localStorage.getItem('storyData'); } })
;
脚本代码块现在应该看起来像以下代码块:
<script>$(function() { var edit = document.getElementById('mypage'); $(edit).blur(function() { localStorage.setItem('storyData', this.innerHTML); }); if ( localStorage.getItem('storyData') ) { edit.innerHTML = localStorage.getItem('storyData'); } });</script>
关闭 body 和 HTML 标签,并保存文件。在浏览器窗口中打开它。现在,您应该能够开始输入自己的故事,并在页面上看到输入的文本,即使您关闭浏览器并稍后重新打开它。它应该类似于以下截图:
工作原理...
当我们将article
标签的contenteditable
属性设置为true
时,我们告诉浏览器允许用户输入文本。大多数 HTML5 元素都可以声明contenteditable
属性,然后将其设置为true
或false
。然后,我们使用document.getElementById
捕获输入的内容,使用 idmypage
。getElementById
jQuery 方法搜索文档,查找其参数中列出的特定 ID 名称。然后,我们在blur
事件上添加了一个事件处理程序,以平滑地显示输入的文本。我们同时使用本地存储方法setItem
和变量storyData
存储文本。最后,我们使用getItem
本地存储方法检查storyData
是否存在,如果存在,则将其加载到可编辑的 HTML 元素中,使用edit.innerHTML
和getItem
。
另请参阅
本书中关于 HTML5 元素和 PACKT jQuery 书籍的早期章节。
使用 parseInt 将本地存储字符串转换为数字
在这个示例中,我们将从本地存储中获取一个字符串值,并将其转换为整数,以便我们可以使用parseInt
对其进行数学运算。
准备工作
我们将使用 Modernizr(www.modernizr.com
)来检测本地存储是否可用,将其托管在名为"js"的子文件夹中。您还需要至少一个最近更新的浏览器。
如何做...
创建一个新的 html 页面,直到标题标签,如下面的代码块所示:
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"> <title>Using numbers with local storage</title>
接下来,添加样式以指定h1
和h2
标签的字体族、文本颜色,以及h2
标签的背景颜色和高度。
<style>body{font-family:Verdana, Geneva, sans-serif;} h1{color:#333; }h2{color:#C30;background-color:#6CF; height:30px;}</style>
添加一个由 Google 托管的 IE HTML5 shiv,以及一个链接到本地 Modernizr JavaScript 文件:
<!--[if IE]><script src="img/html5.js"></script> <![endif]--><script type="text/javascript" src="img/ modernizr-1.7.min.js"></script>
通过 Modernizr 脚本的帮助,执行检查以查看浏览器是否支持本地存储:
<script>if (Modernizr.localstorage) {
// window.localStorage is available!}
else {// the browser has no native support for HTML5 storage document.getElementByID('yayanswer').innerHTML = "Local Storage is not supported by your browser. Maybe it's time for an update?";}
创建一个名为storemyradius()
的函数,声明一个名为myradiusToSave
的变量,并将其赋值为document.getElementById('myradius').value
;当访问者点击保存时,将值传递到文本字段中。
function storemyradius() {var myradiusToSave = document.getElementById('myradius').value;
添加一个if
语句,检查myradiusToSave
是否为 null。在此之下,创建一个本地存储setItem
方法,键为"myradius",值为"myradiusToSave"。在if
语句和storemyradius
函数的闭合括号之前,放置一个对displaymyradius()
的函数调用,如下面的代码块所示:
if (myradiusToSave != null) { localStorage.setItem('myradius', myradiusToSave);displaymyradius();}}
创建一个名为displaymyradius
的函数,不接受任何参数,然后添加一个名为myradius
的变量。将 JavaScript 函数parseInt
赋值给它,其中包含一个本地存储getItem
方法,参数为"myradius",基数为 10。到目前为止,函数应该看起来像以下代码块:
function displaymyradius() { var myradius = parseInt(localStorage.getItem('myradius'),10);
在同一个函数中,创建一个 if 语句,检查myradius
变量是否不为 null 且大于零。创建变量diameter
,并将其值赋为2
乘以myradius
的结果。使用document.getElementById
和innerHTML
来显示直径变量的值,以及在 HTML 页面的h2
标签之间显示消息"The diameter of the circle is"
。
if (myradius != null && myradius > 0) {var diameter = 2 * myradius;document.getElementById('yayanswer').innerHTML = "The diameter of the circle is: " + diameter + "!";}}
创建一个名为clearmyradius
的函数,不接受任何参数,然后创建一个if
语句,检查本地存储getItem
方法是否包含一个不为 null 的值。在if
语句的括号之间,放置本地存储removeItem
方法,参数为"myradius",并调用本地存储clear
方法。关闭脚本和头标签。我们刚刚编写的代码应该类似于以下代码块:
function clearmyradius() {if (localStorage.getItem('myradius') != null) {localStorage.removeItem('myradius'); window.localStorage.clear();}}</script></head>
创建开头的 body、section、hgroup
和h1
标签,并在闭合的h1
标签前输入"localStorage Number Conversion"
。创建一个h2
标签,并给它一个 ID 为"yayanswer"
。关闭hgroup
标签,然后为myradius
文本字段添加一个标签标签。将"Enter the radius of the circle:"
作为标签文本。创建一个带有 ID 为"myradius"
和maxlength
为"4"
的输入表单字段标签。创建两个输入按钮,一个带有onclick
值调用函数storemyradius()
;另一个带有onclick
值调用函数clearmyradius();
。关闭 section、body 和 html 标签,并保存页面。最终的代码块应该如下所示:
<body ><section><hgroup><h1>localStorage Number Conversion</h1> <h2 id="yayanswer"></h2></hgroup><label for="myradius">Enter the radius of the circle:</label><input id="myradius" maxlength="4" /> <input onclick="storemyradius();" name="save" type="button" value="save"><input onclick="clearmyradius();" name="clear" type="button" value="clear"></section></body></html>
在 Google Chrome 浏览器窗口中,完成的 HTML 页面应该如下所示:
它是如何工作的...
HTML 页面中显示的文本字段接受访问者输入并将其作为值传递给storemyradius()
函数。我们声明了一个名为myradiusToSave
的变量,并将其赋值为document.getElementById('myradius').value
;它存储了myradius
中包含的值。然后它将文本字段"myradius"中输入的值传递给本地存储的setItem
方法。在将值传递给本地存储之前,我们需要验证myradiusToSave
实际包含一个不为空的值。如果不为空,那么就有数据可以保存到本地存储中。然后,使用setItem
将该值保存到本地存储中,作为键/值对的一部分。为了将myradius
值作为数字使用,我们需要将其从字符串转换回整数。这是通过调用parseInt
JavaScript 函数来完成的。接下来,我们创建了一个名为diameter
的变量,用于保存我们的直径公式的结果,即半径值乘以 2。最后,我们使用getElementbyId
方法将结果返回到屏幕上。
页面上的另一个选项是清除本地存储变量的值。虽然我们可以使用removeItem
方法,但同时使用 clear 方法也可以确保没有其他本地存储变量潜伏。打开 Google 开发者工具刷新页面,验证本地存储区域为空。
还有更多...
目前,默认情况下,localStorage
将所有数据存储为字符串。我们刚刚练习了将localStorage
变量转换为整数,但它们也可以转换为数组等对象。
在 localStorage 中存储和检索数组
在许多情况下,您会希望使用localStorage
与数组一起保存游戏中的进度或保留用户数据或消息。您可以使用 Douglas Crockford 的 JSON 库来简化数组的存储和检索。访问github.com/douglascrockford/JSON-js
下载代码并了解更多关于 JSON 的信息。
创建一个新的 HTML5 页面,在两个页脚标签之间添加脚本标签。声明一个名为"horsedef"的新变量数组,并将以下键/值对分配给它,如下所示:
var horsedef = {"species":"equine","legs":4,"ears":2, "purposes":{"front":"neigh","behind":"flick"}};
现在,在本地存储中设置一个名为"describehorse"的新项目,同时使用JSON
将我们的数组horsedef
转换为字符串,如下所示:
window.localStorage.setItem('describehorse', JSON.stringify(horsedef));
使用 JSON 解析从本地存储中检索值:
console.log( alert('A horse is a horse of course! ' + JSON.parse (localStorage.getItem('describehorse')) ); // => Object { species="equine", more...} </script>
保存页面,并打开浏览器窗口。您应该看到一个警报框,显示了传递给describehorse
的horsedef
数组中的键/值对,如下面的屏幕截图所示:
提示
在使用 JSON 时要注意跨站点回调。通常最好从自己的服务器下载并使用文件。始终直接从源下载您的 JSON 副本。不要上当受骗,比如 JSONP。
创建 Web SQL 数据库
在这个示例中,我们将创建一个 Web SQL 数据库,并为其定义版本、名称、大小和描述等属性。
准备工作
您需要使用支持 Web SQL 数据库的当前浏览器。
如何做...
创建一个新的 HTML5 文件,在两个页脚标签之间放置开头和结尾的脚本标签。声明一个名为db
的变量,然后将openDatabase()
赋给它。给openDatabase
传递以下参数:'mymotodb', '1.0', 'Motocross Rider List DB', 2 * 1024 * 1024
,然后关闭声明。代码应该如下所示:
<script>var db = openDatabase('mymotodb', '1.0', 'Motocross Rider List DB', 2 * 1024 * 1024);</script>
保存文件。
它是如何工作的...
所有 Web SQL 数据库都使用openDatabase
方法来为数据库分配值。第一个参数“mymotodb”是数据库的名称。接下来是必需的版本号参数。这里的数字必须与用户尝试使用 Web SQL 数据库时匹配。接下来,我们定义了数据库的描述,然后是估计的大小。一旦为请求的openDatabase
方法定义了所有参数,数据库就被创建,并且第一个(不可见的)事务发生了——数据库本身的创建。
更多信息...
浏览器对规范的实现,如 Web SQL 数据库,一直非常不可预测,同样在 Web 开发社区内对这些规范本身的支持也是如此。
Web SQL 可能会被 SQLite 替代
Web SQL 数据库规范本身已不再由 W3C 维护,但在大多数浏览器中它仍然运行得相当好。在未来一年左右的时间内,足够多的主要利益相关者可能会就如何实现不同的客户端数据库解决方案达成一致,比如 SQLite,但这样的事情很难预测。请关注www.w3.org/TR/webdatabase/
上的规范,以获取有关使用客户端数据库的当前选项的更新。
使用 Web SQL 数据库
在这个示例中,我们将使用前一个示例中创建的数据库,并向其中添加表和数据,然后在 HTML 页面上显示结果。
准备工作
您需要一个当前的浏览器和一个带有基本标签的 HTML5 页面,用于头部区域和正文区域。
如何做...
在一个基本的 HTML5 页面上,添加一个h1
标签来显示页面标题,然后创建一个 ID 为“status”的div
标签来保存我们的结果,如下面的代码块所示:
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>Using WEB SQL Databases</title></head><body><article><section><header><h1>Today's Riders</h1></header><div id="status" name="status"></div> </section></article><footer>
开始脚本,如前一个示例所示,以创建数据库(如果尚未创建)。创建一个名为 info 的新变量,然后创建一个包含接受参数的函数的新事务。使用传递的参数,创建一个名为 RIDERS 的表,其中包含唯一 ID 和名为ridername
的行。代码应该类似于以下代码块:
var info;db.transaction(function (tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS RIDERS (id unique, ridername)');
将数据添加到表行中,使用唯一 ID 和每个名称的文本字符串:
tx.executeSql('INSERT INTO RIDERS (id, ridername) VALUES (1, "Joe Fly")'); tx.executeSql('INSERT INTO RIDERS (id, ridername) VALUES (2, "Gira Ettolofal")'); });
执行查询以从数据库中提取数据:
db.transaction(function (tx) { tx.executeSql('SELECT * FROM RIDERS', [], function (tx, results) {
创建一个新变量和for
循环来循环遍历结果并将其打印到屏幕上:
var len = results.rows.length, i; for (i = 0; i < len; i++){ info = "<p><b>" + results.rows.item(i).ridername + "</b></p>"; document.querySelector('#status').innerHTML += info; } }, null);});
关闭脚本和 HTML 页面。
</script></footer></body></html>
它是如何工作的...
当我们在浏览器中打开我们刚创建的页面时,我们将看到我们使用数据库来显示的信息。这是因为查询和循环一起工作,通过数据库并显示适当的信息。
更多信息...
HTML5 中的安全性和数据库事务可能执行不佳。在生产环境中,应该注意保护接受 SQL 查询的任何页面。
将脚本代码保存在单独的文件中
为了使这个示例保持简单,我们没有将 SQL 查询代码和 JavaScript 存储在单独的文件中。这可以通过将代码保存在子文件夹中来实现,例如../js/myCode.js
。注意使用 Web SQL、Indexed DB 或任何其他类型的基于浏览器的查询 API 来获取安全信息。
在生产服务器上防止 SQL 注入
每当有可编辑字段时,都有可能会有一些机器人来尝试进行 SQL 注入攻击。可以通过在事务请求中使用“?”来采取基本预防措施。以下代码显示了一个例子。
store.db.transaction(function(tx) { tx.executeSql( "insert into bmxtricks " + "(time, latitude, longitude, trick) values (?,?,?,?);", [bmxtricks.time, bmxtricks.latitude, bmxtricks.longitude, bmxtricks.trick], handler, store.onError );});
另请参阅
SQL 的 Packt 图书,任何覆盖客户端数据库的 Packt HTML5 图书。
为离线存储创建缓存清单
在这个配方中,我们将创建一个缓存清单文件,以便我们可以离线存储一个 HTML5 页面,并仍然查看页面上显示的图像和视频。
准备工作
您将需要一个 HTML5 页面,比如本配方的代码文件中提供的页面,并且可以上传文件到服务器,然后在计算机、智能手机或其他具有浏览器的网络设备上查看这些文件。
如何做...
首先,我们将创建缓存清单文件。这应该在一个简单的文本编辑器中创建。它应该包含用户在离线状态下访问所需的所有文件和支持代码。首先列出的是当前文件类型(CACHE MANIFEST)。清单的版本号也应包括在内。请注意,我们在以下代码块中添加了所有要让用户访问的文件的路径:
CACHE MANIFEST
# version 0.1
itsallgooed.html
css/Brian Kent Font License.txt
css/exact-css-from-tutorial.css
css/font-stylesheet.css
css/plasdrip-webfont.eot
css/plasdrip-webfont.svg
css/plasdrip-webfont.ttf
css/plasdrip-webfont.woff
css/plasdrpe-webfont.eot
css/plasdrpe-webfont.svg
css/plasdrpe-webfont.ttf
css/plasdrpe-webfont.woff
css/style.css
images/gooed-science-logo.jpg
images/promo-bg.jpg
images/gakposter.png
movie/GakHowTo.mp4
movie/GakHowTo.ogv
movie/GakHowTo.webm
在index.html
页面的DOCTYPE
标签和head
标签之间添加一个 manifest 属性,如下所示:
<!DOCTYPE html> <html lang="en" manifest="gooed.manifest"> <head>
最后,创建一个.htaccess
文件来创建正确的 mime 类型:
AddType text/cache-manifest .manifest
页面应该显示类似于以下内容:
它是如何工作的...
创建缓存清单为浏览器提供了一个在离线加载页面时使用的清单。虽然离线存储页面的想法是它不需要频繁更新,但使用版本号允许作者在用户下次连接到互联网时推送更新。
并非所有浏览器或系统都能正确解释清单文件类型,因此包含一个.htaccess
文件可以确保正确识别缓存清单。
您可以排除您认为不重要的文件,以降低离线页面的大小并减少加载时间。
使用地理位置和 geo.js 显示当前位置
在这个配方中,我们将使用地理位置规范和geo.js
来显示活跃用户的当前位置在地图上,并显示他们当前的纬度和经度。
准备工作
访问code.google.com/p/geo-location-javascript/
下载最新版本的geo.js
,或者直接从 wiki (http://code.google.com/p/geo-location-javascript/wiki/JavaScriptAPI )获取链接 URL 在线链接到它。
如何做...
首先,我们将创建 HTML5 开头页面标签:。
然后,在 meta 标签中,我们将把 name 属性设置为"viewport",并为 content 属性定义以下值:width = device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no
;
现在,声明一个带有 src 属性的脚本标签:code.google.com/apis/gears/gears_init.js
然后,调用geo.js
脚本:src="img/geo.js"
。
到目前为止,代码块应该如下所示:
<html><head><meta name = "viewport" content = "width = device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=no;"> <script src="img/gears_init.js" type="text/javascript" charset="utf-8"></script><script src="img/geo.js" type="text/javascript" charset="utf-8"></script>
为 Google Maps API 添加一个脚本标签:<script type="text/javascript" src="img/js?sensor=false"></script>
。
现在,我们将创建一个初始化地图的函数initialize_map()
,然后创建一个名为myOptions
的数组来存储地图属性。这些属性基于 Google Maps API。它们应该看起来类似于以下代码块:
<script>function initialize_map(){ var myOptions = { zoom: 4, mapTypeControl: true, mapTypeControlOptions: {style: google.maps.MapTypeControlStyle.DROPDOWN_MENU}, navigationControl: true, navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL}, mapTypeId: google.maps.MapTypeId.ROADMAP }
使用google.maps.Map()
方法向页面添加一个名为 map 的新地图,该方法以document.getElementById
元素作为参数,而document.getElementById
又传递了 id 为"map_canvas"。google.maps.Map
接受的另一个方法是myOptions
。
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);}
创建initialize()
函数,并添加一个if
语句来检查geo_position_js.init()
函数是否处于活动状态。使用document.getElementById
和innerHTML
为 id 为"current"的 div 输入一个新的状态。状态文本为"Receiving…"。
function initialize(){ if(geo_position_js.init()){ document.getElementById('current').innerHTML="Receiving...";
如果我们无法获取位置或者由于某种原因浏览器不支持获取当前位置,可以在 helper 消息文本中添加文本以显示,如下所示的代码块:
geo_position_js.getCurrentPosition(show_position,function(){document. getElementById('current').innerHTML="Couldn't get location"}, {enableHighAccuracy:true}); } else{document.getElementById('current').innerHTML="Functionality not available"; }}
function show_position(p){ document.getElementById('current').innerHTML= "latitude="+p.coords.latitude.toFixed(2)+" longitude="+p.coords.longitude.toFixed(2); var pos=new google.maps.LatLng( p.coords.latitude,p.coords.longitude); map.setCenter(pos); map.setZoom(14);
创建一个名为infowindow
的新变量来显示google.maps InfoWindow
,这是一个在单击标记时显示的气泡。给它一个文本字符串“yes”来显示。创建一个新的与用户当前位置相关联的标记,以及标记的标题文本,该文本将在鼠标悬停时显示。添加一个事件侦听器来检测标记何时被点击。
var infowindow = new google.maps.InfoWindow({ content: "<strong>yes</strong>"}); var marker = new google.maps.Marker({ position: pos, map: map, title:"Here I am!" }); google.maps.event.addListener(marker, 'click', function() { infowindow.open(map,marker);});}</script >
样式页面以控制字体系列,填充以及标题和当前 div 的外观。
<style>body {font-family: Helvetica;font-size:11pt; padding:0px;margin:0px} #title {background-color:#0C3;padding:5px;} #current {font-size:10pt;padding:5px;}</style></head>
在 body 标签中创建一个onLoad
命令,初始化initialize_map()
和initialize()
函数以在页面加载时运行。创建一个新的div
来显示页面标题,以及一个 id 为“current”的第二个div
来显示位置获取过程的当前状态。最后,创建一个 id 为map_canvas
的div
来包含地图一旦显示,并使用内联样式设置div
的宽度和高度。关闭标签并保存页面。
<body onLoad="initialize_map();initialize()"><div id="title">Where am I now?</div> <div id="current">Initializing...</div> <div id="map_canvas" style="width:320px; height:350px"></div></body></html>
在浏览器窗口中打开页面,您应该看到类似以下截图的结果:
它是如何工作的...
使用geo.js
简化了在多个设备上使用地理位置信息。它提供了准备好的错误消息,并遵循 W3C 的实现标准,以及“回退”到诸如 Google Gears 之类的工具的能力。首先,我们需要创建一个包含地图显示和处理选项数组的变量脚本,实例化一个新的地图对象,并绘制一个标记以将用户的当前位置固定到屏幕上。悬停在标记上会显示一个带有标题文本的气泡窗口。这个文本也可以包含一个链接,用于获取并显示驾驶方向、评论或笔记。当页面加载时,地图选项创建函数map_initialize()
和主要的触发函数initialize()
被调用。在使用geo.js
的帮助下确定用户的当前位置并绘制地图时,会显示一个临时状态消息。