简介
本系列文章共两部分,在第 1 部分中,将创建将 canvas API 和 HTML/CSS 两种模型的优点结合在一起的应用程序。canvas API 是要求高性能、低负荷图形的 Web 应用程序的理想选择。然而,如果仅仅围绕 canvas 设计整个应用程序而忽略传统 HTML/CSS 模型的优点则不免短视。与其想当然,不如学习一些在 HTML/CSS 中非常有用但在 canvas 中难以或无法实现的功能。
常用缩略词
本文将采用一种 “混合” 方法来设计应用程序,使之能够同时利用传统的 HTML 组件和 canvas 元素。本文稍后将讨论采用这种方法的目的,包括为什么完全基于 canvas 的实现不够理想,并讨论传统 HTML 模型与 canvas API 相比的优点和缺点。一些示例还帮助您在设计应用程序时规划 HTML 和 canvas 元素的布局和交互。
您可以 本文使用的示例源代码。
HTML 和 CSS 模型的优点在一些场景中,使用 HTML 和 CSS 的传统 web 模型更具优势。本节将探讨 HTML 模型的最有用的优点,该模型在 canvas API 中并没有受到很好的支持,或者根本不受支持,特别是其健壮的文本支持和与语义 HTML 标记有关的优点。
HTML 的健壮文本支持HTML 的一个强项就是它能够轻松地利用样式符号对文本添加注解,包括 <b></b> 之类的格式化标记和 font-weight:bold 等 CSS 规则。
另一方面,canvas API 公开了 fillText() 方法,将文本字符串呈现为一个位图。这是一种简单、低级的调用,但是有诸多限制。最大的限制之一就是只能对提供给 fillText() 的文本字符串应用一种统一的样式规则。这里所说的 “样式规则” 可以看作是一个用于设置字体、大小、颜色等的规则(类似 CSS 规则)。
采用统一样式的文本考虑图 1 中的文本。
图 1. 样式文本由于文本包含一个统一的样式规则(红色、斜体和宋体字),您使用 HTML/CSS 或 canvas 都能够很好地显示这一文本。
清单 1 和清单 2 中的代码比较了如何使用 HTML 和 CSS 以及 canvas 呈现这个文本。请参阅 中的例子。
清单 1 显示了使用 HTML 和 CSS 呈现的图 1 中的文本。
清单 1. 在 HTML 和 CSS 中使用统一样式呈现文本<style> .uniform-style { font: italic 12px Arial; color: red; } </style> <span> Variety is the spice of life! </span>
清单 2 展示了使用 canvas 呈现的同一文本。
清单 2. 在 canvas 中使用统一样式呈现文本var canvas = document.getElementById('my_canvas'); var context = canvas.getContext('2d'); context.font = 'italic 12px Arial'; context.fillStyle = 'red'; context.fillText('Variety is the spice of life!', 0, 50);
采用动态样式的文本考虑图 2 中的文本。
图 2. 采用动态样式的文本清单 3 给出了呈现文本所需的 CSS 规则。
清单 3. 在 HTML 和 CSS 中使用动态规则呈现文本<style> .dynamic-style { font: 12px Arial; color: blue; } .dynamic-style strong { font-size : 18px; color: green; } .dynamic-style em { color: red; font-weight: bold; font-style: italic; } </style> <span> <strong>Variety</strong> is the <em>spice of life</em>! </span>
因为 canvas API 中未提供 HTML 标记或 CSS 类等概念,而这些概念允许您对不同字体样式进行注解,因此呈现前例中相同的文本块变得十分复杂。
由于 canvas API 可以充当一个连续的状态机,因此要产生图 2 的效果需要采用称为 “canvas API” 的方法。您必须选择一种要使用的样式,输入需要使用该样式的部分文本,再选择另一种样式,然后输入文本的下一部分,诸如此类。
通常,可以通过以下算法实现这一过程:
清单 4 显示了该算法最基本、原生的实现。
清单 4. 在 canvas 中使用动态样式呈现文本context.font = '18px Arial'; context.fillStyle = 'green'; context.fillText('Variety', 0, 50); context.translate(60, 0); //move 60 pixels to the right (a) context.font = '12px Arial'; context.fillStyle = 'blue'; context.fillText('is the', 0, 50); context.translate(35, 0); //move 35 pixels to the right (b) context.font = 'italic bold 12px Arial'; context.fillStyle = 'red'; context.fillText('spice of life!', 0, 50); // (c)
图 3 解释了在依次呈现三个不同的文本时它们是如何显示的。
图 3. 在 Canvas 中呈现的文本在本文后面,您将看到如何对这种方法进行改进,我们将在原生的 canvas fillText() 函数之上添加另一个抽象层。不管使用哪一种方法,typewriter 算法始终是核心。
应当注意,HTML/CSS 中的大部分文本样式(如文字环绕、字母间隔和行高)从一开始并不受 canvas API 支持。如有必要,需要您自己修改算法并实现这些功能。
至此,您应当很清楚地为什么文本呈现对于 canvas API 并不是一件容易的事,以及为什么传统的 HTML 模型在文本格式化方面表现更为出色。
HTML 的富有含义的语义优秀的 Web 设计的一个重要因素就是有意义、语义正确的 HTML 结构。HTML 语义在编写时考虑了合适的结构和含义,因此具备许多优点。
canvas 的核心其实就是一个绘图仪,因此不存在有含义的标记这一概念,并且完全针对 canvas 编写的应用程序也无法利用有含义的 HTML 标记的诸多优点。例如,从搜索引擎和视力受损用户的角度来看,一个 canvas 元素实际上将显示为一个毫无意义的黑框。
下面,我们将研究有含义 HTML 标记的几个优点。
搜索引擎感知搜索引擎根据自动化搜索机器人 (bot)/爬行器 (spider) 读取的信息创建它们的搜索索引,当一个搜索爬行器访问您的网页时,它将解析 HTML 来尽量多地提取有含义的信息。
由于在 canvas 上以编程方式显示的文本其实就是位图,因此搜索爬行器将完全忽略文本。因此,一定要注意如果您的整个应用程序都在 canvas 中开发,那么搜索爬行器几乎无法从您的页面中搜索到上下文信息。
尽管如此,搜索引擎仍然能够在 <canvas> 元素中读取任何回退 (fallback) 文本,该元素主要针对不兼容 HTML5 的浏览器,如清单 5 所示。
清单 5. canvas 元素中的回退文本<canvas> We are sorry, your browser doesn't support HTML5! </canvas>
这对于 canvas 来说并不是什么刚刚发现的问题,缺少搜索引擎感知能力一直以来都困扰着针对 Flash 和 Silverlight 等浏览器插件编写的应用程序。
可访问性