CSS3-动画高级教程-全-

CSS3 动画高级教程(全)

原文:Pro CSS3 Animation

协议:CC BY-NC-SA 4.0

零、简介

欢迎来到专业 CSS3 动画。这本书教你如何使用 CSS 的全部力量,通过交互性和新鲜的视觉方法使你的网页内容生动起来。在接下来的章节中,您将学习如何使用最先进的行业标准来增加网站的视觉吸引力、可访问性和受欢迎程度。

这本书是给谁的

这本书是为至少有几年 web 开发经验的设计人员和编码人员设计的,他们希望快速提升自己的技能以适应新的 W3C 标准,或者希望以大胆的新方向探索 CSS 转换、过渡和动画。这不是一个介绍性的网页设计文本:这本书假设至少对 HTML、CSS 和 JavaScript 有基本的理解。由于 web 开发是一个多学科的过程,我还将讨论诸如可访问性和语义等读者应该熟悉的概念。

这本书的结构

我把这本书分成十章。第一章介绍了 CSS 动画的基本组件,而后面的章节将动画与其他 web 技术相结合。

第一章 介绍了 CSS3,详细介绍了它的语法和发展,并与以前的技术进行了对比。

第二章 涵盖了 CSS3 的变换和转场。

第三章 展示了如何对图像使用 CSS3 过渡,包括图库效果。

第四章 将过渡与按钮、菜单等站点用户交互元素集成在一起。

第五章 介绍 CSS 动画模块。

第六章 在各种网页内容上使用 CSS3 动画。

第七章 展示了如何将 CSS3 过渡和动画与可缩放矢量图形(SVG)和 CSS 滤镜相集成。

第八章 将响应式网页设计和 JavaScript 与 CSS 动画结合在一起。

第九章 将变换、过渡、动画带入第三维。

第十章 展望视觉效果的 web 标准的未来,以及今天可以用来简化 CSS web 动画的各种工具。

下载代码

本书中所示示例的代码可在 Apress 网站www.apress.com上获得。在该书的信息页面上的源代码/下载选项卡下可以找到一个链接。该选项卡位于页面相关标题部分的下方。

联系作者

如果您有任何问题或意见,或者发现了您认为我应该知道的错误,请随时通过电子邮件(dudley.storey@gmail.com)或 Twitter (@dudleystorey)与我联系。我欢迎你的想法和反馈。

一、CSS3 基础知识

近二十年来,级联样式表(CSS)标准一直被用来控制网页的显示。HTML 定义了是什么:标题、段落、地址、图片等等。CSS 描述了元素是如何呈现给用户的,包括颜色、边框和尺寸。CSS 包括很少有网页设计者考虑的表示控件,例如文本到语音转换服务对网页内容的发音方式。

CSS 的所有原始表示规则都是为静态内容设计的;即不随时间变化的 HTML 元素。直到最近,如果你想让一张图片在网页上淡入,只有几种网络技术可以使用,其中最流行的是 JavaScript 和 Flash 。然而,这些技术并不是完整的解决方案;它们有几个严重的缺点,我将在本章末尾讨论。

现在,我们有了 CSS3 变换、过渡和动画模块。这些是所有现代浏览器都支持的 CSS 语法的扩展,重叠,在某些情况下,取代了 JavaScript 和 Flash 的传统角色。虽然 CSS3 也有其局限性,但它是许多动态网页内容的发展方向。

要了解我们是如何走到这一步的,你需要知道我们去过哪里。这一介绍性章节将提供 CSS 开发过程的概述,以及 web 开发的现状,展望未来。

CSS 的开发

web 技术的独立发展有一段不稳定的历史:浏览器供应商有时推动技术向前发展,而其他技术实现通过采用不兼容的方法使 web 开发变得复杂。

万维网联盟(W3C) 的成立是为了尝试将 web 技术综合并标准化为一系列规范,这些规范得到了 Web 开发行业的广泛支持。W3C 可以被称为 web 开发的联合国:作为一个独立的标准机构,它可以评估不同的提议;为工业界、学术界、开发者和其他利益相关者之间的讨论创建论坛;谈判和解决分歧;并敲定每个人都同意遵循的最终规范。

CSS 标准是由 CSS 工作组(CSSWG) 开发的,它是 W3C 的一个子组。随着时间的推移,CSSWG 扩展了 CSS,对网页内容的更多方面提供了更好的控制。随着 CSS 2.1 接近它的最终完成状态,规范的进一步开发被分成多个模块。这些模块中的许多都是从“第三级”建议开始的,这导致开发人员使用无所不包的术语 CSS3 来描述 CSS2.1 之后的任何东西。从技术上来说,我在本书中关注的 web 技术——动画、变换和过渡——都是全新的第一级规范,因为它们在 CSS1 或 CSS2 中没有先例。在非常正式的讨论之外,web 开发行业将它们统称为 CSS3 ,我将在本书中继续这样称呼。

与此同时,浏览器开发者继续创新。我将在本书中讨论的许多 CSS 属性最初是由 Apple、Google 和 Mozilla 提出的,而不是 W3C 或 CSS 工作组。这导致了一个问题:开发人员希望他们的浏览器支持这些很酷的技术今天,而不必等待 W3C 推荐、讨论和最终批准的漫长过程。每个人都知道 90 年代浏览器战争的惨痛教训以及相关的技术冲突。浏览器如何支持他们公司提出的最新技术,同时明确这些新特性是实验性的,并且不与 W3C 随后可能出现的官方声明相冲突?

这个解决方案被证明是可行的,但是有争议:CSS 厂商前缀。

CSS 厂商前缀

为了允许浏览器开发人员对 CSS3 进行创新,web 开发社区同意每个浏览器都有自己独特的前缀,用于提议的或实验性的 CSS 属性(参见表 1-1 )。

表 1-1。独特的浏览器前缀

前缀 浏览器
-moz--o- 浏览器
-webkit--ms- Safari/Chrome/KonquerorInternet Explorer 9+

image 注意此处显示的供应商前缀并不是唯一存在的,只是您在大多数情况下需要的前缀。供应商前缀的完整列表可在http://alrra.github.com/little-helpers/vendor-prefixes/)找到。

每个打算支持实验性 CSS 属性的浏览器都可以通过在其前面放置自己的供应商前缀来实现。请注意,这些属性在获得 W3C 的最终批准之前是不标准的。在那之前,它们对供应商和 W3C 本身的修改和解释都是开放的。由于考虑了不同的方法并制定了不同的标准,即使在同一个浏览器中,属性名及其值的指定方式也可能会快速变化。例如,直到 Safari 5.1/iOS 5.0 发布之前,Webkit 开发团队提出了以下在 CSS 中实现线性渐变的方法:

body { background-image: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0.11, rgb(167,9,246)),
color-stop(0.56, rgb(194,242,242)) );

其他浏览器以不同的方式实现渐变。例如,在 Firefox 中是这样做的:

body {
background-image: -moz-linear-gradient(bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
}

这两种方法在每个浏览器中产生相同的结果;争论的焦点是哪种编码方式更好。在渐变的情况下,W3C 采取了第三种方式,与 Firefox 的方法更接近:

body {
background-image: linear-gradient(to bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
}

然而因为浏览器不能被强制追溯升级,所以仍然有必要包含早期的厂商前缀方法,以支持旧版本。在渐变的情况下,这包括基于 Webkit 的浏览器的两种方法,这两种方法切换到支持现在的标准方法,但暂时保留供应商前缀。

约定规定 W3C 方法(最终的、预期的标准)在声明中放在最后,供应商前缀的版本放在它的前面。所有浏览器的完整声明如下:

body {
background-image: -o-linear-gradient(bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
background-image: -moz-linear-gradient(bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
background-image: -webkit-linear-gradient(bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
background-image: -ms-linear-gradient(bottom, rgb(167,9,246) 11%, rgb(194,242,242) 56 %);
background-image: -webkit-gradient(linear, left bottom, left top,
color-stop(0.11, rgb(167,9,246)),
color-stop(0.56, rgb(194,242,242)) );
background-image: linear-gradient(to top, rgb(167,9,246) 11%, rgb(194,242,242) 56%);
}

由于浏览器只关注他们理解的 CSS,而忽略任何他们不理解的 CSS,Safari 和 Chrome 将读取适用于该浏览器版本的声明的-webkit 行并实现它。理解规范最终版本的更高版本的浏览器将读取最后一行。

浏览器完全有可能同时支持带前缀和不带前缀的 CSS 属性。声明中的外观规则是从左到右、从上到下读取的。在有冲突的情况下,在之后规定的规则优先于在之前规定的规则。将 W3C 标准放在声明的最后确保了如果浏览器支持它,它将总是优先。

虽然这段代码看起来有些令人生畏,但很明显其中有大量的重复。除了不赞成使用的 Webkit 方法之外,大多数 CSS 声明都可以通过复制和粘贴第一行并在副本前添加供应商前缀来轻松创建。还有自动生成厂商前缀代码的工具和技术,我将在第十章中讨论。

为了在特定的浏览器中获得对实验性 CSS 属性的支持,您必须在样式表中包含适当的供应商前缀和值。只有两个例外:

  • 浏览器允许前缀别名(将在下一节讨论)。
  • 浏览器遵循最终的 W3C 标准,不需要前缀。

令人欣慰的是,CSS 变换、过渡和动画的属性和值从模块开始就已经被广泛认同;在撰写本文时,所有当前的浏览器都以相同的方式实现代码,尽管带有供应商前缀。

image 2012 年 6 月 6 日,W3C 最终确定了过渡、动画和转换的规范,并同意让所有浏览器厂商支持它们,而不使用厂商前缀。Internet Explorer 10 是第一个这样做的浏览器,预计其他浏览器将很快跟进。旧版本的浏览器仍然需要供应商前缀。

供应商前缀问题

虽然供应商前缀系统可以工作,但它确实有几个问题。异常和边缘情况可能很难跟踪和记忆。例如,在所有浏览器中实现段落断字的最佳当前解决方案如下:

p { −ms-word-break: break-all; word-break: break-all; word-break: break-word;
-moz-hyphens: auto; -webkit-hyphens: auto; hyphens: auto; hyphenate: auto;  }

正如您所看到的,前面的一些 CSS 声明使用了供应商前缀,但是属性名称和值最终与 W3C 建议不匹配,并且不同的浏览器使用其他属性。

此外,一些浏览器供应商倾向于保留他们的专有前缀,并且在标准达成一致后不弃用它们,要求开发人员维护遗留的带前缀的 CSS 代码。

最后,懒惰的开发人员倾向于只实现一个或两个供应商前缀,忽略了在他们自己的规范版本下提供同等支持的其他浏览器。例如,许多开发人员会在他们的样式表中包含-moz 和-webbkit 前缀属性,但忘记添加-ms 或-o。因此,一些浏览器——最明显的是 Opera 的最新版本——能够识别其他供应商前缀。在 Opera 的情况下,这意味着一些-webkit 前缀属性。

image 注意因为一个包含所有厂商前缀的完整 CSS 声明可能会很长,所以本书中的代码示例通常只使用最终的预期规范。如果你想在所有浏览器中获得完全的向后兼容性,在大多数情况下,你不应该将前缀属性局限于你在这里看到的例子。

CSS3 浏览器支持

带有供应商前缀的以下浏览器版本完全支持 CSS3 转换:

  • Internet Explorer 9 (IE10 不需要前缀)
  • Firefox 3.5 及以上版本
  • Chrome 4 及以上版本
  • Safari 3.1 及更高版本
  • Opera 10.5 及以上版本
  • iOS Safari 3.2 及以上版本
  • 歌剧移动 11
  • Android 2.1 及以上版本

带有供应商前缀的以下浏览器版本完全支持 CSS3 转换:

  • Firefox 4 及以上版本
  • Chrome 4 及以上版本
  • Safari 3.1 及更高版本
  • Opera 10.5 及以上版本
  • iOS Safari 3.2 及以上版本
  • Opera Mobile 10
  • Android 2.1 及以上版本

Internet Explorer 10 支持不带前缀的转换;其他浏览器的最新版本也会这样做。

带有供应商前缀的以下浏览器版本完全支持 CSS3 动画工作草案:

  • 火狐 5 及以上版本
  • Chrome 4 及以上版本
  • Safari 4 及以上版本
  • Opera 12 及以上
  • iOS Safari 3.2 及以上版本
  • Android 4.0 及以上(2.1 起部分支持)

同样,Internet Explorer 10 支持不带前缀的 CSS 动画。

image 提示 www.caniuse.com是跟踪浏览器对 CSS3 支持的极好资源。

CSS3 动画 的局限性

虽然 CSS3 的变换、过渡和动画非常强大,但有几个属性是它们不能影响的,至少目前不能:

  • CSS3 不能控制滚动条或“滚动”整个文档
  • 渐变不能被动画化(尽管这可以通过 SVG 或 JavaScript 来实现)。

设计原则:渐进增强和优雅退化

CSS 和 JavaScript 共有的设计方法之一是优雅退化,也称为渐进增强。简单地说,这个想法是用 CSS 来增强一个网站,而不是让网站完全依赖于它。

当您开始制作动画内容时,这变得尤其重要。因为 CSS3 只在某些浏览器中受支持,所以在应用高级技术时,你应该总是问:“如果浏览器没有显示我试图实现的内容,网站还能使用吗?”

这对于一些人来说是有问题的,尤其是客户,他们坚持认为一个站点应该“在每个浏览器中看起来和执行起来完全一样”然而,在 iPhone 和响应式网页设计的时代,这不再是一个现实的期望。相反,您需要将向站点添加高级 CSS 视为一系列假设场景:

  • 如果你用 CSS3 在网页上制作图像幻灯片(如第六章所示),浏览器不支持,会发生什么?如果用户看到一个静态的占位符图像来代替幻灯片,这样可以吗?还是需要使用 JavaScript 作为退路?
  • 如果你用 CSS3 来增强一个站点的导航条的动画效果,一些用户看不到动画效果可以吗?没有导航条他们还能用吗?

本书中的各种示例和教程将展示实现向后兼容性的不同解决方案,因为没有一种实践或技术适用于所有情况。同时,我也会强调可访问性;也就是说,允许具有不同需求和能力的用户(例如盲人或使用键盘而不使用鼠标的网站访问者)访问您的作品。

为什么是 CSS3 而不是 JavaScript 或 Flash?

你可以在表 1-2 中找到使用 CSS3 而不是 JavaScript 或 Flash 的优缺点的综合列表。

表 1-2 。CSS3 与 JavaScript 和 Flash

CSS3
优势
建立在熟悉的基础上;使用既定的 CSS 语法。简单易懂。
浏览器中最快、最流畅的动画形式,帧速率高于 JavaScript。
操纵现有的 HTML 内容,增强搜索引擎优化。
闪光
优势
建立良好的图形用户界面来创建动画。
循环、变量和函数使 ActionScript (Flash 的脚本语言)比 CSS 更强大。
JavaScript
优势
支持良好,有许多框架。
通过 DOM 和 CSS 操作 HTML 元素,这是任何 web 开发人员都熟悉的。
循环、变量和函数使这门语言比 CSS 更强大。

其他技术

对于其他新的网络技术的角色存在一定程度的混淆,特别是在客户端,所以讨论 CSS3 动画不是什么是值得的。

  • CSS3 不是 HTML5 。虽然这两种技术往往被相提并论,但 CSS3 与 HTML5 无关。标记不是表示:CSS3 同样适用于 XHTML 或 HTML3.1。在本书中,您将使用 HTML5 作为您的标记,但不是必须的。

  • CSS3 不是画布。

    是一个 HTML5 元素,在网页上创建一个 JavaScript 可访问的“绘图区域”。表面的位置是由 CSS 定义的,但是其中的任何动画都是由 JavaScript 控制的。

  • CSS 3D 变换是 CSS 变换模块的一部分,不是动画。CSS 转换用于操纵 HTML 元素的视觉透视。这些变换可以被动画化,但是 CSS 3D 变换(在第九章中讨论)本身并不是动画。

WebGL 不是 CSS 动画。WebGL 是一个 JavaScript 3D API,它操纵

元素中的绘图。

摘要

在这一章中,你已经学习了 CSS 是如何被开发和标准化的,以及 W3C 在这个过程中的角色。初学 web 开发的人有时会将 W3C 视为一种良性的霸主,从高处制定标准;事实是,该组织及其各种工作组实际上是浏览器供应商创造的创新的集成者和标准化者。

虽然它们仍处于试验状态,但新的 CSS 属性在如何实现方面仍有待开发。为此,特定于每个浏览器的供应商前缀用于区分浏览器制造商对新 CSS 属性的解释。只有当 W3C 对属性进行了标准化,并且软件中内置了支持时,浏览器才会解释非前缀版本。

虽然 CSS3 动画、过渡和变换相对于 Flash 和 JavaScript 的传统 web 动画解决方案有许多显著的优势,但它们相对较新,限制了它们只能用于相当新的浏览器版本,尤其是在 Internet Explorer 和 Opera 的情况下。在开发过程中考虑回退技术是很重要的,这样使用旧浏览器或依赖屏幕阅读器等辅助设备的用户就不会错过您的站点内容。(同样重要的是将这些问题传达给客户和其他 web 开发人员,当他们试图谈论 web 动画时,可能会经常从外围或不相关的技术(如 HTML5)中进行选择。)

在下一章,我将介绍 CSS 转换的语法以及如何创建 CSS 转换,这是最简单的 CSS3 动画形式。虽然会有一点数学,我们将通过比较 CSS3 动画和真实世界的运动示例,包括迪士尼采用的经典动画技术,来丰富这一点。

二、CSS3 变换和过渡

虽然 CSS 动画可以用来改变 HTML 元素的几乎每一个方面(除了上一章列出的属性),但操纵网页表示的一些最强大的方法存在于 CSS Transforms 和 Transitions 模块中,这在 CSS3 中是全新的。

CSS 转换是最简单的动画形式:两种状态之间的移动。一旦你掌握了本章中描述的过渡的基本语法,你将能够将简单、有效的动画应用到图像(在第三章中描述)和用户界面元素(在第四章中描述),然后开始创建更复杂的关键帧动画(在第五章和更远的地方描述)。

CSS 变换

有四个主要的 CSS 翻译函数:translaterotatescaleskew。这些功能被组合在matrix转换功能中。您将把这些转换应用到一个标准的 web 页面布局中,这个页面布局是一个浮动在文本段落旁边的图像,如清单 2-1 所示。

清单 2-1 。 HTML5 代码为浮动图像

<!DOCTYPE html>
<html>
<head>
<title > Simple CSS3 Transformation</title>
</head>
<body>
<p> < img src = "dudley-storey-statuette.jpg" alt = "Student-made statuette of Dudley Storey" style = "width: 300px; height: 300px; float: left; margin: 0 2em 1.4em 0;" > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eu mi tellus. Vestibulum tortor erat, facilisis in auctor semper, pharetra quis mi...</p>
</body>
</html>

清单 2-1 中所示的代码将产生图 2-1 所示的布局。

9781430247227_Fig02-01.jpg

图 2-1。浮动有段落文本的图像

有了这个基础页面,就可以开始对图像元素应用变换了。

旋转

首先,你将通过旋转来变换图像(见清单 2-2 )。CSS3 旋转变换的值可以用度、梯度、转角或弧度来指定,使用正或负浮点值来创建顺时针或逆时针旋转。您必须包含供应商前缀以涵盖所有浏览器。

清单 2-2 。 内嵌 CSS 旋转图像

<img src = "dudley-storey-statuette.jpg" alt = "Statuette of Dudley Storey" style = "width: 300px; height: 300px; float: left; margin: 0 2em 1.4em 0; -moz-transform: rotate(7.5deg); -ms-transform: rotate(7.5deg); -o-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg); transform: rotate(7.5deg); ">

清单 2-2 中代码的结果如图图 2-2 所示。

9781430247227_Fig02-02.jpg

图 2-2。带有 CSS 旋转变换的浮动图像

虽然测量旋转角度是编写 CSS 转换时最常用的方法,但 CSS3 允许各种单位,如表 2-1 所示:

表 2-1。**CSS 角度数据类型可能的单位制

Table2.1.jpg

使用rotate : 浮动图像时,有一些事情需要注意

  • 页面上的其他 HTML 内容不受变换的影响:段落的布局不会随着图像的旋转而改变;进一步旋转图像会使其与文本重叠。(CSS 区域模块支持对变换做出反应的内容)。
  • 文档对象模型(DOM) 同样不受影响;转换后的元素(如offsetWidth)的属性值也将保持不变。
  • CSS 转换本质上在受影响的元素上强加了一种相对定位的状态;元素使用的原始空间将被保留。
  • 如果overflow属性的值是scrollauto,滚动条将根据需要出现,使您能够查看在可见区域之外转换的内容。
  • 旋转从元素的计算的中心开始,即transform-origin
  • 应用于元素的其他 CSS 外观规则,如box-shadow,在转换之前应用,因此它们将随效果一起旋转。
  • 将图像旋转 180 度不会翻转或镜像图像;这可以通过使用本章稍后讨论的scale变换或第九章讨论的 3D 旋转来实现。
  • 你可以旋转任何你想要的 HTML 内容,但是从设计的角度来看,不建议你旋转文本:这样做会降低可读性,并且会给你的读者带来痛苦。
  • 测量单位需要存在,即使旋转量为 0。在大多数 CSS 测量中,0 对于任何单位都是 0,(即width: 0作为width: 0px的替代)。)但旋转到 0°时,必须指定transform: rotate(0deg)transform: rotate(0)不起作用。

正如您所看到的,由于需要包含供应商前缀,转换的内联样式可能会很长。更常见的是单独创建转换,如嵌入或链接样式表中的classid(见清单 2-3 )。

清单 2-3 。 用于转换图像的嵌入式 CSS 样式表

<!DOCTYPE html>
<html>
<head>
<title > Simple CSS3 Transformation</title>
<style>
img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
}
</style>
</head>
<body>
<p > <img src = "dudley-storey-statuette.jpg" alt = "Statuette of Dudley Storey" style = "margin: 0 2em 1.4em 0; class = "tilt" > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eu mi tellus. Vestibulum tortor erat, facilisis in auctor semper, pharetra quis mi...</p>
</body>
</html>

要旋转图像,就像它被钉在右上角一样,你必须将元素的transform-origin移动到那个位置,如清单 2-4 中的所示。

清单 2-4 。 从一个角落旋转一个图像

img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform-origin: right top;
-o-transform-origin: right top; -ms-transform-origin: right top;
-webkit-transform-origin: right top; transform-origin: right top;
-moz-transform: rotate(−10deg); -o-transform: rotate(−10deg);
-ms-transform: rotate(−10deg); -webkit-transform: rotate(−10deg);
transform: rotate(−10deg);
}

清单 2-4 中的代码将产生如图图 2-3 所示的结果;注意,我不得不稍微改变图像的内嵌样式,为右边的空白提供更多的空间,以补偿图像的新角度。

9781430247227_Fig02-03.jpg

图 2-3。带有段落文本的旋转浮动图像

transform-origin取值的方式与background-position和其他组合水平和垂直偏移的属性相同。这些值被指定为原点的水平位置,后跟相对于元素本身的垂直位置这些值可以指定为关键字(topcenterbottomleftright)、数字或两者的组合。它们也可以在元素本身的区域之外(例如,在元素的上方或下方创建一个变换原点轴,如第三章中的“card fan”图像库示例所示)。

Webkit CSS3 转换锯齿问题

Chrome 和 Safari 的早期版本(直到版本 5.1)包含一个渲染 bug:当转换一些元素时,浏览器不会对旋转或倾斜的 HTML 内容的边缘进行反锯齿,从而导致图像边缘出现所谓的“锯齿”或“阶梯”,如图 2-4 所示。

9781430247227_Fig02-04.jpg

图 2-4。缩放图像,显示使用 CSS 变换旋转的图像边缘的锯齿

有多种方法可以解决这个问题:

  • 在元素周围应用 1 像素的白色边框。
  • webkit-backface-visibility: hidden;应用到元素。
  • 向元素添加另一个转换,比如-webkit-transform: rotate(−10deg) translateZ(0);

然而,没有一种技术能在所有情况下都最好地解决呈现错误;每种技术的有效性取决于所呈现的元素的上下文。

标度

当应用于图像时,scale变换有点奇怪:考虑到改变图像的heightwidth会有几乎相同的视觉效果,它可能看起来没什么用。不同之处在于,scale可以应用于任何 HTML 元素的:改变段落的width会重排文本内容,但改变其scale会使文本物理上变大或变小。

scale的值是一个乘数:scale(2)应用于一个元素将使它看起来两倍宽和两倍高(换句话说,是正常大小的四倍),而scale (.5)将产生一个原始大小四分之一的图像。scale将在所有方向上均等地变换元素。您也可以将scale应用于顺序方向:X(水平)、Y(垂直)和 Z(深度)。

使用 scaleX 翻转图像

您可以使用scale CSS 转换来有效地镜像 HTML 元素(通常是图像,尽管原则上这种技术可以应用于任何元素)。如果scale1开始,如图 2-5 左侧所示,当您降低scale的值时,受影响的元素将变小,直到您达到 0,此时图像消失。如果将该值推入负值区域,图像将再次开始增长,但会出现水平翻转,如图 2-5 右侧所示。

9781430247227_Fig02-05.jpg

图 2-5。使用 scaleX()的小负值的影响

您可以使用scale快速翻转页面上的图像,而不是通过 Adobe PhotoShop 等应用处理它来生成新的副本。清单 2-5 展示了如何应用变换来反转亚伯拉罕·林肯的图像。

清单 2-5 。 使用内嵌变换样式翻转图像

<img src="lincoln.jpg" alt="Abraham Lincoln, 1863" style="width: 389px; height: 480px;
-moz-transform: scaleX(−1); -o-transform: scaleX(−1);  -ms-transform: scaleX(−1);
-webkit-transform: scaleX(−1); transform: scaleX(−1);">

图 2-6 显示了清单 2-5 中代码的结果。

9781430247227_Fig02-06a.jpg 9781430247227_Fig02-06b.jpg

图 2-6。亚伯拉罕·林肯的原始照片(左)使用 CSS3 缩放变换(右)翻转

使用像这样的 CSS 技术,您可以动态调整图像,而不必返回 PhotoShop 进行更改,然后保存文件并上传到网站,也不必修改任何 HTML 代码。

翻译

scale一样,translate修改器起初看起来可能有点多余:它使用相同的坐标系(视觉上,产生相同的结果)将topleftbottomright属性应用于相对定位的元素。然而,正如你将看到的,translate可以使 HTML 内容更容易动画化。

translate(x,y)使用正值或负值在水平和垂直方向移动元素。translateX()在水平面内移动元素,translateY()在垂直方向上移动元素。

例如,如果你想将图 2-4 中显示的小雕像图像向上4em并向右移动50px,你可以使用清单 2-6 中显示的代码。

清单 2-6 。 用于翻译图片的 CSS 代码

img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform: translate(50px, -4em); -o-transform: translate(50px, -4em);
-ms-transform: translate(50px, -4em); -webkit-transform: translate(50px, -4em);
transform: translate(50px, -4em);
}

歪斜

skew应用到一个元素会水平或垂直地“剪切”它,这对于赋予一个元素额外的速度或运动感很有用。想象一下,拿一个矩形的对边(例如,上边和下边,或者左边和右边)向不同的方向拉,同时确保它们保持平行。

skew输入的值指的是其他侧将被设置的角度。例如,将图像向右“倾斜”是一种skewX变换。transform: skewX(21deg)将意味着图像的左右边缘将被设置为与垂直方向成 21 度(参见清单 2-7 )。将图像向左倾斜仍然使用skewX,但是使用负值:例如:skewX(−21deg),将设置相同的边缘从垂直方向负 21 度(即向左)。skewY将元素框的左侧右侧上下移动。

清单 2-7 。 倾斜图像的 CSS 代码

img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform: skewX(21deg); -o-transform: skewX(21deg);
-ms-transform: skewX(21deg); -webkit-transform: skewX(21deg);
transform: skewX(21deg);
}

你可以在图 2-7 中看到列表 2-7 的结果。

9781430247227_Fig02-07.jpg

图 2-7。倾斜 CSS 的矩形元素

在相应方向上平移元素时,水平和垂直倾斜与适当值的组合可以提供元素形成一个盒子的一边的印象,如清单 2-8 所示。

清单 2-8 。 CSS 代码将一幅图像转换成一个等角长方体的一边

img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform: skewY(30deg); -o-transform: skewY(30deg);
-ms-transform: skewY(30deg);  -webkit-transform skewY(30deg);
transform: skewY(30deg);
}

将单独的变换组合在一起(例如,旋转和平移)可以为 CSS 提供更多的功能,并为动画提供更多的可能性。

组合变换

可以通过以下两种方式之一合并元素的转换:作为转换属性的空格分隔值,或作为矩阵属性的值。

要将转换合并为一个transform属性的空格分隔值,使用清单 2-9 中的代码。

清单 2-9 。 单个 CSS 声明中的多次变换

img.tilt { width: 300px; height: 300px; float: left;
-moz-transform: translate(50px, -4em) rotate(15deg);
-webkit-transform: translate(50px, -4em) rotate(15deg);
-o-transform: translate(50px, -4em) rotate(15deg);
-ms-transform: translate(50px, -4em) rotate(15deg);
transform: translate(50px, -4em) rotate(15deg); }

将转换合并为一个matrix属性的值的过程要复杂得多。矩阵变换稍微超出了本书的范围;使用工具生成代码是最简单的。Useragentman 矩阵构造集(www.useragentman.com/matrix/)和 CSS3 变换矩阵计算器(www.leeourand.com/test/transform/test/transform.html)提供了两种方法。矩阵变换的解释可以在 CSS Matrix Transform for The mathematical Challenged(www.useragentman.com/blog/2011/01/07/css3-matrix-transform-for-the-mathematically-challenged/)和 Opera Web Developer site (http://dev.opera.com/articles/view/understanding-the-css-transforms-matrix).找到,虽然它们的优点是更短和更有效,但是矩阵变换不是人类可读的,所以我不会在本书的例子中使用它们。

image 注意编写单独的转换将而不是创建一个组合的转换。

img.tilt { width: 300px; height: 300px; float: left;
transform: translate(50px, -4em);
transform: rotate(15deg);
-webkit-transform: translate(50px, -4em);
-webkit-transform: rotate(15deg); }

使用上面的 CSS,浏览器将遵循最后一行适用的代码;也就是说,图像将被旋转,但不会被平移。

CSS 过渡

CSS 转换就是:从一种视觉状态到另一种视觉状态的转换,通常是由一些用户事件引发的,比如鼠标悬停在一个元素上。换句话说,转换是点对点的。如果你需要在多个状态和另一个状态之间制作动画,你会发现 CSS 关键帧更适合这项工作。(CSS 关键帧将在第五章中讨论。)

注意,对于本章中的例子,我将使用:hover来启动转换,但是从技术上来说对元素属性值的任何修改都会触发该属性的转换。

让我们回到第一个例子,为页面上的图像创建一个简单的旋转过渡。当用户将鼠标放在图像上时,您希望将元素旋转 7.5 度。你可以通过在.tilt选择器中添加一个:hover伪类来做到这一点(:hover可以应用于每个元素,而不仅仅是链接),如清单 2-10 所示。

清单 2-10 。上的 CSS 变换悬停,无过渡

<style>
img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
}
</style>

清单 2-10 中显示的代码可以工作,但是如果你试着在浏览器中查看页面,你会发现鼠标经过时没有动画,只有一个状态和另一个状态之间的瞬间切换。您将通过使用transition属性在这些状态之间创建一个动画(参见清单 2-11 )。

清单 2-11 。 使用过渡平滑 CSS 变换

img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
-moz-transition: 2s all; -webkit-transition: 2s all;
-o-transition: 2s all; transition: 2s all;
}

在清单 2-11 中显示的代码要成功得多:当你将鼠标放在图像上时,你会看到它现在平滑地旋转到新的位置。用多个供应商前缀重复的语法也很容易理解。元素旋转超过两秒钟,在转换过程中它的所有属性都可以改变。注意,值的顺序无关紧要:您可以使用2s allall 2s

如果你在包含几分之一秒的时间段内制作元素动画,你可以将时间段指定为以秒为单位的浮点值,或者以毫秒(千分之一秒)为单位,如清单 2-12 所示。

清单 2-12 。 一个以秒为单位的 CSS 转场

img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
-moz-transition: 2.35s all; -webkit-transition: 2.35s all;
-o-transition: 2.35s all; transition: 2.35s all;
}

这也可以用清单 2-13 中的来表示。

清单 2-13 。?? 一个以毫秒为单位的 CSS 转场

img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
-moz-transition: 2350ms all;
-webkit-transition: 2350ms all; -o-transition: 2350ms all;
transition: 2350ms all;
}

虽然以毫秒为单位的动画计时允许更高的精度,但是上面的两个声明达到了相同的结果——使用毫秒并不能创建更平滑的动画序列。很少有动画需要精确到千分之一秒,以毫秒为单位指定时间通常需要更多的输入,所以我坚持使用更熟悉的秒格式(例如,即使值小于一秒:transition: .35s all)。你应该使用你觉得更舒服的系统。

image 注意如果你已经用 JavaScript 制作了动画,注意这里的区别:CSS3 可以使用秒毫秒的浮点值来计时动画。JavaScript 专门使用毫秒,尽管许多用于创建动画的 JavaScript 框架可以使用以秒为单位的时间间隔。

还有一点需要改进。您会注意到,旋转元素后,将鼠标从图像上移开会立即将它恢复到初始状态。虽然这可能是您在某些情况下为网页元素寻求的视觉效果,但在大多数情况下,最好是显示元素返回到其初始方向,就像它到达其旋转状态一样平滑。

解决方案有点违反直觉:将 CSS 代码的transition部分从:hover声明移到图像的默认状态,只保留:hover声明上的transform(参见清单 2-14 )。

清单 2-14 。 创建与默认状态的平滑过渡

<style>
img.tilt {
width: 300px; height: 300px; float: left;
-moz-transition: 2s all; -webkit-transition: 2s all;
-o-transition: 2s all; transition: 2s all;
}
img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
}
</style>

想法很简单:将transition属性放在类声明中意味着任何从和返回到状态的转换都是有效的。前面的例子将转换放在了:hover声明上,这意味着它只在鼠标悬停时有效,在返回正常状态时无效。

您还会注意到,如果在图像区域来回移动鼠标,过渡会被打断;它的运动将平稳地逆转。您可以通过仅指定转换时间来进一步简化代码(参见清单 2-15 )。

清单 2-15 。CSS 变换中的定时旋转

img.tilt {
width: 300px; height: 300px; float: left;
-moz-transition: 2s;
-webkit-transition: 2s; -o-transition: 2s;
transition: 2s; }
img.tilt:hover {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
}

正如你所看到的,使用 CSS3 转场创建一个平滑简单的动画是很容易的。您可以修改 CSS 属性提供访问的元素外观的几乎每个方面并制作动画。到目前为止,我向您展示的转换一次只改变了元素的一个方面,并且总是以相同的方式进行。要创建更丰富的动画,您可以组合同一元素在不同时间和速度发生的多个属性转换。

延迟和组合过渡效果

转换事件可以通过添加一个transition-delay来延迟,或者作为一个单独的属性,或者附加到transform的值上:

-moz-transition: 2s 4s;
-webkit-transition: 2s 4s; -o-transition: 2s 4s; transition: 2s 4s;

请注意,延迟在动画开始时以及元素反转到其起始点时生效。光标停留在图像上四秒钟后,动画才会开始;一旦完全旋转,该元素将停留在原位四秒钟,然后返回到其默认方向。(另请注意,直到鼠标在图像上停留至少四秒钟,动画才会开始)。

你可以通过将多个 CSS 属性添加到:hover状态来同时激活它们(见清单 2-16 )。

清单 2-16 。?? 几个 CSS 属性同时过渡

<style>
img.tilt {
width: 300px; height: 300px; float: left;
-moz-transition: 2s;
-ms-transition: 2s;
-o-transition: 2s;
-webkit-transition: 2s;
transition: 2s;
}
img.tilt:hover {
-moz-transform: rotate(15deg);
-o-transform: rotate(15deg); -ms-transform: rotate(15deg);
-webkit-transform: rotate(15deg); transform: rotate(15deg);
opacity: .3;
}
</style>

属性可以在动画中被赋予单独的时间,方法是将transition-duration声明为具有逗号分隔值的单独属性。假设你想在悬停时将图像向右移动,同时淡出,但是淡出时间是移动时间的一半(见清单 2-17 )。

清单 2-17 。 多个属性的 CSS3 转换,每个属性有不同的计时

<style>
img.tilt {
width: 300px; height: 300px; float: left; position: relative;
-moz-transition-property: opacity, left;
-o-transition-property: opacity, left;
-webkit-transition-property: opacity, left;
transition-property: opacity, left;
-moz-transition-duration: 2s, 4s;
-o-transition-duration: 2s, 4s;
-webkit-transition-duration: 2s, 4s;
transition-duration: 2s, 4s;
}
img.tilt:hover {
opacity: .2; left: 60px;
}
</style>

我添加了position: relative,以便能够通过改变其left的值来移动元素,并通过清楚地声明要动画的属性来提高动画的效率。(显然,你不必为所有浏览器都支持的属性加上前缀,比如opacity。)您会注意到,在某些浏览器中,从左到右的动画可能不是特别流畅。让我们将动画属性改为translate,如清单 2-18 所示。

清单 2-18 。 一 CSS3 翻译过渡

<style>
img.tilt {
width: 300px; height: 300px; float: left;
-moz-transition-property: opacity, translateX;-o-transition-property: opacity, translateX;
-webkit-transition-property: opacity, translateX;
transition-property: opacity, translateX;
-moz-transition-duration: 2s, 4s;
-o-transition-duration: 2s, 4s;
-webkit-transition-duration: 2s, 4s;
transition-duration: 2s, 4s;
}
img.tilt:hover {
opacity: .2;
-webkit-transform: translateX(60px);
-moz-transform: translateX(60px); -ms-transform: translateX(60px);
-o-transform: translateX(60px); transform: translateX(60px);
}
</style>

你可能会发现运动现在更顺畅了;对于通过操纵absoluterelative定位来动画化 HTML 元素的移动来说,translate是一个很好的选择。

介绍缓动功能

请仔细观察您到目前为止创建的动画中鼠标悬停时图像的移动:它有一些特殊之处(延长动画的时间值可能有助于使其更加清晰)。图像的运动不是机械的,而是有机的:从默认位置开始,图像随着旋转而加速,在一段时间内达到恒定速度,然后在静止之前减速。

在动画中,这种运动被称为缓入/缓出。它是日常世界中物体的运动。例如,没有一辆车,无论多么强大,可以达到 0-60 秒的速度记录。每一个运动的物体都加速到一定的速度;在其行程结束时(除了极端情况,如汽车以最高速度撞上砖墙),物体将在停止前减速。

在 CSS3 动画中,缓和转场是默认的;没有必要声明你正在使用它们。如果你想让动画更有“机械”感,你可以从指定一个linear过渡开始(见清单 2-19 )。

清单 2-19 。 CSS 为线性旋转过渡

<style>
img.tilt {
width: 300px; height: 300px; float: left;
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
-moz-transition: 2s transform linear;
webkit-transition: 2s transform linear; -o-transition: 2s transform linear;
transition: 2s transform linear;
}
</style>

你会发现鼠标悬停时图像的运动更加机械。

过渡定时功能和贝塞尔曲线

linearease只是被称为计时函数 的两种形式,即描述一个物体以直线从 A 到达 B 的方式。这些定时函数可以用一种称为贝塞尔曲线的数学表达式来表示。

例如,如果你绘制了一个元素在线性条件下从 0 度到 15 度的转换过程中的运动,将时间分配给水平轴,将图像的角度分配给垂直轴,则线性动画的图形将看起来像图 2-8 。随着时间的推移,旋转的角度随着时间的流逝而增加,从而产生了恒定的运动速度。

9781430247227_Fig02-08.jpg

图 2-8。线性动画图形:x 轴为时间,y 轴为距离/角度。注意这种直接关系

从声明中删除关键字linear会使动画返回到自然的放松状态,当绘制在相同的轴上时,看起来更像图 2-9。

9781430247227_Fig02-09.jpg

图 2-9。缓时功能:x 轴时间,y 轴距离

正如你所看到的,旋转的角度在放松的动画的第一瞬间变化很慢;在过渡的中间,变化率显著增加,达到一个“极限速度”,然后减速,直到序列到达其结尾。

有几个关键字可用作普通过渡运动的快捷方式(见表 2-2 )。

表 2-2。常用三次贝塞尔计时函数的关键字替代方法

关键字 图表 三次贝塞尔曲线 描述
linear 9781430247227_unFig02-01.jpg 0, 0, 1, 1 瞬间启动和停止;在整个运动范围内速度恒定。
ease 9781430247227_unFig02-02.jpg 0.25, 0.1, 0.25, 1 启动迅速,加速迅速;缓慢过渡到终点停止。
ease-in 9781430247227_unFig02-03.jpg 0.42, 0, 1, 1 缓慢启动,加速爬升至突然停止。
ease-out 9781430247227_unFig02-04.jpg 0, 0, 0.58, 1 动画瞬间开始,运动在接近尾声时变慢。
ease-in-out 9781430247227_unFig02-05.jpg 0.42, 0, 0.58, 1 在动画过程中元素被缓和地放入和放出:一个缓慢平滑的开始,在过渡中间短暂地达到一个恒定的速度,然后减速到停止。

正如您所看到的,所有缓动曲线都有一个三次贝塞尔表达式形式的数学等价物:一个数字对,其中每组浮点数字描述坐标空间中的一个点,形成一条创建缓和曲线的线。(注意,不能移动或定义曲线任一端的终止点)。

对于渐入渐出曲线,这些点看起来像图 2-10 。

9781430247227_Fig02-10.jpg

图 2-10。贝塞尔曲线渐出动画效果

用 CSS 表示,图 2-10 是这样的:

transition-timing-function: cubic-bezier(0.42, 0, 0.58, 1);

理解三次贝塞尔函数允许你为你的 CSS 动画创建几乎无限多种自定义缓动曲线。甚至可以给这些点负值或大于 1 的值来创建极端的缓和曲线,这可以在图 2-11 中看到。

9781430247227_Fig02-11.jpg

图 2-11。使用负值和大于 1 的值的贝塞尔曲线,创建“推拉”动画效果

在 CSS 中,图 2-11 是这样的:

transition: all 2000ms cubic-bezier(0.280, -0.315, 0.685, 1.390);

使用这些值创建带有“弹簧”或“弹跳”的动画,也称为推拉动画。我将在第四章中探索这些动画的用途。

image 提示停止(http://matthewlein.com/ceaser/)和三次(http://cssglue.com/cubic)是从图形操作的三次贝塞尔曲线生成 CSS 缓和代码的优秀工具。两者都包括一个测试服务,允许你看到变化的可视化结果。彼得·贝弗卢的资源(http://peter.sh/experiments/css3-transition-timing-functions/)也很有用,尤其是在可视化阶跃函数方面。

分步制作动画

也可以分步制作元素动画,而不是平滑过渡。(想象一下时钟上秒针的突然递增运动)。这些是通过steps函数和变量创建的。在这里,我将通过只显示标准属性、Firefox 和 Webkit 的 CSS3 代码来节省代码。

假设你有一个h1想要在鼠标悬停时制作动画(见清单 2-20 )。

清单 2-20 。中的过渡序列为一个标题的步骤

<style>
h1 {
 font-family: Futura; "Arial Black", Arial, sans-serif;
 text-align: center;
 }
h1:hover {
 -moz-transition: 4s all steps(3, end);
 -webkit-transition: 4s all steps(3, end);
 transition: 4s all steps(3, end);
 -moz-transform: translateX(400px);
 -webkit-transform: translateX(400px);
 transform: translateX(400px);
 }
</style>

清单 2-20 中的代码将在两秒钟的延迟后,在四秒钟内连续三次“跳跃”动画化所有的h1元素,每一步之间没有可见的运动。其他变化也是可能的,如表 2-3 所示。

表 2-3。CSS3 过渡的步长值

功能 图表 描述
steps(3) 9781430247227_unFig02-06.jpg x 步数的动画(图中显示了steps(3))。开始时暂停。相当于steps(x, end)
steps(3), end 9781430247227_unFig02-07.jpg 元素仍在开始处,在结尾处暂停。
steps(x), start 9781430247227_unFig02-08.jpg 动画即时开始,元素在结束时暂停。

在 CSS3 过渡中增加对移动设备的支持

到目前为止,您只在:hover上激活了变换。这是最常见的伪类,但不是唯一的,你会在第三章中看到。

:hover可能会给安装在移动设备上的浏览器带来两个问题:

  • 用户的指尖可能会模糊动画,尤其是在较小的屏幕上。
  • 一些设备不支持:hover(严格来说,这是有意义的,因为当前所有的移动平台都依赖于直接触摸)。相反,它们涵盖了与:focus.的简单用户交互

如果您选择使用:hover,您应该通过使用一个分组选择器来覆盖只有:focus的移动平台的可能性,如下面的代码所示:

img.tilt:hover, img.tilt:focus {
-moz-transform: rotate(7.5deg); -o-transform: rotate(7.5deg);
-ms-transform: rotate(7.5deg); -webkit-transform: rotate(7.5deg);
transform: rotate(7.5deg);
}

摘要

在本章中,你已经学习了 CSS3 变换 : scalerotateskewtranslate的语法,包括如何翻转图像和组合变换。我还讲述了最简单的动画形式 CSS3 转场的代码,向您展示了如何创建转场,如何修改它们的定时和延迟,以及启动它们的两种常用方法。

虽然也可以使用steps功能和关键字快捷键,但过渡的移动和定时通常是通过贝塞尔曲线控制的。

在下一章,我们将探索如何将这些动画技术应用于图像元素。

三、图像的 CSS3 过渡

CSS3 转场在网页上最常见的用途是,首先,为用户界面(UI)元素生成视觉效果(将在下一章讨论),其次,为图像创建简短的动画效果。在这一章中,你将使用转场模块的语法通过动画来增强图像及其标题。这些技术展示了在视觉上增强网页的简单方法,使图像内容和相关信息更具交互性,同时最小化屏幕“空间”:这是移动 web 开发时代的一个重要考虑因素。

简单图像交叉渐变效果

你将处理的第一个过渡将演示在后续练习中使用的许多基本概念:将大小完全相同的图像放置在彼此之上,并在:hover启动事件(参见图 3-1 )。

9781430247227_Fig03-01.jpg

图 3-1。使用过渡不透明度的交叉淡入淡出效果

有几种可能的方法可以达到图 3-1 所示的效果:

  • 选项 1 :将第一张图片指定为容器元素的 CSS background,第二张图片在元素本身内部。
  • 选项 2 :创建一个带有position: relative的容器元素来保存两个图像,第二个图像带有position: absolute
  • 选项 3 :将两幅图像都指定为背景,并在它们之间进行过渡。

这三种方法各有利弊。第一种和第三种方法可能创建速度更快,响应速度更快,但是不太容易使用。使用第一种方法还意味着对图像的任何更改都必须在不同的地方进行,因为一个图像将只存在于 CSS 中,而另一个图像将作为 HTML 元素存在。第二个选项可能需要更多的代码,但好处是将两张图片都保存为<img >元素,因此更容易访问。在撰写本文时,第三个选项在技术上超出了规范范围,但可能是最容易使用的。

我将使用由 Ton Rulkens (www.flickr.com/photos/47108884@N07/4595559479/)和 Peter Shanks (www.flickr.com/photos/botheredbybees/1954163161/)提供的照片来演示所有这三种方法,这些照片是经许可使用的。

两幅图像的大小必须完全相同。有几种方法可以实现这一点:

  • 在 Adobe PhotoShop 等应用中将图像裁剪为相同的尺寸(这是最明显的解决方案)。
  • 您可以通过 CSS 或 HTML 属性修改图像的widthheight,尽管这通常会导致视觉失真。
  • 您可以在div上设置一个widthheight,并使用overflow:hidden来修剪图像中落在该区域之外的部分。
  • 如果两个图像都被表示为代码中的元素,那么可以对每个图像使用相同的 CSS clip值。

选项 1:第一张图片作为 CSS 背景

这个选项的 HTML 非常简单,如清单 3-1 所示。

清单 3-1。 HTML 选项 1 创建两个分层图像

<div class=crossfade>
        <img src=jatropha-hybrid.jpg alt="Jatropha hybrid leaf">
</div>

image 注意本书中展示的 HTML5 代码样本是“缩小的”语法,以节省空间。元素仅在需要时闭合,属性值仅在包含空格时加引号。

清单 3-2 中显示的 CSS 也非常简单。

清单 3-2。 CSS 为 HTML 选项 1 创建交叉渐变效果

div.crossfade { background: url(leaf-veins.jpg); background-size: cover; }
div.crossfade, div.crossfade img  { width: 418px; height: 500px;  }
div.crossfade img { transition: 3s opacity ease-out; }
div.crossfade img:hover { opacity: 0; }

选项 2:两个图像都作为 HTML 元素

或者,您可以将两个图像作为单独的图片堆叠在一个容器中;HTML 如清单 3-3 中的所示。

清单 3-3。 HTML 选项 2 创建分层图片

<div class=crossfade>
        <img src=leaf-veins.jpg alt="Red-veined leaf">
        <img src=jatropha.jpg alt="Jatropha hybrid leaf">
</div>

与其通过将一个类附加到第二个图像来使 HTML 变得复杂,不如使用第 n 个子伪选择器来改变它,如清单 3-4 所示。

清单 3-4。 CSS 为 HTML 选项 2 创建交叉渐变效果

div.crossfade { position: relative; }
div.crossfade, div.crossfade img { width: 418px; height: 500px; }
div.crossfade img:nth-child(2) { position:absolute; left:0; top:0; transition: 3s opacity ease-out; }
div.crossfade img:nth-child(2):hover { opacity: 0; }

选项 3:两幅图像都作为背景

虽然最容易编码,但这个选项也是最大胆的:它超出了当前的规范(而且,在撰写本文时,仅在 Chrome 中受支持)。在这种情况下,包含的 div 完全没有内容,一切都是通过 CSS 实现的,如清单 3-5 所示。

清单 3-5。 CSS 创建图像交叉淡入淡出效果(选项 3)

div.crossfade { width: 418px; height: 500px; transition: 3s background-image ease-out;
background-image: url(leaf-veins.jpg); }
div.crossfade:hover { background-image: url(jatropha.jpg);  }

如果你愿意进一步推进你的代码,另一种方法是对 CSS4 cross-fade属性使用相同的空div,如清单 3-6 所示。

清单 3-6。【CSS4】交叉淡入淡出用于创建图像过渡

div.crossfade { width: 418px; height: 500px;
background-image: -webkit-cross-fade(url(jatropha.jpg), url(leaf-veins.jpg),0);
transition: 2s background-image linear; }
div.crossfade:hover { background-image: -webkit-cross-fade(url(jatropha.jpg), url(leaf-veins.jpg),100); }

顾名思义,cross-fade是一种更有效的方法,但目前实际应用有限;cross-fade不是通过过渡opacity来伪造溶解效果,而是用适当的算法来处理图像。

CSS4?你在说什么,威利斯?

随着 CSS3 在浏览器中成为主流,W3C 的注意力已经转移到 CSS 开发的下一个阶段,其中包括新的选择器以及图像和渐变的外观规则。浏览器支持(在撰写本文时)是有限的和试验性的,但正在增长。

与本节最相关的是 CSS4 图像值和替换的内容模块,您可以在http://dev.w3.org/csswg/css4-img/阅读其概述。还有一个用于背景和边框(http://dev.w3.org/csswg/css4-background/)以及文本(http://dev.w3.org/csswg/css4-text/)的模块。

几乎不可避免的是,在不久的将来,“CSS4”这个术语将会像今天的“CSS3”一样被广泛误解和误用,正如我在第一章中所讨论的。

用 CSS3 增强的简单图库

对于第二个例子,您将使用 HTML 创建一个图像缩略图图库,并使用 CSS3 过渡增强图库中大图像的显示(参见图 3-2 )。

9781430247227_Fig03-02.jpg

图 3-2。一个简单的图库

你至少需要三对图像。每一对将由一个缩略图和一个相同图像的全尺寸版本组成。大版可以是你希望的任何尺寸,只要合理;我建议缩略图的大小大约为 150 x 150 像素。为了保持文件组织的清晰,请遵循命名约定。例如,如果全尺寸图像是x,jpg,则将成对的缩略图命名为x_thumb.jpg,两者都存储在 images 文件夹中。

HTML 标记

你的目标是尽可能保持图库中使用的 HTML 简洁明了。为此,您将使用定义列表作为标记的基础。定义列表包含成对的元素:一个(定义术语)用于您的缩略图,另一个(定义声明)用于它匹配的大图像。

在相对于文件夹的标记中组装内容,页面的 HTML 看起来类似于清单 3-7 (使用前一个练习中的图片,以及 Paul Bica 的另一张照片(www.flickr.com/photos/dexxus/4137841698/)

清单 3-7 。 HTML5 为一个简单的图库

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title> CSS3 Gallery</title>
<style>
        body { background: #234; }
</style>
</head>
<body> 
  <dl id=gallery>
        <dt><img src=jatropha_thumb.jpg alt="Jatropha Leaf Thumbnail">
        <dd><img src=jatropha.jpg alt="Jatropha Leaf Large">
        <dt><img src=leaf-veins_thumb.jpg alt="Leaf Veins Thumbnail">
        <dd><img src=leaf-veins.jpg alt="Leaf Veins">
        <dt><img src=cascada_thumb.jpg alt="Cascada Thumbnail">
        <dd><img src=cascada.jpg alt="Cascada Large">
</dl> 
</body>
</html>

初始 CSS

这里使用的 CSS 应该是不言自明的:你正在定位定义列表relative,这样大的、绝对定位的图像是相对于列表而不是文档的主体来组织的。绝对定位大图像也意味着您可以将它们堆叠在完全相同的位置,并且文档的其余部分(包括缩略图)将表现得好像全尺寸图像根本不在那里一样。最后,用visibility: hidden隐藏大图。,并通过在带有相邻组合子的dt元素上使用:hover选择器再次显示它们,如清单 3-8 所示。

清单 3-8。 CSS 用于一个简单的图库

dl#gallery { position: relative; }
dl#gallery dt img { width: 150px; height: 150px; margin: 2.2em; }
dl#gallery dd { position: absolute; left: 200px; top: 2.2em; visibility: hidden; }
dl#gallery dt:hover + dd { visibility: visible; }

将鼠标移动到缩略图图像上,会立即显示定义列表中与之配对的大图像。但是,在将动画引入画廊之前,您需要解决一个 UI 问题。

改善画廊

到目前为止,您所做的工作是有效的,但是有点笨拙:您会注意到,将鼠标放在缩略图图像的右侧会使相关的大图像立即出现。您将通过几行 CSS 来解决这两个问题,从用visibility(不能动画)隐藏大图像改为用opacity(可以),同时与缩略图共享定义术语的大小,如清单 3-9 所示。

清单 3-9。 用转场增强图库的 CSS

dl#gallery dd { position: absolute; left: 200px; top: 2.2em; opacity: 0;
transition: .85s opacity linear; }
dl#gallery dt:hover + dd { opacity: 1; }

现在,当你将鼠标移动到缩略图上时,大图会平滑地淡入。

添加字幕

如果用户能够阅读图片说明,这将非常有帮助。在这种情况下,不需要添加任何额外的标签,只需要标题内容和 CSS。我将修改其中一个<dt ><dd >对作为例子,如清单 3-10 所示。

清单 3-10。 简单标题图片的 HTML 示例

<dt><img src=jatropha_thumb.jpg alt="Jatropha Leaf Thumbnail">
<dd><img src=jatropha.jpg alt="Jatropha Leaf Large"> A closeup photograph of a Jatropha Hybrid

你的 CSS 也必须做出相应的改变(见清单 3-11 )。

清单 3-11。 CSS 为简单的带标题的图片

dl#gallery dd { position: absolute; left: 200px; top: 2.2em; opacity: 0;
text-align: center; font-family: Futura, Arial, sans-serif; color: white;
transition: .85s opacity linear; }
dl#gallery dd img { display: block; margin: auto; padding-bottom: 1.2em; }

在这种情况下,你的说明会随着图片淡入。将标题与图像分开制作动画也很常见,这将在下一个练习中进行。

改变启动事件

虽然:hover用于启动图库中的大图像的淡入,但对于用户来说,点击缩略图似乎更自然。这里,您遇到了一个问题:在 CSS 中没有与 JavaScript onclick事件处理程序直接对等的东西。然而,在这种情况下有几个选择。

:活动

虽然它与链接紧密相关,但也可以使用:active伪类来启动转换,如清单 3-12 所示。

清单 3-12。 CSS 对鼠标按下产生效果

dl#gallery dt:active + dd { opacity: 1; }

您将立即看到这种方法的主要缺点:只有在缩略图上按住鼠标按钮时,大图像才会出现。

:目标

在这种情况下,使用:target可能是最有效的伪选择器,尽管它确实需要在标记中添加一些内容。:target源自使用传统的id值的“锚”,检测链接到这些 id 的元素的点击。

您的 HTML 更改为清单 3-13 中显示的内容。

清单 3-13。 HTML 为一个图库配:target

<dl id=gallery>
<dt><a href=#jatropha><img src=jatropha_thumb.jpg alt="Jatropha Leaf Thumbnail"></a>
<dd id=jatropha><img src=jatropha.jpg alt="Jatropha Leaf Large"> 
A closeup photograph of a Jatropha Hybrid leaf
<dt><a href=#veins><img src=leaf-veins_thumb.jpg alt="Leaf Veins Thumbnail"></a>
<dd id=veins><img src=leaf-veins.jpg alt="Leaf Veins"> 
Closeup photgraph of leaf veins
<dt><a href=#cascada><img src=cascada_thumb.jpg alt="Cascada Thumbnail"></a>
<dd id=cascada><img src=cascada.jpg alt="Cascada Large"> 
Falls in Dundas Peak, Ontario, Canada
</dl>

在正常情况下,一个锚的链接会迫使页面滚动到id的位置,并有一个视觉跳转;这种情况下可以避免,因为dd元素绝对位于页面顶部附近。

只有一行 CSS 需要修改。您的:hover声明如清单 3-14 中的所示。

清单 3-14。 一个图库用 CSS:target

dd#jatropha:target, dd#veins:target, dd#cascada:target { opacity: 1; }

这种方法还具有修改 URL 的优点,这意味着通过使用带有附加 id 的链接,用户可以被引导到特定的图像。例如,www.yourdomain.com/gallery.html#cascada会自动调出图库中的最后一幅图像。

简单的弹出图像标题

也可以在鼠标悬停时显示图像的标题,可以在图库中显示,也可以作为用户界面的一部分。理想的标记要么是一个定义列表,如前一个例子,要么是一个<figure >和<figcaption>,这是你将在下一个例子中使用的元素,如图 3-3 和清单 3-15 所示。(我用的是布拉德利·戴维斯(www.flickr.com/photos/backpackphotography/244716694/)和沃尔夫冈·斯陶特(www.flickr.com/photos/wolfgangstaudt/)的照片。如果您决定使用自己的图像,请确保它们的大小相似。)

9781430247227_Fig03-03.jpg

图 3-3。动画图像字幕

在这种情况下,标题是图像的描述,但这种技术也可以用于网站的图形导航(见第四章)。

清单 3-15 。HTML5 图形和图形标题代码

<figure>
        <img src=devils-tower.jpg alt="A photo of Devil's Tower, inWyoming, USA">
        <figcaption> Devil's Tower, Wyoming, USA</figcaption>
</figure>
<figure style=left:550px>
        <img src=sunrise-point.jpg alt="A photo of Sunrise Point, Bryce National Park, Utah, USA">
        <figcaption> Bryce National Park, Utah, USA</figcaption>
</figure>

您将在 CSS 中做一些事情。首先,图像和它们周围的figure元素应该设置为相同的大小,并且并排浮动。您还将在用更多 CSS 隐藏标题之前对其进行样式化。

雷姆:不是乐队

传统上,网页上的字体是以像素、百分比或 ems 来确定大小的。后两种方法通常是首选方法,因为它们具有内在的可伸缩性。由于1em实际上是M字符的宽度,将段落文本放大 20%就像声明p选择器的font-size1.2em一样简单。使用em还可以随着字体大小的增加和减小,方便地按比例调整元素之间的间距。例如,您可以通过以em为单位测量图像的边距来设置图像及其周围文本之间的装订线,从而在正文和插图之间创建一种视觉关系。

在网页中使用em作为度量系统的一个问题是它很复杂,因为单位总是相对于父元素的字体大小来设置。将li元素的大小设置为1.2em是没问题的,直到你在其中嵌套了一个列表:内部 l i的内容将以1.4em的大小呈现。

rem (for root em )通过相对于根元素(即html元素)测量自身来解决这个问题。这意味着你可以在html选择器上声明一个单一的字体大小,并相对于它缩放一切,如清单 3-16 所示。

清单 3-16。 为文档调整 rem 字体大小

html { font-size: 62.5% }
body { font-size: 1.4rem; }
h1 { font-size: 2.4rem; }

这也很好地转换为像素:在上面的样式表中,页面上的正文文本大小相当于 14px,而h1元素呈现为 24 像素。

浏览器对 rem 的支持出奇的好:最近所有支持 CSS 转换的浏览器(Safari 5+,Chrome,Firefox 3.6+,IE9+,Opera 11.6+)也都支持rem单元)。

现在让我们来看看图表和标题的基本 CSS(见清单 3-17 )。

清单 3-17。 基本 CSS 为一个图和标题

figure { float: left; }
figure, figure img { width: 500px; height: 333px; }

figcaption {
font-family: Baskerville, "Baskerville Old Face", Garamond, "Times New Roman", serif;
font-style: italic; background: rgba(0,0,0,0.4);
font-size: 2rem; padding: 0.8rem; color: #fff;
}

在这个阶段,页面看起来将类似于图 3-4 。

9781430247227_Fig03-04.jpg

图 3-4。隐藏前带有定位字幕的图像

现在它们已经被样式化了,您将通过在 figure 元素上使用overflow: hidden来隐藏标题。同时,你需要定位标题。对于本例中的图像,从顶部向下放置标题可能看起来最好。有几种可能的方法来定位字幕。我将使用relative定位和一个稍微大于图片高度加上标题高度的bottom值(见清单 3-18 )。

image 提示在添加转场之前检查元素的重定位是否有效是个好主意。

清单 3-18。 CSS 隐藏并定位标题

figure { float: left; }
figure, figure img { width: 500px; height: 333px; overflow: hidden; }
figcaption {
font-family: Baskerville, Garamond, "Times New Roman", serif;
font-style: italic; background: rgba(0,0,0,0.4); font-size: 2rem;
padding: 0.8rem; color: #fff;  position: relative;  bottom: 400px;
}
figure:hover figcaption { bottom: 340px; }

最后,你将添加标题的过渡,如清单 3-19 所示。

清单 3-19。 CSS 到转场一个字幕

figcaption {
font-family: Baskerville, Garamond, "Times New Roman", serif;
font-style: italic; background: rgba(0,0,0,0.4);
font-size: 2rem; padding: 0.8rem; color: #fff;
position: relative;  bottom: 400px;
transition: 2s all; }

image 注意我已经通过使用描述性文件名和 alt 属性值来保持我们的图像的可访问性。这是非常重要的:永远记住,不是每个人都能够看到你的设计或与之互动。

图像牌叠和扇形显示

随着网页变得越来越复杂,它们变得越来越难以概括和说明。如果你创建了一个大的图库页面,很难只选择一张图片来激发访问者的兴趣。一个可能的解决方案是使用几个图像,显示在一个关键帧滑块画廊(如第五章所示)或一个交互式显示器中。在这种情况下,我会将几张照片明显地堆叠在一起,在鼠标悬停时显示它们,以产生更大的兴趣和对链接内容的理解(参见图 3-5 )。

9781430247227_Fig03-05.jpg

图 3-5。一种动画卡牌粉丝效果

同样,您将使用相同大小的图像来产生最佳效果,如清单 3-20 所示。

清单 3-20 。动画图像的 HTML】卡扇效果

<div id=cardfan>
        <img src=bike.jpg alt="A photograph of a bicycle parked on Italian street">
        <img src=florence.jpg alt="A photograph of bridge in Florence, Italy">
        <img src=roma.jpg alt="A photograph of a ruined aqueduct outside Rome">
</div>

您已经将图像包装在一个容器元素中,使它们更容易通过 CSS 引用和控制。div和它包含的图像大小相同。当样式化和堆叠里面的图像时,你也将使容器居中对齐页面(见清单 3-21 )。

清单 3-21 。 基本 CSS 为一卡一扇效果

#cardfan, #cardfan img { width: 640px; height: 480px; }
#cardfan { margin: 0 auto; }
#cardfan img { border: 32px solid #ffe;
box-shadow: 12px 12px 10px rgba(0, 0, 0, 0.2);
position: absolute; }

您希望当用户将鼠标悬停在图像上时,图像呈扇形展开;你可以通过使用:first-child:last-child伪类将堆栈中的第一个最后一个图像旋转 12 度来实现,如清单 3-22 所示。

清单 3-22 。 卡片叠中第一张和最后一张图片的旋转效果

#cardfan:hover img:first-child {
    transform: rotate(12deg);
}
#cardfan:hover img:last-child {
    transform: rotate(−12deg);
}

清单 3-22 中的代码将产生如图图 3-6 所示的图像。

9781430247227_Fig03-06.jpg

图 3-6。使用 CSS 变换围绕各自中心旋转的堆叠图像

如你所见,图像围绕其中心旋转。在这种情况下,您希望图像稍微成扇形,因此您需要将变换轴移动到图像的下方(参见清单 3-23 )。

清单 3-23 。偏移图像的变换原点

#cardfan img { border: 32px solid #ffe;
    box-shadow: 12px 12px 10px rgba(0, 0, 0, 0.2);
    position: absolute;
    transform-origin: center 600px;
}

清单 3-23 中的代码将产生如图图 3-7 所示的输出。

9781430247227_Fig03-07.jpg

图 3-7。围绕偏移原点旋转的堆叠图像,用十字光标高亮显示

现在你可以真正地将卡片展开,同时应用一个过渡,如清单 3-24 所示。(请注意,我已经更改了一些值来增加风扇效果。)

清单 3-24 。 全 CSS 为动画卡粉丝图库

#cardfan, #cardfan img { width: 640px; height: 480px;
transition: .6s transform ease-out;
}
#cardfan { margin: 0 auto; }
#cardfan img { border: 32px solid #ffe;
box-shadow: 12px 12px 10px rgba(0, 0, 0, 0.2);
position: absolute;
transform-origin: center 1200px;
}
div#cardfan:hover img:first-child {
    transform: rotate(24deg);
}
div#cardfan:hover img:last-child {
    transform: rotate(−24deg);
}

你也可以将图片链接到一个图库页面,如清单 3-25 所示。

清单 3-25 。 一联卡粉丝图库

<div id=cardfan>
 <a href=gallery.html>
 	<img src=bike.jpg alt="A photograph of a bicycle parked on Italian street">
 	<img src=florence.jpg alt="A photograph of bridge in Florence, Italy">
 	<img src=roma.jpg alt="A photograph of a ruined aqueduct outside Rome">
 </a>
</div>

如果您想旋转第一个和第二个图像,并保持顶部的照片不变,请更改以下选择器:

div#cardfan:hover img:last-child

div#cardfan:hover img:nth-child(2n)

你也可以稍微旋转图像的默认位置,让用户对将要发生的事情有所了解,如清单 3-26 所示。

清单 3-26 。 一个视觉上有暗示的卡迷图库

#cardfan img:first-child {
    transform: rotate(6deg);
}
#cardfan img:nth-child(2n) {
    transform: rotate(−6deg);
}

你也可以将照片单独链接到本章开头的图库示例(见清单 3-27 )。

清单 3-27 。

<div id=cardfan>
<a href="gallery.html#bike">
    <img src=bike.jpg alt="A photograph of a bicycle parked on Italian street">
</a>
<a href="gallery.html#florence">
    <img src=florence.jpg alt=="A photograph of bridge in Florence, Italy">
</a>
<a href="gallery.html#aqueduct">
    <img src=roma.jpg alt="A photograph of a ruined aqueduct outside Rome">
</a>
</div>

但是,如果您单独链接图像,您将需要更改您的 CSS,因为您的标记的组织已经发生了变化。你将通过它们的src属性的值来引用图像,而不是将它们作为子对象来引用(参见清单 3-28 )。

清单 3-28 。 一个卡片爱好者图库,图片被其 src 属性引用

#cardfan img[src="bike.jpg"] {
    transform: rotate(6deg);
}
#cardfan img[src="roma.jpg"] {
    transform: rotate(−6deg);
}
#cardfan:hover img[src="bike.jpg"] {
    transform: rotate(24deg);
}
#cardfan:hover img[src="roma.jpg"] {
    transform: rotate(−24deg);
}

注意清单 3-26 中的技术没有为你的图像创建和引用 id 值灵活:如果你因为任何原因改变了文件名,你将不得不相应地改变你的 CSS。

你也可以在鼠标悬停时将单个图像提升到前景(见清单 3-29 )。

清单 3-29 。 一个卡迷图库的图像提升到前台

img[src="bike.jpg"]:hover, img[src="florence.jpg"]:hover { z-index: 2; }

通过使用::before::after伪元素选择器来生成其他图像,您可以编写更少的标记(但稍微多一点 CSS)。(请注意,您不能在<img >标签上使用生成的内容,因为它们是替换元素的一种形式)。同样重要的是要注意,这种方法实际上扼杀了可访问性,因为大多数屏幕阅读器目前不访问生成的内容,JavaScript 也不能访问它。这里显示的技术是一种有趣的可能性,而不是作为一种网站中心内容的生产方法。

image 注意 替换的元素是 HTML 元素,有固有的宽度和高度,没有 CSS 的好处;也就是说,任何产生占位符的标记,其内容随后被外部资源替换。例如,当您使用<input type =text>时,文本框会以适合单行文本输入的大小出现。这并不意味着你不能应用 CSS 来调整它的大小,只是默认情况下浏览器用预定大小的元素替换了<input>标签的实例。<img>也是如此;如果没有 CSS,图像会以其自然的宽度和高度加载到页面上。

<br>, <img>, <video>, <iframe>, and <object>are all replaced elements, as are <input>, <button>, and <textrarea>.

最重要的是,在这个练习的上下文中,作为一般规则,生成的内容不能应用于替换的元素。也就是说,你不能在<img>或者上面列出的其他标签上使用::before或者::after。此外,不能转换内联元素,除非它们也是被替换的元素。

走这条路,你的 HTML 和 CSS 代码简化成你在清单 3-30 中看到的样子。

清单 3-30 。 HTML 和 CSS 代码为一张卡片生成粉丝效果图

<div id=cardfan>
        <img src=florence.jpg alt="A photograph of bridge in Florence, Italy">
</div>
#cardfan { position: relative; margin: 0 auto; }
#cardfan, #cardfan img, #cardfan img:before, #cardfan img:after {
    width: 640px; height: 480px;
}
#cardfan img, #cardfan:before, #cardfan:after {
    border: 32px solid #ffe;
    box-shadow: 12px 12px 10px rgba(0, 0, 0, 0.2);
    position: absolute;
    transform-origin: center 1200px;
}
div#cardfan::before { content: url(bike.jpg); }
#cardfan::after { content: url(roma.jpg); }
#cardfan::before, div#cardfan:after { position: absolute; left: 0; top: 0; }
#cardfan::before { transform: rotate(6deg); }
#cardfan::after { transform: rotate(−6deg);  }

清单 3-30 中的代码创造了同样的卡迷效果,可以说具有更强的适应性;要更改中心图像两侧的照片,只需修改 CSS,而无需修改标记。如前所述,这种方法也有明显的缺点。

你可以通过链接伪选择器来制作这些图像的动画,如清单 3-31 所示。

清单 3-31 。 CSS 代码动画生成内容

div#cardfan:hover::before {
    transform: rotate(24deg);
}
div#cardfan:hover::after {
    transform: rotate(−24deg);
}

image 为什么::before::after中的双冒号?CSS2 和 CSS2 之间对现有选择器的少数正式更改之一是 W3C 在生成的内容选择器中添加了另一个冒号,以便区分它们的不同性质。现代浏览器将会识别并支持:::前置到生成的内容选择器。在本书中,我使用了新的正式版本;为了更好地向后兼容旧的浏览器,您可能希望只使用一个冒号。

具有不同进入和退出效果的快板图像字幕

虽然从顶部或底部引入图像标题适用于短文本,但当涉及大量文本时,过渡会有点大且笨拙。如果标题文本很长,最好在悬停时“摆动”它。

你将使用与之前相同的方法:一张已知尺寸的图像(由美国宇航局提供),使用overflow: hidden隐藏标题,直到你在悬停时显示它(见图 3-8 )。

9781430247227_Fig03-08.jpg

图 3-8。快板字幕动画

图 3-8 所示的快板标题的 HTML 和 CSS 如清单 3-32 所示。

清单 3-32 。 代码创建一个快板标题

<figure class=clapperboard> 
  <img src=apollo-17.jpg alt="Photograph of astronaut on the Moon">
<figcaption>
<q>We leave as we came and, God willing, as we shall return, with peace and hope...</q> 
– Eugene Cernan, commander of Apollo 18, the last man on the moon.
</figcaption>
</figure>
figure.clapperboard { position: relative; }
figure.clapperboard figcaption { position: absolute; top: 0; left: 0; padding: 2rem; }
figure.clapperboard, figure.clapperboard figcaption { width:618px;height:515px; }
figure.clapperboard figcaption q { font-size: 2rem; display: block; margin-bottom: 2rem; }

你还没有隐藏标题,这使得它更容易定位:你需要将figcaption元素旋转 90 度,使其右下角与图像的角相匹配(见图 3-9 )。

9781430247227_Fig03-09.jpg

图 3-9。图和旋转的标题,突出显示重新定位的变换原点

在图 3-9 中定位标题的代码可以在清单 3-33 中看到。(注意,我使用了 CSS3 box-sizing属性来确保添加填充后figcaption保持正确的宽度和高度。)

清单 3-33 。 CSS 代码来定位一个快板标题

figure.clapperboard figcaption { font-family: Futura, Arial, sans-serif;
font-weight: 100; font-style: italic; color: black;
box-sizing: border-box;
font-size: 1.2rem; padding: 2rem; padding-top: 8rem;
border: 2px solid black;
transform-origin: bottom right; transform: rotate(90deg);
}

现在标题在正确的位置,你可以关闭border,设置overflowhidden,并反转颜色(见清单 3-34 )。

清单 3-34 。 CSS 代码来定位一个拍板的标题

figure.clapperboard, figure.clapperboard figcaption {
    width:618px;height:515px;
    overflow: hidden;
}
figure.clapperboard figcaption {
    font-family: Futura, Arial, sans-serif;
    font-weight: 100; font-style: italic; color: white;
    font-size: 1.2rem; padding: 2rem; padding-top: 8rem;
    box-sizing: border-box;
    background: rgba(0,0,0,0);
    transform-origin: bottom right;
    transform: rotate(90deg);
}
figure.clapperboard:hover figcaption {
    transform: rotate(0);
}

要使这成为一个动画过渡,请将以下内容添加到figure.clapperboard figcaption声明中:transition: transform 2s cubic-bezier(.12,.49,.17,.87);.

(注意,通过使用适当的属性,您将转换限制为仅仅跟踪转换:这不仅更有效,而且当您在六个月后再次使用它时,更容易跟踪代码。。。同时避免仅仅因为在字幕的默认状态和旋转状态之间改变了某些东西而出现意外的转换)。

虽然这种方法可行,但仍然存在一些问题。例如,在宇航服和月亮的背景下,文本确实不够清晰,所以你会想给figcaption添加一些text-shadowbackground

清单 3-35。 改进了快板字幕过渡的代码

figure.clapperboard figcaption {
    font-family: Futura, Arial, sans-serif;
    font-weight: 100; font-style: italic; color: white;
    font-size: 1.2rem; padding: 2rem; padding-top: 8rem;
    box-sizing: border-box;
    background: rgba(0,0,0,0.6);
    text-shadow: 3px 3px 1px rgba(0,0,0,0.6);
    transform-origin: bottom right;
    transform: rotate(90deg);
    transition: transform 2s cubic-bezier(.12,.49,.17,.87);
}

这对于文本的易读性来说是一个显著的改进,但是背景边缘下降的方式看起来仍然有点奇怪。有几个可能的解决方案:一个是使figcaption更宽,把文本推到右边,把figcaption本身推到左边,这样盒子看起来更像一个视觉“切片”效果(清单 3-36 )。

清单 3-36 。 改进了快板字幕过渡的代码

figure.clapperboard figcaption {
    width: 1236px; height:515px;
    font-family: Futura, Arial, sans-serif;
    font-weight: 100; font-style: italic; color: white;
    font-size: 1.2rem; padding:
    padding: 8rem 2 rem 0 660px;
    box-sizing: border-box;
    background: rgba(0,0,0,0.6);
    text-shadow: 3px 3px 1px rgba(0,0,0,0.6);
    transform-origin: bottom right;
    transform: rotate(90deg);
    left: -618px;
    transition: transform 2s cubic-bezier(.12,.49,.17,.87);
}

在这种情况下,我将figcaption的宽度增加了一倍,并从左侧填充内容,使其覆盖图像的相同部分。通过改变figcaption框的位置和元素变换原点的位置,你会发现创建许多不同种类的效果是可能的。

创建单独的过渡序列

创建字幕过渡的另一种方法是在文本旋转到位后,淡入字幕背景。这需要设置两个独立属性的动画,并延迟其中一个属性,直到第一个属性完成。默认情况下将figcaptionbackground设置为完全透明可以启动这个过程,然后用逗号分隔过渡效果,并为一组值添加延迟。参见图 3-10 中的示例。

9781430247227_Fig03-10.jpg

图 3-10。扩展 figcaption,获得更好的隔板字幕过渡效果。(溢出:为了便于说明,隐藏被关闭,颜色被反转,并且添加了边框。)

清单 3-37 展示了完整的 CSS 代码。

清单 3-37 。 用于快板标题的 CSS 代码

figure.clapperboard { position: relative; overflow: hidden; }
figure.clapperboard figcaption { position: absolute; top: 0; left: 0; padding: 2rem; }
figure.clapperboard, figure.clapperboard figcaption { width:618px;height:515px; }
figure.clapperboard figcaption {
    font-family: Futura, Arial, sans-serif; font-weight: 100; font-style: italic;
    color: white;  font-size: 1.2rem; padding: 2rem; padding-top: 8rem;
    box-sizing: border-box; background: rgba(0,0,0,0);
    text-shadow: 3px 3px 1px rgba(0,0,0,0.6);
    transform-origin: bottom right; transform: rotate(90deg);
}
figure.clapperboard:hover figcaption {
    transform: rotate(0);
    opacity: 1;
    background: rgba(0,0,0,0.6);
    transition: transform 2s cubic-bezier(.12,.49,.17,.87), background .9s linear 2.2s;
}
figure.clapperboard figcaption q { font-size: 2rem; display: block; margin-bottom: 2rem; }

你会注意到,在文本旋转到位后,背景会在 200 毫秒内消失。剩下的一个问题是,当用户将鼠标从图像上移开时,标题会立即消失,这导致了我在《??》第二章中引入转场时遇到的同样问题。将figcaption的转换代码移动到默认状态将意味着转换将在 mouseout 上反转,这看起来也有点奇怪。理想情况下,你想要的是让figcaption以不同于它出现时的方式消失。

改变退出事件

为了达到这个效果,你将制作三个属性的动画:opacitytransformbackground。您将明确地将转换划分为单独的组件,以便于跟踪。每次指定属性的顺序必须相同,此效果才能生效。

然而,首先,您将把opacity添加到各种状态中(清单 3-38 )。

清单 3-38 。 改进了用于快板标题的 CSS 代码

figure.clapperboard figcaption {
    opacity: 0;
...
figure.clapperboard:hover figcaption {
    opacity: 1;
...

现在这没有任何区别,因为标题在默认状态下是不可见的,因为figure元素上有overflow: hidden。但是稍后会有所不同,你很快就会看到。

接下来,你将分解不同的动画组件(清单 3-39 )。

清单 3-39 。 为快板标题的 CSS 代码

figure.clapperboard:hover figcaption { transform: rotate(0); opacity: 1;
    transition-property:         opacity,    transform,                              background;
    transition-timing-function:     ease,         cubic-bezier(.12,.49,.17,.87), linear;
    transition-duration:                 0s,           .9s,                      1s;
    transition-delay:                      0s,            0s,                    1s;
 }

它有助于将转换更改作为列来阅读,这就是为什么我在代码中添加了不必要的空格。在这种情况下,opacity没有计时功能,没有持续时间,也没有延迟(意味着它立即生效),而background具有线性计时功能,持续一秒,延迟一秒(意味着它在文本旋转到位后生效)。

现在到了figcaption的默认状态(清单 3-40 )。

清单 3-40 。 为快板标题的 CSS 代码

figure.clapperboard figcaption {
opacity: 0;
transition-property:                 opacity,   transform,               background;
transition-timing-function;     linear,      ease,                        linear;
transition-duration:                 2s,           9999999s,                0s;
transition-delay:                      0s,           0s,                    0s;
...

这些效果发生在从转换回默认状态的过程中,在两秒钟内将figcaption的不透明度设置回 0。你可能想知道为什么自转会持续不到 1000 万秒。这个高得离谱的数字是适当的,因此将figcaption转换回默认方向(即侧身站立)实际上具有无限的持续时间。从视觉上看,这意味着当用户将鼠标从图像上移开时,文本不会发生任何旋转:标题只是保持静止并淡出。

背景图像过渡和页面加载动画

为了说明页面加载的转变,您将创建一个新西兰在线旅游指南页面(参见图 3-11 )。

9781430247227_Fig03-11.jpg

图 3-11。过渡背景图像

当页面加载时,您希望几张图片从页面的一边滑到另一边。在这个例子中,我将使用车红(www.flickr.com/photos/chleong/6867222762/)、安德里亚斯·比克(www.flickr.com/photos/kiwiwings/2148854337/sizes/l/in/photostream/)、戈登·瑞格里(www.flickr.com/photos/tolomea/4498923741/sizes/l/in/photostream/)和大卫·普尔斯豪斯(www.flickr.com/photos/mdid/2235443912/sizes/l/in/photostream/)的照片。

首先,你将设置你的基本页面,其标记在整个练习中将保持不变(见清单 3-41 )。请注意,图像从页面左侧偏移其宽度(1300 像素)加上一个增量,在水平方向上交错排列。

清单 3-41 。 HTML 和 CSS 代码,用于页面加载时的后台过渡

<div id=wrapper>
<h1> New Zealand</h1>
<p> Lorem ipsum dolor sit amet....
</div>
body { font-family: Futura; margin: 0; line-height: 200%;
background:
    url(lake-benmore-new-zealand-panorama.jpg) -1300px 200px no-repeat,
    url(lake-tekapo-new-zealand-panorama.jpg) -2000px 600px no-repeat,
    url(new-zealand-panorama.jpg) -3900px 1000px no-repeat,
    url(lindis-pass-new-zealand-panorama.jpg) -1300px 1300px no-repeat;
}
div#wrapper { width: 600px; margin: 5em auto; padding: 3em; }

不幸的是,CSS 中还没有background-opacity属性;在保存图像之前,您必须在 PhotoShop 中淡出图像,或者在图像经过文本下方时,采取其他措施来保持文本的易读性。首先,通过应用background: rgba(255, 255, 255, 0.8);,给div添加一个部分透明的background-color

加载背景图像时制作动画

用 CSS3 关键帧开始这样的动画是最容易的(在第五章中讨论过),但是通过在主体上放置一个伪类,只使用过渡也可以达到类似的效果。为了演示这个概念,您将向您的 CSS 添加一个新的声明(清单 3-42 )。

清单 3-42 。 CSS 代码用于页面加载时的背景过渡

body:hover {
background:
    url(lake-benmore-new-zealand-panorama.jpg) calc(100%+1300px) 200px no-repeat,
    url(lake-tekapo-new-zealand-panorama.jpg) 2400px 600px no-repeat,
    url(new-zealand-panorama.jpg) 2400px 1000px no-repeat,
    url(lindis-pass-new-zealand-panorama.jpg) 2400px 1300px no-repeat;
    transition: 70s all linear;
}

假设浏览器窗口宽度小于 2400 像素,这会将图像设置在屏幕的最右侧。(现在做出一个合理的假设,但长期来看是危险的:更好的解决方案是在完全支持 CSS3 变量或 calc 后使用它们。)

这种方法有三个缺点:第一个也是最严重的一个缺点是,当用户的鼠标移出浏览器窗口时,图像会重置到屏幕左侧的默认位置。您可以通过将转换代码移动到默认的身体状态来稍微缓解这个问题,这样当用户的鼠标移开时,转换将开始反转。

第二个问题是所有的背景图像必须作为一个组一起被动画化;使用这种方法无法单独过渡图像。

CALC 是什么?

虽然在这种情况下技术上没有必要,但我在清单 3-42 中的声明中使用了calc作为展示一个令人兴奋的新属性的手段。calc非常接近 CSS3 变量的概念(另一个新的 CSS3 模块),允许我们将任何长度值指定为算术表达式。在清单 3-42 的例子中,计算只是简单地将当前元素的宽度加到它的父元素(??)上,这样当页面加载时,图像就能保证不在屏幕上。

你可以在https://hacks.mozilla.org/2010/06/css3-calc/阅读更多关于calc的内容。

最后一个不太严重的问题是,当背景图像移动到div后面时会突然褪色。这个问题有两个显而易见的解决方案:

  • 使用与divbackground同色的双box-shadow和高模糊量来模糊div的左右边缘,如清单 3-43 所示。

清单 3-43 。 CSS 代码模糊背景图片的过渡

div#wrapper { width: 600px; margin: 5em auto;
    padding: 3em;
    background: rgba(255, 255, 255, 0.8);
    box-shadow: 100px 0 100px  rgba(255, 255, 255, 0.8),
    -100px 0 100px  rgba(255, 255, 255, 0.8);

}

  • 扩展div以覆盖整个身体,这样它后面的所有东西都会被淡出。如清单 3-44 中的所示设置开始声明。

清单 3-44 。 CSS 代码强制整个页面背景图片的不透明度

html, body { min-height: 100%; margin: 0; }
html, body { height: 100%; margin: 0; }
div#wrapper { width: 100%; min-height: 100 %;
    padding: 3em;
    box-sizing: border-box; background: rgba(255, 255, 255, 0.8);
}

创建假背景图像并制作动画

如果您希望对背景图像有更大程度的控制,您必须通过利用positionz-index CSS 属性将图像强制放入背景中来伪造它们。有两种主要方法可以做到这一点。第一个是创建真实的图像,并把它们放在背景中。

这种技术不是通过 CSS 绘制背景图像,而是将它们作为图像放在代码中的上方、下方,甚至是在div ( 清单 3-45 )内部。

清单 3-45 。 HTML 和 CSS 代码为页面创建假背景图片

<img src=lake-benmore-new-zealand-panorama.jpg alt="Lake Benmore, New Zealand" id=benmore>
<img src=lake-tekapo-new-zealand-panorama.jpg alt="Lake Tekapo, New Zealand" id=tekapo>
<img src=lindis-pass-new-zealand-panorama.jpg alt="Lindis Pass, New Zealand" id=lindis>
#benmore, #tekapo, #lindis { position: absolute; z-index: -1; }
#benmore { top: 300px; left: 200px; }
#tekapo { top: 600px; left: 800px; }
#benmore, #tekapo, #lindis {
    position: absolute; z-index: -1; opacity: 0; transition: 4s linear all 2 s; }
#lindis { top: 900px; left: 50px; }

作为单独的图像,这些元素可以跨所有属性单独设置动画。为元素提供一个负的z-index将它们推入深层背景。它们在清单 3-46 中以与之前练习中相同的方式被制作成动画。

清单 3-46 。 动画假背景图片

body:hover img#benmore, body:hover img#tekapo, body:hover img#lindis { opacity: 0.6;  }

同样,如果您希望序列不管用户活动如何都循环播放,您通常会使用关键帧动画。

或者,您可以通过使用生成的内容来创建相同的效果。这样做的优点是不需要额外的标记,但是限制了两个添加的元素(一个通过使用:before生成,一个通过使用:after)。如前所述,给定z-indexopacity,这些元素也可以被转换。

摘要

在这一章中,你已经学习了如何使用带有不透明度的 CSS3 过渡和 CSS4 交叉淡入淡出来交叉淡入淡出两幅图像。您还创建了一个简单的图片库(在许多站点环境中都很有用),并通过过渡逐渐增强了图片库。我已经向您展示了如何使用几个不同的伪选择器(:target:active:hover),)来启动这些转换,其中的每一个都将适用于特定的演示。

您已经为图像的标题制作了动画,并且在这个上下文中,移动了变换轴以创建“偏移”旋转。

过渡模块有几种延迟序列以创建分层动画效果的方法,从简单的(transition-delay)到诸如提供极高的时间值以有效地将过渡元素永久保持在适当位置的技巧。您可以使用这些相同的技术在过渡元素中创建不同的入和出效果,这些效果通常只是按照它们出现时的动画顺序进行反转。

最后,您已经将过渡推进到了大多数开发人员很少涉足的领域:生成内容的动画和页面加载时移动的背景图像。

在下一章,我将向你展示如何将 CSS3 过渡应用到网站导航和其他用户界面功能中。

四、UI 元素的 CSS3 过渡

CSS3 transitions 的另一个明显的作用是增强网页中的用户界面元素:在导航、表单和按钮中构建动画,使网站上的信息更清晰、更吸引人。在这一章中,我将学习到目前为止你已经探索过的动画原理和 CSS 语法,并在课程中对它们进行扩展,这将使你的设计更具互动性、更有趣、更好玩。

现代网站导航标记

在你的站点导航中添加过渡之前,花点时间研究一下你将把 CSS 规则挂入的标记是值得的。对于 HTML5 网站,主导航应该位于一个<nav>元素中。为了确保与屏幕阅读器的兼容性,您将在标签中添加一个 ARIA 导航角色,如清单 4-1 所示。

清单 4-1 。 最小 HTML5 站点导航结构

<nav role=navigation>
<a href=index.html>Home</a>
<a href=about.html>About Us</a>
<a href=products.html>Products</a>
</nav>

image 您可以在www.w3.org/TR/wai-aria-practices/了解更多关于 ARIA 地标角色的信息。

如您所见,HTML5 允许您在nav元素中放置一系列简单的站点链接。但是,您可能会发现,添加标记增加了导航的语义价值,同时允许您以更大的灵活性修改其外观。在大多数情况下,站点导航可以被视为一个无序列表;或者,如果希望用户以特定的顺序阅读页面,您可能希望使用有序列表。

无论您选择哪种方法,键盘快捷键也应该通过accesskey属性添加到主链接中,如清单 4-2 所示。(注意,role属性已经移动到无序列表中。)

清单 4-2 。 一个易访问的站点导航代码结构

<nav>
<ul role=navigation >
<li><a href=index.html accesskey=1>Home</a>
<li><a href=new-xyz-corp.html accesskey=2>What's New</a>
<li><a href=about-xyz-corp.html accesskey=a>About Us</a>
<li><a href=contact-xyz-corp.html accesskey=6>Contact Us / Help</a>
</ul>
</nav>

这是你将在本章中构建的每一个主要导航界面的基础。为了节省空间,您并不总是需要包含完整的辅助功能,但是在最终的产品代码中使用这些功能是非常重要的。

image 注意在某些情况下,对于 CSS 规则的某些组合,如果链接在水平排列的<li>元素中,它们之间可能会出现微小的视觉间隙(如清单 4-3 )。虽然无论如何格式化都希望保留您的代码——与 HTML 相反,HTML 将所有连续的空格字符折叠成一个空格,回车符计为一个空格,除非内容包含在<pre>标签中——但是找出这些差距的原因可能会非常令人沮丧。

The issue lies not with the CSS, but with the HTML, in the form of carriage returns between each list item. While CSS solutions to this problem exist (setting font-size: 0 on the parent element, for example, or floating the list item elements), the best option is usually to remove the carriage returns, placing all of the list items in a single line, as shown in Listing 4-3.

清单 4-3 。 一个无障碍的站点导航代码结构,没有多余的空格

<nav>
<ul role=navigation><li><a href=index.html accesskey=1>Home</a><li><a href=new-xyz-←
corp.html accesskey=2>What's New</a><li><a href=about-xyz-corp.html accesskey=a>About←Us</a><li><a href=contact-xyz-corp.html accesskey=6>Contact Us / Help</a></ul>
</nav>

`For the sake of clarity I will not be using this solution in the code samples to come, but you should be aware of the potential problem and its solution.

不管它们是否用一行代码编写,用有序或无序列表构建的导航结构都会在单独的一行上显示每个链接。要创建水平导航栏,您必须在 CSS 中添加一个内容。

水平导航栏基础知识

当网站相对较小时,通常使用水平导航界面。(下拉菜单条是这个规则的一个例外,我将很快介绍它。)

“神奇的数字 7,加或减 2”是确定导航结构的有效经验法则:平均而言,人类在任何时候都可以回忆或联系到多达 7 个项目。导航中超过七个条目通常意味着你需要重新考虑 UI(用户界面)——分块或者将相关条目组合在一起通常可以解决问题。根据屏幕的宽度,你通常也可以在一个导航浏览器窗口中水平放置七个导航项目;非常窄的窗口(比如在移动设备上)或者超过七个主链接通常需要垂直方向的导航格式。

链接是自动内联显示的,所以几乎不需要添加 CSS 来使它们在水平导航栏中看起来有组织。如果您已经将链接包装在<li>标签中,那么几乎没有什么工作要做:只需将清单 4-4 中的声明添加到您的样式表中。

清单 4-4 。从一个 HTML5 导航结构创建一个水平导航条

nav li { display: inline; }

现在您已经为最常见的站点导航格式建立了基本的标记,您可以继续使用 CSS3 来增强它们。

用 CSS3 增强的简单导航栏

让我们从清单 1-1 中选取最简单的导航标记,并在导航栏后面放置一个background-image。您将可视化地格式化文本,以便通过添加a text-shadow and a hover effect仍然可以阅读,如清单 4-5 所示。

清单 4-5 。从一个 HTML5 导航结构创建一个水平导航条

nav { background: url(img/clouds.jpg) no-repeat; padding: 1em 0; }
nav a { text-decoration: none; color: #fff; padding: 1em;
font-family: Futura, Arial, sans-serif;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.6); }
nav a:hover { background: rgba(0, 0, 0, 0.7); }

然后,你将添加一个简单的过渡,通过调整清单 4-6 中的选择器,来淡入一个悬停链接后面的背景。

清单 4-6 。 使用 CSS3 给链接引入过渡效果

nav a { text-decoration: none; color: #fff; padding: 1em;
font-family: Futura, Arial, sans-serif;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.6);
-webkit-transition: background .85s ease-in-out;
-moz-transition: background .85s ease-in-out;
-o-transition: background .85s ease-in-out;
transition: background .85s ease-in-out;
 }

最后,做一点安全检查:任何时候你把一张图片放在一个元素的背景中,你都应该设置一个代表图片主色的background-color,以防图片无法加载。修改nav声明,如清单 4-7 所示,确保链接的文本在任何情况下都清晰可辨。

清单 4-7 。 创建一个 CSS 背景色作为图片的退路

nav { background: url(img/clouds.jpg) #007 no-repeat; padding: 1em 0; }

您还可以使用nav a:visited作为选择器,对用户之前访问过的链接应用不同的外观。如清单 4-8 所示,当鼠标悬停在这样的链接上时,你甚至可以创建一个不同颜色的过渡。

清单 4-8 。 为访问过的链接创建单独的效果

nav a:visited:hover {
background: #f00;
background: rgba(255, 0, 0, 0.7);
}

过渡效果仍将应用于已访问的链接,但它们将褪色为红色,而不是黑色。这将产生如图 4-1 所示的菜单。

9781430247227_Fig04-01.jpg

图 4-1。具有动画悬停效果的导航栏

以这种方式添加 CSS3 完全向后兼容旧的浏览器。如果浏览器不支持过渡,用户只会在当前悬停的链接后面看到部分透明的背景。

image 提示想象只支持 CSS 2.1 的旧浏览器的行为的最简单的方法是记住,它们对任何过渡都施加了一个持续时间0。顺便说一下,这就是为什么transition-durationtransition property的默认值分别是0all

如果您想确保更好的跨浏览器兼容性,您可以在声明的rgba部分之前为悬停的链接添加一个后退的黑色(#000背景。理解rgba的浏览器会遵循最后一条规则;那些没有的将遵循十六进制颜色。淡入仍然可以工作,并且在支持它的浏览器中正确显示。

在导航中高亮显示当前页面

在导航栏中突出显示用户的当前页面是有问题的。CSS 不知道应用的内部状态——它不知道在哪里。你可以通过在body标签上为每个页面上的自引用链接创建一个classdata属性或id来避免这个问题,允许 CSS 匹配选择器,如图图 4-2 所示。

9781430247227_Fig04-02.jpg

图 4-2。高亮显示当前位置的导航栏

从清单 4-9 中的代码开始。

清单 4-9 。 在网站导航条上标记出“你在这里”的视觉效果

index.html:

<body id=home>
<nav role=navigation>
<a href=index.html class=home>Home</a>
<a href=about.html class=about>About Us</a>
<a href=products.html class=products>Products</a>
</nav>
about.html:
<body id=about>
<nav role=navigation>
<a href=index.html class=home>Home</a>
<a href=about.html class=about>About Us</a>
<a href=products.html class=products>Products</a>
</nav>

定位表示当前页面的链接是一个简单的过程,将一系列后代选择器分组,如清单 4-10 所示。

清单 4-10 。 CSS 高亮显示当前页面链接

#home nav a.home, #about nav a.about { background: rgba(0,0,212,0.6);}

也可以通过在每个页面上嵌入一个单独处理每个链接类的样式表来达到这种效果。这两种方法都有相同的缺点:它们需要为每个页面定制标记。更好的解决方案可能是 CSS 和 JavaScript 的结合(这里以 JQuery 的形式显示)。

HTML 返回到开始时的样子(清单 4-1 ),你的样式表简单地加入一个新类,如清单 4-11 所示。

清单 4-11 。 CSS 通过 JavaScript 突出显示“你在这里”链接

a.current { background: rgba(0,255,0,0.7); }

在每个文档的head中,你包含了清单 4-12 中的代码。

清单 4-12 。 JavaScript 将“你在这里”类应用到站点导航中

<script src=//code.jquery.com/jquery.min.js></script>
<script>
$(document).ready(function(){
$('ul[role="navigation"] a').each(function() {
if (this.href === window.location.href){ $(this). addClass('current');}
});
})
</script>

在下一节将要创建的更高级的导航示例中,您可以使用这些方法中的任何一种来突出显示当前页面。

带有 CSS3 过渡的水平标签导航

作为站点导航的一个更高级的例子,你可以在“标签”导航中包含移动。在这种情况下,你将把链接放在一个有序列表中以提供更多的结构,就像你在清单 4-2 中所做的那样。按照清单 4-13 中的,你将通过并排设置链接,在它们的右上角和左上角添加一个border-radius,并在每个标签的背景中放置一个渐变来创建标签的视觉效果。这将产生如图 4-3 中所示的菜单。

9781430247227_Fig04-03.jpg

图 4-3。动画标签导航系统

在这个例子中,您将使用一个属性选择器来访问列表项和链接。

清单 4-13 。 CSS 将导航链接样式化为选项卡

ul[role=navigation] li {
display: inline; font-family: Futura, Arial, sans-serif;
text-transform: uppercase;
}
ul[role=navigation] li a {
text-decoration: none; color: #fff;
padding: 0.8rem 1.2rem 2rem 1.2rem;
border: 1px solid #777; border-radius: 5px 5px 0 0;
background: linear-gradient(to bottom, #dfc891, #776c51);
box-shadow: 0 0 15px rgba(0,0,0,0.5);
letter-spacing: 0.15rem; text-shadow: 0 1px 0 #000;
}

接下来,您需要稍微重叠选项卡。您可以通过为每个列表项提供一个负数margin-left来实现。鼠标经过时标签会上移,所以你故意把它们做得比正常状态下要长。使用无序列表上的overflow: hidden隐藏底部边缘的多余部分,如清单 4-14 所示。

清单 4-14 。 CSS 将导航链接样式设置为选项卡

ul[role=navigation] {
background: #000;  padding-top: 3.2rem; padding-bottom: 1rem;
overflow: hidden; margin-top: 0; }
ul[role=navigation] li {
display: inline; font-family: Futura, Arial, sans-serif;
text-transform: uppercase; margin-left: -.5rem;  }

代表当前页面的链接将应用一个类forefront。这个类通过使用负的topposition: relative和修改后的z-index ( 清单 4-15 ),将适当的链接放在所有其他选项卡之上,并且比其他选项卡略高。

清单 4-15 。 将当前页面的链接放置在其他页面的顶部

ul[role=navigation] li a.forefront { -0.2rem; z-index: 2;}

您可以使用已经讨论过的任何一种方法来应用这个类:将它添加到标记中,或者用 JavaScript 动态地应用它。最后,你将在悬停时通过提升链接的顶部位置来提升链接,并将默认状态的转换动画化(清单 4-16 )。

清单 4-16 。 制作标签页链接动画

ul[role=navigation] li a {
position: relative; top: 0;
transition: 0.2s all linear;
...
}
ul[role=navigation] li a:hover,  ul[role=navigation] li a:focus {
top: -0.6rem;
}

HTML5 表单自定义验证错误动画

用户输入表单的信息通常至少要检查两次:一次在前端(通常用 JavaScript),一次在后端(用 PHP 或其他服务器端语言)。这种方法有几个优点:

  • 冗余 :如果客户端验证过程失败,或者在浏览器中被阻止或不支持,后端过程仍然会寻找错误。
  • 即时性 :客户端解决方案通常在访问者向字段中输入信息时或字段失去焦点后提供即时反馈;除非使用 AJAX 或类似技术,否则服务器端解决方案在提交按钮被按下之前无法提供响应。
  • 安全 :一般来说,服务器端语言将提供一种比使用 JavaScript 更合适、更安全的方式从 VISA 和 Mastercard 获取信用卡验证信息。

JavaScript 中已经有很多验证脚本,但是在 HTML5 中,同样的验证表单的能力现在在浏览器中得到了原生支持,具有pattern属性和两个新的 CSS 伪类::valid:invalid。为了演示这一点,你将创建如图 4-4 所示的表单。

9781430247227_Fig04-04.jpg

图 4-4。用 CSS3 制作动画形式的错误信息

你从易访问表单的基本标记开始,如清单 4-17 所示。

清单 4-17 。?? 一个可访问的 HTML5 表单

<form>
<label for=age accesskey=a>Age</label>
<input type=number name=age id=age size=3 maxlength=2 min=1 max=99pattern="^([1-9]|[1-9][0-9]){1,2}$” required >
<label for=name accesskey=n>Name</label>
<input type=text name=name id=name size=40 maxlength=38 ←
pattern="^[a-zA-Z]'?[- 'a-zA-Z]+$" placeholder="Your full name" required >
<label for=email accesskey=e>eMail address</label>
<input type=email name=email id=email size=50 maxlength=256 placeholder="Your contacteMail"required>
<input type=submit value=submit>
</form>

正如您所看到的,您使用了一个带有minmax值的number字段来限制用户输入的年龄、一个电子邮件输入和一个带有正则表达式的标准文本输入来获取用户的姓名。所有输入都是必需的。(我给number输入添加了一个pattern,尽管它在 HTML5 中是无效的,以便在 Firefox 14 和更早的版本中得到加强,它识别pattern但不识别number属性值本身,默认字段为标准文本输入。)你可以使用一些基本的 CSS 来改善这些元素的显示,如清单 4-18 所示。

清单 4-18 。 CSS 为典型的可访问表单

form { font-size: 1.2rem; font-family: "Gill Sans", Arial, sans-serif; }
label,input { display: block; }
label:first-letter { border-bottom: 2px solid #bbb; }
input { border: 1px solid #bbb; padding: .4rem; border-radius: .2rem; margin: .5rem 0; }
input[type="submit"] { border: none; text-transform: uppercase; }

这个样式表唯一稍有不同的地方是第三个声明,它给每个表单标签的第一个字母加下划线,以显示相关字段的适当的 accesskey。要显示输入的信息是对还是错,需要添加清单 4-19 中的代码。(注意第一个 CSS 声明,它关闭了有效和无效输入的当前默认 Firefox UA 样式)。

清单 4-19 。 CSS 为典型的可访问表单

input:valid, input:invalid {box-shadow: none; }
input:valid { border: 2px solid green; }
input:invalid { border: 2px solid yellow; }

虽然您当然可以将目前的表单制作成动画,但是目前的表单有一些缺点:当用户第一次看到页面时,浏览器默认将输入显示为无效,并且没有指示用户输入错误的确切内容。

您不能使用伪类在输入之后生成错误消息,因为它们是被替换的元素,但是您可以将错误消息放在输入之后的跨度的属性中。清单 4-20 中显示了一些例子。

清单 4-20 。 在 HTML5 表单输入后添加 Span 元素作为验证错误消息

<span title="Must be between 1 and 99"></span>
<span title="Must a complete valid eMail address"></span>
<span title="Letters, spaces, apostrophes and hyphens only"></span>

因为每个span只包含其title属性中的信息,没有可见的内容,所以不完全支持 CSS3 的旧浏览器不能向用户显示任何令人困惑的消息。从你的代码中删除清单 4-20 ,用清单 4-21 代替。

清单 4-21 。样式和显示验证错误

input + span:after { content: attr(title); color: red; margin-left: 0.6rem; opacity: 0; }
input:invalid + span:after { opacity: 1; }

有一个直接的问题:浏览器通过在页面加载时显示span title属性来继续显示输入错误。原因?

image 提示具有required属性的input由它的pattern评估,或者在用户聚焦或向字段中输入任何信息之前输入type

通过从输入中移除required属性,并给错误消息添加一个转换,如清单 4-22 中的所示,你实现了你想要的效果。请注意,我已经为转换添加了延迟:如果没有延迟,在输入字段中的第一个字符时,错误消息会立即显示出来。在你告诉用户他们的信息是错误的之前,你需要一段合理的时间。

清单 4-22 。 延迟后显示表单验证错误信息

input + span:after { content: attr(title); color: red; margin-left: 0.6rem; opacity: 0;
transition-property: opacity;transition-duration: 2s; transition-delay: 2s;}

您还可以通过在表单元素中显示勾号来显示输入的有效性状态。回到清单 4-17 中的标记和清单 4-18 中的 CSS,添加清单 4-23 中的 CSS。(你可以进一步将tick.png变成精灵图像,并在输入无效时显示一个十字)。

清单 4-23 。 显示表单输入验证的背景图像

input:focus:valid { background-image: url(tick.png); background-repeat: no-repeat;
background-position: right 6px;  }

您不能直接淡入背景图像(到目前为止,还没有对背景图像不透明度的直接控制),但是您可以操作图像,所以如果您想淡入符号,您可以将图像放在输入之后,并像您之前处理验证消息一样转换它。

image 注意您也可以完全通过 JavaScript 关闭浏览器的内置表单验证消息,如下所示,使用 jQuery:

$(document).ready(function() {
$('form').bind('invalid', function(e){
$(e.target).attr('validity')
}); });

UI 按钮按下过渡

使用 CSS,你也可以给人一种链接或按钮降低或沉入页面的感觉,如图图 4-5 所示。

9781430247227_Fig04-05.jpg

图 4-5。典型的按钮示例

实现这一效果的简单方法如清单 4-24 所示。

清单 4-24 。 CSS 使链接点击时降低

a:active { position: relative; top: 1px; }

当然,也可以更精细地设计一个链接,如清单 4-25 所示。

清单 4-25 。 HTML 和 CSS 创建巨型帮助按钮

<a href=# class=bigbutton>help</a>
a.bigbutton {
font-family: "Blue Highway"; text-transform: uppercase; color: #fff;
background: radial-gradient(center 50px, circle farthest-corner, #ef6634, #c63a17 43%,#ba1a01 45%,#bf6e4e 100%);
display: inline-block; width: 200px; height: 200px; border-radius: 100%;
font-size: 70px; text-decoration: none; text-align: center; padding-top: 50px;
box-sizing: border-box; font-weight: 900;
box-shadow: 0 8px 0 rgb(183,0,0), 0 15px 20px rgba(0,0,0,.35);
text-shadow: 0 3px 1px rgba(122,17,8,.8);
transition: .4s all ease-in;
}

在这里,您通过创建两个方框阴影来创建 3D 按钮的效果:一个用于创建按钮边缘的效果,另一个在其下方作为常规阴影。您通过转换四个同时发生的动作来创建按钮降低的印象:

  1. 降低按钮上的文本。
  2. 使用 translate 物理降低整个按钮。
  3. 减少代表按钮边缘的阴影。
  4. 减少和加强整个元素下方阴影的模糊度。

你将在一个基于:active伪选择器的声明中做到这一点,如清单 4-26 所示。

清单 4-26 。 HTML 和 CSS 创建巨型帮助按钮

.bigbutton:active {
   padding-top: 53px;
   transform: translate(0, 4px);
   box-shadow: 0 4px 0 rgb(183,0,0), 0 8px 6px rgba(0,0,0,.45);
}

还可以创建一个按钮显示效果,您将在下一节看到。

UI 按钮显示过渡

标准的 HTML button元素也可以用包含过渡的 CSS 进行大量定制。在这种情况下,你需要一个按钮在hover上展开,显示里面的推广或引导信息(见图 4-6 )。

9781430247227_Fig04-06.jpg

图 4-6。一个按钮有两种模式,用 CSS3 过渡了

你的 HTML 将由三个元素组成:一个包含两个标签的button。你可以在清单 4-27 中看到这个标记。

清单 4-27 。 HTML 为一个显示按钮

<button>Sign up
<span class=hidden>For Free</span>
<span class=right></span>
</button>

image 提示当用于 UI 元素的右侧时,Unicode 字符比图像适应性更强,也更容易控制。我在这里使用了一个十进制实体字符来表示向右的黑色(可以在copypastecharacter.com找到 Unicode 字符的一个很好的资源)。)

接下来,您将添加 CSS 来设置您的按钮外观(清单 4-28 )。

清单 4-28 。 为一个显示按钮的基本 CSS

* {box-sizing: border-box;
color: #333; font-family: Futura, Arial, sans-serif;
}
button {
        font-weight: 600;
        text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.3);
border-radius: 34px; height: 68px; width: 180px;
padding: 0 20px; font-size: 18px;
background: linear-gradient(to bottom, #1e5799,#7db9e8);
border: 1px solid rgba(0,0,0,0.4);
box-shadow: 0px 1px 1px rgba(255, 255, 255, 0.8) inset,
1px 1px 3px rgba(0, 0, 0, 0.2),
0px 0px 0px 4px rgba(188, 188, 188, 0.5);
text-align: left;
}
span.hidden, span.right  { color: #fff;  }
span.right { padding-left: 18px;  }
span.hidden {background: linear-gradient(to bottom, #222, #000);
display: inline-block; width: 0; margin-left: 22px;
overflow: hidden;
white-space: nowrap; padding: 22px 0;
border-left: 2px double rgba(0,0,0,0.3); }

因为.hidden跨度设置为box-sizing: border-boxwhite-space: nowrapoverflow: hiddenwidth: 0,所以正常情况下你只能在左侧看到它的border

您希望多个过渡事件在同一时间以相同的动作发生。虽然您可以将转换属性放在单独的声明中,但是将它们放在 CSS 中尽可能高的位置通常会更有效。

清单 4-29。 CSS 为一个按钮显示过渡

button { transition: .6s all ease-in-out; }
button:hover { width: 290px; color: #fff; text-shadow: none;  }
button:hover span.hidden { width: 120px; padding: 22px;  }

带有 CSS3 过渡 的可访问水平下拉导航

下拉菜单是复杂网站的常见导航选项。用户已经熟悉了他们电脑上用户界面的格式,所以在网站上使用相同的界面设计是有意义的。参见图 4-7 中的示例。

9781430247227_Fig04-07.jpg

图 4-7。下拉菜单

HTML 页面上的下拉菜单传统上是使用 Flash 或 JavaScript 创建的,但这些工具都有一个明显的缺点:对于残疾人来说,使用屏幕阅读器和/或键盘使用它们创建的菜单可能很困难。

通过在带有 CSS3 过渡的 HTML5 标记中使用 ARIA 特性,您可以获得最好的一切:可访问的、视觉上吸引人的、动画的 UI 元素。基本标记如清单 4-30 所示。

image 提示你可以在www.w3.org/TR/wai-aria/roles了解更多关于咏叹调角色的信息。

清单 4-30 。 可访问下拉菜单的 HTML

<nav role=navigation aria-label="Main menu">
<ul role=menubar>
<li role=menuitem tabindex=0><a href=#>Home</a>
<li role=menuitem aria-haspopup=true tabindex=0><a href=#>Services</a>
<ul class=submenu role=menu aria-hidden=true>
<li role=menuitem tabindex=-1><a href=#>Abrasion</a>
<li role=menuitem tabindex=-1><a href=#>Peel</a>
<li role=menuitem tabindex=-1><a href=#>Wax</a>
</ul>
<li role=menuitem tabindex=0><a href=#>Contact</a>
</ul>
</nav>

代码类似于您在清单 4-1 中开始的代码(没有访问键,为了节省空间,本例中省略了访问键)。导航角色已经移回到nav元素上,该元素也获得了一个描述其用途的标签,相当于标题工具提示。

每个列表项都有一个角色menuitem,表示它是可操作的,还有一个tabindex,或者是0(表示它可以通过使用 TAB 键在两个列表项之间跳转)或者是-1(意味着必须使用其他控件,比如箭头键来聚焦它们)。最后,包含子菜单的列表项有一个aria-haspopup属性,子菜单本身有一个aria-hidden属性,表示默认情况下它是不可见的。

为此,你要添加一些基本的 CSS,如清单 4-31 所示。

清单 4-31 。代码为 CSS3 的下拉菜单

body { font-family: Futura, Arial, sans-serif; }
nav { height: 41px;
background: linear-gradient(to bottom, rgb(93,146,207) 0%, rgb(79,79,181) 100%); }
nav ul { margin: 0; }
nav, ul.submenu { background: #35f; border-radius: 5px;  padding: 0;  }
nav ul li { display: block; width: 150px; text-align: center; float: left; margin: 0; padding: 0;  }
nav li:hover { background: rgba(0,0,0,0.4); }
nav a { color: #fff; text-decoration: none; display: block; padding: 10px; }
nav ul.submenu { background: rgba(0,0,0,0.8); position: relative; border-radius: 0 0 5px 5px; height: 0px; overflow: hidden; }
nav ul.submenu li { float: none; text-align: left; border-bottom: 1px solid rgba(0,0,0,0.3); }

清单 4-31 中的代码应该是不言自明的:主列表项并排浮动,子菜单放在下面,在本例中,通过将其高度设置为 0 来隐藏。

在当前大多数浏览器中,CSS3 的实现要求您在转换元素的维度时设置明确的度量;在这种情况下,height: 100%height: auto都不起作用。此外,您希望将相同的过渡效果添加到多个元素中;与其重复自己,不如在清单 4-32 的顶部添加声明。

清单 4-32 。 CSS 为一个动画下拉菜单

nav ul li { transition: .3s all linear; }
nav ul li:hover ul.submenu { height: 126px;  }

这种标记和 CSS 可以成为许多界面设计的基础。例如,通过一些小的调整,垂直扩展的“手风琴式”菜单也可以遵循这个模板。

点击按钮后启动 CSS3 过渡效果

在大多数标准 HTML 中,没有记录状态的方法;也就是说,你可以捕捉用户的鼠标在一个元素上的动作(:hover)、按下的动作(:active),以及在某些情况下,在一个元素内输入的动作(:focus),但是很少有直接明显的方式来说“如果这个元素被点击,这样做;但如果关闭了,就撤销动作。”

然而,对于 CSS,您确实有一些选择。CSS 可以通过使用:checked伪类读取复选框和单选按钮元素的状态。通过隐藏复选框,但通过使用关联的label元素来保持可访问性,您可以使用 CSS 来“切换”页面的显示。

image 注意虽然我接下来要讨论的技术在 HTML5 中是有效的(它允许你在页面的任何地方放置表单元素),但是它们在语义上是有问题的。有一个学派认为表单元素只应该在表单中使用,并且这些类型的行为应该专门归属于 JavaScript。在继续下面的技术之前,您应该意识到这种争用。

接下来,我将演示如何实现图 4-8 所示的图像。

9781430247227_Fig04-08.jpg

图 4-8。一张火星的图片和描述,显示了一个被点击的元素(图片由美国宇航局提供)

根据清单 4-33 中的,你的标记将由一个容器div、一个复选框input和一个包含一些内容的内部div组成。

清单 4-33 。??【复选框标记】打开和关闭一个关联的 div

<div id=mars>
<input type=checkbox id=marstoggle>
<div class=toggle>
<img src=mars.jpg alt=Mars>
<p>Trace amounts of methane were discovered in the atmosphere of Mars in 2003... ←Asmethane is unstable, its presence indicates an active source on the planet that is ←continuallyreplenishing the gas, at the rate of approximately 270 tons per year. ←
</div>
</div>

您将使用清单 4-34 中的代码对外部div及其内容进行样式化。

清单 4-34 。 div 为弹出文本

div#mars { background: #000; color: #fff;
font-family: Futura, Arial, sans-serif;
width: 400px; padding: 1.6rem;
line-height: 175%; border-radius: 6px; }
img { display: block; margin: 0 auto; }
div#mars p { margin: 1rem; }

您想要隐藏内部的div,方法是使用同级选择器将它的height设置为0,并隐藏它之外的任何内容。同时,您还将使用前面讨论的推拉动画原理来设置过渡。(参见清单 4-35 。)

清单 4-35 。??【开合一格】过渡

input ∼ div { overflow: hidden; height: 0; transition: .6s all cubic-bezier(0.735, -0.485, ←
0.145, 1.625);   }

要完成交互式元素的基本功能,如果复选框被选中,您需要展开内部的div。正如我提到的,height需要被显式设置,以便元素在当前浏览器中正确转换(参见清单 4-36 )。

清单 4-36 。 div 为弹出文本

input:checked ∼ div { height: 480px; }

这在这里效果很好,但是用单选按钮隐藏和显示页面内容对于大多数设计来说可能不太好。为了解决这个问题,您可以将一个labelinput相关联,通过使用for属性将label的文本“链接”到checkbox。因此,点击label将打开表单元素,并使你的 CSS 继续响应,即使复选框本身是隐藏的(见清单 4-37 )。

清单 4-37 。 完成复选框关联 div 的标记

<div id=mars>
<label for=marstoggle>Mars</label>
<input type=checkbox class=toggle id=marstoggle>
<div>
<img src=mars.jpg alt=Mars>
<p>Trace amounts of methane were discovered in the atmosphere of Mars in 2003...
</div>
</div>
label { display: block; text-align: center; font-size: x-large;
background: red; border-radius: 6px; padding: .2rem; }
label:hover { background: yellow; color: #000; cursor: pointer; }
input { display: none; }

如果您愿意忽略一些语义问题,这个复选框控件有许多可能性。甚至可以在菜单中使用它来保持状态打开(例如,作为一系列下面有内容的选项卡,或者作为一个折叠菜单)。

用 CSS3 制作表单元素动画

可以扩展转换来直接修改表单元素的外观。一个简单的例子是当输入文本元素的信息不正确时,视觉上的“抖动和淡入”,如清单 4-38 和图 4-9 中的所示。

清单 4-38 。简单动画表单元素的 CSS

input { padding: 1rem; transition: .5s 2s all cubic-bezier(0.475, -0.600, 0.435, 1.650);   }

input:invalid { border: 3px solid red; transform: translateX(10px); }

9781430247227_Fig04-09.jpg

图 4-9。一组动画的、定制的单选按钮

有一些注意事项,您可以使用 Simurai ( http://simurai.com/)首先提出的技术将它扩展到单选按钮。基本的标记非常简单:每个单选按钮都有相同的名称,这意味着每个按钮在被单击时都会关闭其他按钮。默认情况下,一个单选按钮自动打开,如清单 4-39 所示。

清单 4-39 。 HTML 为动画单选按钮

<input type="radio" name="radiobutton" checked>
<input type="radio" name="radiobutton">
<input type="radio" name="radiobutton">
<input type="radio" name="radiobutton">
<input type="radio" name="radiobutton">

接下来是 CSS,如清单 4-40 所示。

清单 4-40动画单选按钮的 CSS

body, input { background-color: rgb(20%,20%,20%); }
input {
     appearance: none;
     margin: 10px; width: 22px; height: 22px;
     border-radius: 50%; cursor: pointer;
     vertical-align: middle;
     box-shadow: hsla(0,0%,100%,.15) 0 1px 1px, inset rgba(0,0,0,.5) 0 0 0 1px;
     background-color: rgb(20%,20%,20%);
        background-image: radial-gradient(
        hsla(0,100%,90%,1) 0%,
        hsla(0,100%,70%,1) 15%,
        hsla(0,100%,60%,.3) 28%,
        hsla(0,100%,30%,0) 70%
    );
      background-repeat: no-repeat;
      transition-property: background-position, transform;
      transition-duration: .15s, .25s;
       transition-timing-function: cubic-bezier(.8, 0, 1, 1);
     }
input:checked {
     transition-property: background-position, transform;
     transition-duration: .2s, .25s;
     transition-delay: .15s, 0s;
     transition-timing-function: cubic-bezier(0, 0, .2, 1);
   }
input:active { transform: scale(1.5); transition: transform .1s cubic-bezier(0, 0, .2, 1); }
input,input:active { background-position: 22px 0; }
input:checked { background-position: 0 0; }
input:checked ∼ input, input:checked ∼ input:active { background-position: -22px 0; }

image 注意appearance属性旨在从一个元素中移除所有预配置的默认样式,或者允许元素呈现其他元素的外观(例如,将一个span样式化为一个textbox)。appearance是为 CSS3 提出的,但没有进入 UI 模块的规范,尽管它正在被考虑用于规范的未来迭代。该属性在 Webkit 中支持前缀,在 Firefox 中支持部分前缀。出于这个原因,在我写这篇文章的时候,清单 4-40 中显示的代码在 Chrome 中运行得最好。

一旦你克服了hsla颜色渐变的复杂性(非常适合创建不同颜色的“信号”灯),剩下的代码就简单了:单选按钮在焦点上变大,释放时径向渐变的背景图像移动到按钮的位置。

摘要

在这一章中,你已经看到了 CSS3 过渡可以用来增强用户界面元素的一些方法,从表单到站点导航。有无数的可能性,我将留给你的想象力和实验。

尽管它们很有用,但转换受到两个事实的限制:它们依赖于某种用户动作来启动,并且它们总是在两点或两种状态之间活动。在曲线上移动对象是不可能的,因为让它们自己循环或运行是不可能的。所有这些特性都属于 CSS 动画模块的范围(我称之为“关键帧动画”以进一步区分它们和过渡)。我将在下一章讨论这个模块。`

五、CSS3 关键帧动画

对于在两种状态之间创建简单的元素动画,CSS 转换很容易实现和使用,但是这种简单性有几个明显的限制。为了创建更复杂的动画,你需要 CSS 动画模块。我将 CSS 动画模块创建的动画称为关键帧动画,以进一步区分它们和过渡。

如果您更熟悉 Flash 之类的动画工具,或者来自视频或电影背景,CSS 关键帧动画使用的基于时间的“无帧”方法一开始可能会有点混乱。为了确保每个人都有相同的理解,我将定义关键帧和补间,然后看看它们是如何通过 CSS 动画模块实现的。

关键帧和补间和

现代动画继承了迪士尼和其他动画师在 20 世纪早期开发的传统手绘、cel-shaded 动画的术语和流程。在角色研究、草图和剧本完成后,动画开发是这样的:

  1. 一个序列的主要帧是由一个监督动画师绘制的。(在迪士尼工作室,这可能是“九个老人”中的一个,他是创造确立镜头的动画大师。)例如,在像 Dumbo 这样的功能中,Dumbo 试图通过拍打他的耳朵来飞翔的序列可能包括两个关键帧:一个是 Dumbo 耳朵朝上的帧,另一个是耳朵朝下的帧。
  2. 然而,将动画限制在这两帧会使序列看起来非常不稳定(或者使 Dumbo 看起来像蜂鸟一样飞)。为了创建一个更平滑的动画序列,关键帧被交给一个“中间者”,一个低级别的动画师,他将使用第一个和最后一个关键帧作为参考来绘制所需的中间帧。这个过程被称为补间。
  3. 完整的序列将被着墨、着色和对齐。以每秒 24 帧的速度回放,每幅画之间的过渡看起来很流畅,创建了一个无缝的动画。

今天,你是主动画师,浏览器扮演中间人的角色。创建一个好的 CSS3 动画就是为浏览器提供完整的关键帧,这些关键帧具有足够的信息来在它们之间平滑地进行补间。在补间时,浏览器必须做出许多假设。糟糕的动画通常是由于没有为样式表提供足够的元素信息,或者做出了与 CSS3 内置的假设相反的假设。

image 注意根据屏幕上的运动速度,如果大约每 50 毫秒显示一个新帧,动画序列就会平滑播放。遵循 CSS 的原则,动画模块不试图定义回放速率或每秒显示的帧数(FPS)。所有 CSS 动画都是由状态( a 状态)或一个序列需要多长时间(之前的时间和 a 状态之后的时间)定义的。剩下的就交给浏览器或客户端了。您完全可以优化您的 CSS 声明,以减少浏览器的负载并创建更高效的动画,但是您不能“逐帧”创建您的序列(除了可能的步骤过渡,在第三章中讨论),并且您不能定义帧速率。

CSS3 关键帧动画语法

关键帧动画总是以动画名称开始,该名称与 id 值一样,必须是唯一的。如果两个关键帧序列具有相同的名称,则只会识别最后一个。动画序列本身可以用两种方式指定。第一个是作为一个from ... to声明,如清单 5-1 所示。

清单 5-1简单的从左到右动画的关键帧

@keyframes slide {
from { left: 0; }
to {left: 100%; }
}

动画也可以指定为时间百分比,如清单 5-2 所示。

清单 5-2 。?? 一个复杂动画的多个关键帧

@keyframes multislide {
0% { left: 20px; }
20% { right: 200px; }
80% { left: 50px; }
100% { right: 180px; }
}

如果您没有在动画声明中明确定义开始或结束状态(from/0%to/100%)),浏览器将从元素的初始或最终状态进行插值。您还可以在声明中创建关键字和值的混合,如清单 5-3 所示。

清单 5-3 。 混合了关键词和百分比值的关键帧序列

@keyframes multislide {
20% { right: 200px; }
80% { left: 50px; }
to { right: 180px; }
}

因为它只描述了两种状态,所以在清单 5-1 中显示的 CSS 动画语法产生了一个本质上等同于过渡的结果,尽管动画方法仍然保留了一些优于过渡序列的优点,你很快就会看到。

实际上,关键帧序列可以写在 CSS 中的任何地方,但是我建议在大多数情况下将它们放在样式表的顶部,与任何@font-face声明放在一起,以便于参考。您可能希望将很长的序列放在样式表的底部(以避免它们碍事),或者甚至将它们作为一个单独的。css 文件(通过@import<link>), although this adds a separate HTTP request.进入你的页面)

通过对一个元素应用单独的 CSS 属性来调用 CSS 关键帧动画序列,如清单 5-4 所示。

清单 5-4 。 调用 CSS 关键帧动画序列

#redbox {
background-color: red;
width: 100px; height: 150px;
animation-name: slide;
animation-duration: 5s;
animation-timing-function: ease-in;
}

正如你所看到的,这些属性(除了animation-name之外)非常类似于第三章中介绍的那些过渡,并且它们具有非常相同的功能。一个区别是animation-duration可以设置为 infinite 关键字,而不是以秒或毫秒为单位的时间。动画模块也有animation-delay属性,增加了animation-iteration-countanimation-direction, animation-play-stateanimation-fill-mode

该动画也可以在单个animation快捷方式属性中调用,如清单 5-5 所示。

清单 5-4 。 用快捷方式调用 CSS 关键帧动画序列

#redbox { animation: slide 5s ease-in 2s; }

动画值可以以任何顺序声明,除了durationdelay值,必须先声明duration,后声明delay

支持旧浏览器中的关键帧动画

旧的浏览器需要厂商前缀,正如已经讨论过的过渡。这很复杂,因为@keyframes声明也需要前缀,如清单 5-6 所示。

清单 5-6 。 调用旧 Webkit 浏览器的 CSS 关键帧动画序列

@-webkit-keyframes multislide {
0% { left: 20px; }
20% { right: 200px; }
80% { left: 50 %; }
100% { right: 180px; }
}
#bluebox {
width: 100px; height: 150px;
-webkit-animation-name: multislide;
-webkit-animation-duration: 10.5s;
-webkit-animation-timing-function: ease-in-out;
-webkit-animation-delay: 200ms;
}

这种重复显然是在你为支持其他旧版本浏览器而写的时候积累起来的;第十章中讨论的一些工具可以简化和自动化这个过程。

控制关键帧动画回放

如果您尝试回放您创建的动画,您将看到元素重置为其初始状态。如果希望元素在最后一帧停止,有几种选择。

  • 为元素设置一个长的animation-duration,让它永远到达最后一帧。
  • 设置animation-direction,使元件在同一位置缠绕。
  • animation-fill-mode设置为forwards

animation-fill-mode的名字很奇怪,但是它有一个特殊的用途,如表 5-1 所示。

表 5-1。动画填充模式属性值

填充模式 描述
forwards 元素位置在最后一帧结束。
backwards 元素返回到第一帧的位置。
both 将元素设置为页面加载时第一个关键帧的位置,而不考虑元素在其他 CSS 中的默认位置。仅当animation-delay 的值大于 0 时适用。
none 元素在关键帧之外由 CSS 提供的初始默认位置开始和结束。

您也可以使用animation-direction返回动画序列,如表 5-2 所示。

表 5-2。动画方向属性值

动画方向 描述
normal 动画正常向前播放
alternate 动画向前播放,然后反向播放,返回到其初始位置
reverse 动画向后播放
alternate-reverse 动画在第一次播放时向后播放,第二次播放时反向正常播放

混合和链接关键帧动画

合并多个关键帧动画与合并转场非常相似,如清单 5-7 所示。

清单 5-7 。 在一个元素上混合多个关键帧动画

@keyframes lefttoright {
0% { left: 0; }
100% { left: 800px; }
}
@keyframes toptobottom {
0% { top: 0; }
25% { top: 100px; }
50% { top: 0; }
75% { top: 100px; }
100% { top: 0; }
}
#box { background: red; width: 100px; height: 100px; position: absolute;
animation-name: lefttoright, toptobottom;
animation-duration: 4s, 2s;
animation-timing-function: ease-in, ease-in-out;
}

组合这两个动画序列的绘制结果如图 5-1 所示。

9781430247227_Fig05-01.jpg

图 5-1。一个合并的 CSS3 动画

这个动画可以通过保持相同的关键帧但改变它们的持续时间来改变,如清单 5-8 所示。

清单 5-8 。 一个通过改变关键帧持续时间而改变的合并 CSS3 动画

#box { background: red; width: 100px; height: 100px; position: absolute;
animation-name: lefttoright, toptobottom;
animation-duration: 3s, 6s;
animation-timing-function: ease-in, ease-in-out;
animation-fill-mode: both;
}

结果如图图 5-2 所示。

9781430247227_Fig05-02.jpg

图 5-2。改变动画时长值后元素的移动

也可以通过在关键帧动画序列之间引入延迟来“链接”它们,如列表 5-9 和图 5-3 所示。

清单 5-9 。 CSS3 连锁动画序列

#box { background: red; width: 100px; height: 100px; position: absolute;
animation-name: lefttoright, toptobottom;
animation-duration: 3s, 6s;
animation-timing-function: ease-in, ease-in-out;
animation-delay: 0s, 3s;
animation-fill-mode: both;

}

9781430247227_Fig05-03.jpg

图 5-3。设置动画延迟值后元素的移动

您将在 CSS3 动画模块中使用所有这些功能的组合来创建复杂的动画,如下一节中描述的弹跳球和图像幻灯片。

重复动画序列

增加迭代次数允许动画重复多次。使用infinite关键字可以将动画设置为无休止地重复播放。例如,无限动画可以用来创建一个永无止境的弹跳球(见图 5-4 )。

9781430247227_Fig05-04.jpg

图 5-4。来自动画弹跳球序列的截图

为了创建一个真实的橡胶球,你需要同时完成几个视觉效果:当球接触到它下面的理论表面时,它应该在反弹之前稍微“挤压”(使用在第四章中讨论的挤压和拉伸原理),而当球升到空中时,它下面的阴影变得更加分散,并远离撞击点。要增加额外的真实感,您可以为某些关键帧插入单独的缓动功能。(本动画来源于tym pus . net/CoDrops/2012/05/22/creating-an-animated-3d-bounding-ball-with-css3/的 CoDrops 原创作品,经许可使用。)参见清单 5-10 。

清单 5-10 。 CSS 使用挤压和拉伸动画原理制作一个无休止重复的弹跳球

@keyframes ballbounce {
 0% { top: 0;
 	animation-timing-function: ease-in; }
 50% { top: 140px; height: 140px;
 	animation-timing-function: ease-out;}
 55% { top: 160px; height: 120px; border-radius: 50 % / 60px;
 	animation-timing-function: ease-in;}
 65% { top: 120px; height: 140px; border-radius: 50 %;
 	animation-timing-function: ease-out;}
 95% { top: 0; animation-timing-function: ease-in;}
 100% { top: 0;animation-timing-function: ease-in;}
}
@keyframes shadowshrink {
 0% { bottom: 0;
 	margin-left: -30px;width: 60px;height: 75px;
 	background: rgba(20, 20, 20, .1);
 	box-shadow: 0px 0 20px 35px rgba(20,20,20,.1);
 	border-radius: 30px / 40px;
 	animation-timing-function: ease-in;}
 50% {bottom: 30px;
 	margin-left: -10px;width: 20px;height: 5px;
 	background: rgba(20, 20, 20, .3);
 	box-shadow: 0px 0 20px 35px rgba(20,20,20,.3);
 	border-radius: 20px / 20px;
 	animation-timing-function: ease-out;}
 100% { bottom: 0;
 	margin-left: -30px;
 	width: 60px;
 	height: 75px;
 	background: rgba(20, 20, 20, .1);
 	box-shadow: 0px 0 20px 35px rgba(20,20,20,.1);
 	border-radius: 30px / 40px;
 	animation-timing-function: ease-in;}
}
#ball {
 width: 140px;
 height: 140px;
 border-radius: 70px;
 background: rgb(187,187,187);
 background: linear-gradient(to bottom,
 	rgba(187,187,187,1) 0%,rgba(119,119,119,1) 99 %);
 box-shadow: inset 0 -5px 15px rgba(255,255,255,0.4),
 	inset -2px -1px 40px rgba(0,0,0,0.4), 0 0 1px #000;
 animation: ballbounce 1s infinite;
}
#shadow {top: 280px;
 width: 60px;
 height: 75px;
 box-shadow: 0px 0 20px 35px rgba(20,20,20,.1);
 border-radius: 30px / 40px;
 transform: scaleY(.3);
 animation: shadowshrink 1s infinite;}
#ball, #shadow { position: absolute; top: 0; }
#shadow { left: 65px; }
#wrapper { position: relative; width: 200px; margin: 40px auto; }
<div id = wrapper>
<div id = shadow > </div>
<div id = ball > </div>
</div>

正如你所看到的,通过合并和同步多个 CSS 动画序列,你可以在 HTML 元素中创建复杂的、真实的运动。

暂停关键帧动画

可以通过更改animation-play-state属性的值来暂停动画。在清单 5-9 和 5-10 的代码中,可以添加清单 5-11 中的代码。

清单 5-11 。 暂停一个 CSS3 动画

#wrapper:hover #ball, #wrapper:hover #shadow  {
animation-play-state: paused;
}

因为animation-play-state的默认值是running,所以当鼠标从悬停在包装器 div 上移开时,动画将恢复。正如你将在第六章中看到的,完全可以通过其他方式设置runningpaused状态。

摘要

利用关键帧的 CSS3 动画为网页上的 HTML 元素提供了更多的动画机会,比通过过渡创建的 HTML 元素有更多的变化。虽然为旧的浏览器构建前缀支持可能是一个有些艰难的过程,但基本的语法使 CSS3 动画更加有效和有趣。虽然许多属性与过渡模块有共同之处,但animation-fill-mode 却非常不同:虽然受 CSS3 过渡影响的元素通常会返回到它们的初始状态,但对于成熟的动画来说,这样做是不常见的,需要小心处理animation-directionanimation-fill-mode

在下一章中,您将使用在这里学到的语法来创建 web 内容的高级动画,包括图像幻灯片。

六、Web 内容的 CSS3 关键帧动画

正如您在上一章中看到的,CSS 动画模块的语法比过渡语法更强大,允许通过使用关键帧来更好地控制 web 内容。本章将通过几个例子来说明这种能力:一个循环幻灯片,一个复制 JavaScript 经典 Lightbox 插件外观的图库,以及一个徽标动画。

一个简单的 CSS3 幻灯片演示

传统上,图片库幻灯片效果是使用 Flash 或 JavaScript 创建的,通常以框架插件的形式出现,如 Nivo Slider ( http://nivo.dev7studios.com)和 Camera ( www.pixedelic.com/plugins/camera)。虽然使用框架/插件方法有很多优势(主要是在可用的各种过渡方面),但是在 CSS3 中完成幻灯片也有很多优势,稍后您将会看到。

HTML 代码

标记 CSS3 幻灯片的图像是一个相当简单的过程:你将图像放入一个容器中,该容器作为一个条带穿过另一个“窗口”元素,该元素与条带中的每个图像大小相同(参见图 6-1 )。

9781430247227_Fig06-01.jpg

图 6-1。CSS 幻灯片的组织(红色“窗口”容器被放大以示强调)

在代码中,这是使用清单 6-1 中的创建的,在接下来的例子中会添加更多的标记,

清单 6-1 。 HTML 代码为一个基本的 CSS3 幻灯片

<div id=slideshow>
    <figure id=imagestrip>
        <img src=black-kite.jpg alt="Photograph of a Black kite">
        <img src=red-kite.jpg alt="Profile of a Red kite">
        <img src=pelicans.jpg alt="Pelicans on moorings at sea">
        <img src=pariah-kite.jpg alt="Photograph of Pariah kite">
    </figure>
</div>

在本例中,您有四个 400 像素高、500 像素宽的图像,因此内部容器的总宽度必须为 2000 像素。(注意,所有图像的大小必须完全相同;示例中的图片由 Challiyil Eswaramangalath Pavithran Vipin、Ariful H Bhuiyan、Márcio Cabral de Moura 和 Alan Saunders 根据知识共享协议授权使用。

清单 6-2 中显示的基本 CSS 同样简单明了:

清单 6-2 。CSS 3 幻灯片图像库的基本 CSS 代码

div#slideshow { position: relative; background: #000; overflow: hidden; }
figure#imagestrip, div#slideshow { box-sizing: border-box; }
div#slideshow, figure#imagestrip img { width: 500px; height: 400px; float: left; }
figure#imagestrip { position: absolute; width: 2000px; margin: 0; }

要创建最简单的滑块动画,您必须以 500 像素的增量水平移动内部图形,每次移动后都有一个停顿,以便观众有时间欣赏每张图片。正如我在前一章中讨论的,CSS3 动画不能在显式帧中工作。您必须将动画视为时间的一部分:为每个图像指定相等的时间,在此期间它将保持静止,剩余时间指定为运动。在这个例子中,每个图像在 20%的时间里是静止的,而整个带在 20%的时间里是运动的,分为四个序列。因此,每次间隙移动将占用总时间的 5%。

写入关键帧时要记住的重要部分是,如果你想保持它们相同,你改变的属性必须作为多个关键帧之间的设定值出现;否则,浏览器将使用您不希望它使用的值恢复到插值。

你对关键帧声明的第一次尝试可能看起来类似于清单 6-3 。

清单 6-3 。 简单图像滑块的关键帧

@keyframes slider {
  0%  { transform: translateX(0px); }
  20% { transform: translateX(0px); }
  25% { transform: translateX(−500px); }
  45% { transform: translateX(−500px); }
  50% { transform: translateX(−1000px); }
  70% { transform: translateX(−1000px); }
  75% { transform: translateX(−1500px); }
  95% { transform: translateX(−1500px); }
 100% { transform: translateX(−2000px); }
}

然后你调用动画序列。与过渡不同,关键帧动画不需要启动事件,这意味着该动画将在页面加载时运行,如清单 6-4 所示。

清单 6-4 。 简单图像滑块的关键帧

figure#imagestrip { animation: slider 10s infinite; }

您会发现这是可行的,但只有一个问题:最后一次移动显示了一个空窗口,因为没有超过 2000 像素的图像用于显示图像条。您可以通过引入一点小技巧来解决这个问题,将第一个图像的副本放在条带的末尾,在我们的 CSS 中将整个条带延长到 2500 像素(清单 6-5 )。

清单 6-5 。修改了一个基本 CSS3 幻灯片的 HTML 代码

<div id=slideshow>
    <figure id=imagestrip>
       <img src=black-kite.jpg alt="Photograph of a Black kite">
        <img src=red-kite.jpg alt="Profile of a Red kite">
        <img src=pelicans.jpg alt="Pelicans on moorings at sea">
        <img src=pariah-kite.jpg alt="Photograph of Pariah kite">
        <img src=black-kite.jpg alt="Photograph of a Black kite">
    </figure>
</div>

由于最后一个关键帧现在在视觉上与第一个匹配,这就创建了一个完整平滑的动画序列。

背景图像的变化

您可以仅使用背景图像来创建等效的效果,例如,在横幅元素或徽标后面创建幻灯片显示。这将把您的代码简化为一个单独的<figure>,但是会使您的 CSS 有些复杂。(请注意,您将在背景列表的末尾重复第一幅图像,就像您在上面的示例中所做的一样,原因也是一样的。参见清单 6-6 。)

清单 6-6 。 HTML 和 CSS 代码为一个滑块使用背景图片

<style>
figure#imagestrip { width: 500px; height: 400px;
background: #000; box-sizing: border-box;
 background-image: url(black-kite.jpg), url(red-kite.jpg), url(pelicans.jpg),← url(pariah-kite.jpg), url(black-kite.jpg);
 background-repeat: no-repeat;
 background-position-x: 0, 500px, 1000px, 1500px, 2000px;
 animation: slider 20s infinite;
}
@keyframes slider {
  0%  { background-position-x: 0, 500px, 1000px, 1500px, 2000px; }
  20% { background-position-x: 0, 500px, 1000px, 1500px, 2000px; }
  25% { background-position-x: -500px, 0px, 500px, 1000px, 1500px, 2000px; }
  45% { background-position-x: -500px, 0px, 500px, 1000px, 1500px, 2000px; }
  50% { background-position-x: -1000px, -500px, 0px, 500px, 1000px, 1500px; }
  70% { background-position-x: -1000px, -500px, 0px, 500px, 1000px, 1500px; }
  75% { background-position-x: -1500px, -1000px, -500px, 0px, 500px, 1000px; }
  95% { background-position-x: -1500px, -1000px, -500px, 0px, 500px, 1000px; }
  100% { background-position-x: -2000px, -1500px, -1000px, -500px, 0px, 500px; }
}
</style>

<figure id=imagestrip></figure>

您还可以创建一个包含多个背景图像的容器元素,并通过一个可见的“窗口”移动它,或者为背景创建一个将所有图像连接在一起的图像。后一种方法会使 CSS 变得更容易,但也会使以后更改图库变得更加困难。

暂停幻灯片放映

允许用户暂停滑块来聚焦一张图片是合理的。启动这样一个动作最简单的方法是滑块本身上的一个hover;同时,您应该在幻灯片上放置一个视觉标识符,以清楚地表明它处于暂停状态。对于这个例子,我将通过淡化imagestrip元素并在屏幕上放置一个替代暂停图标的文本作为伪元素(我也可以使用一个图像文件)来实现。所有的变化都是对 CSS 的补充,如清单 6-7 所示。

清单 6-7 。 CSS 代码悬停时暂停一个图库幻灯片

div#slideshow:hover figure#imagestrip { animation-play-state:paused; opacity: 0.5; }
div#slideshow:hover:before {
content: "||"; font-size: 200px;
color: rgba(255,255,255, 0.7);
position: absolute;
left: 160px; top: 80px;
}

注意,您可以通过在内部的figure元素(比如transition: 1s opacity linear)上放置一个适当的转换来缓和暂停状态的可视标识符。

改变图像之间的过渡

最终,滑块图库中的每个图像之间有许多种可能的淡入淡出和擦除方式,下面将展示其中的几种。

淡入淡出

在简单的水平或垂直爬行之后,滑块最常见的过渡是让每个图像按顺序淡入/淡出黑色。在不改变标记的情况下,你可以淡出图像条,在它是黑色的时候移动图像条“在黑暗的掩护下”,然后作为一个整体再次淡入图像条,如清单 6-8 所示。

清单 6-8 。 CSS 代码悬停时暂停一个图库幻灯片

@keyframes slider {
  0%  { transform: translateX(0); }
  20% { opacity: 1; }
  22% { opacity: 0; transform: translateX(0); }
  23% { opacity: 0; transform: translateX(−500px);  }
  25%,   45%  { opacity: 1; }
  47% { opacity: 0; transform: translateX(−500px); }
  48% { opacity: 0; transform: translateX(−1000px); }
  50%,   70%  { opacity: 1; }
  72% { opacity: 0; transform: translateX(−1000px); }
  73% { opacity: 0; transform: translateX(−1500px); }
  75%, 95%  { opacity: 1; }
  97% { opacity: 0; transform: translateX(−1500px);  }
  98% { opacity: 0; transform: translateX(−2000px); }
 100% { opacity: 1; transform: translateX(−2000px); }
}

请注意,我对具有相同属性的关键帧进行分组的方式与对普通 CSS 选择器进行分组的方式相同。然而,通常情况下,您会希望让动画上的调用更长,以防止它显得匆忙。我建议使用animation: slider 20s infinite

Because the other images in the strip are not visible during the fade sequences, you can drop the final duplicate image on the end of the slider div, running it back to the beginning in complete darkness before starting the animation again. That will not be possible in the next example.

运动过程中的淡入淡出

通过在图像从左向右移动的过程中淡出图像,您可以保留带有淡出效果的滑块效果。虽然在单个关键帧动画中完全可以做到这一点,但最简单的方法可能是将代码创建为同时运行的两个序列。

为了实现这一点,你恢复到你原来的滑块关键帧序列,现在运行超过 30 秒,并添加一个新的fader关键帧声明(见清单 6-9 )。

清单 6-9 。 CSS 代码悬停时暂停一个图库幻灯片

@keyframes slider {
    0%  { transform: translateX(0px); }
    20% { transform: translateX(0px); }
    25% { transform: translateX(−500px); }
    45% { transform: translateX(−500px); }
    50% { transform: translateX(−1000px); }
    70% { transform: translateX(−1000px); }
    75% { transform: translateX(−1500px); }
    95% { transform: translateX(−1500px); }
    100% { transform: translateX(−2000px); }
}
@keyframes fader {
    0% { opacity: 1; }
    70% { opacity: 1; }
    90% { opacity: 0; ease-out; }
    95% { opacity: 0; }
    100% { opacity: 1; ease-in; }
 }

figure#imagestrip { width: 2500px;
animation: slider 30s infinite, fader 7.5s infinite; }

计时背后的原理很简单:动画总长度为 30 秒,幻灯片中的每个图像将在屏幕上完全显示 6 秒(动画时间的 20%),并在 1.5 秒内移动到左边(总时间的 5%)。通过循环播放第二个动画,使imagestrip元素在接近结束时淡出超过 7.5 秒,您可以合并这两个动画以获得平滑的结果。

交叉路径〔??〕

要实现交叉渐变效果,您有三个选项,但在所有情况下,图像不再作为“条带”放置,而是一个叠一个,最上面的图像依次淡出。

第一个也是最简单的选择是简单地将每个背景图像设置为一个空的(但大小正确的)元素的关键帧(见清单 6-10 )。

清单 6-10 。 CSS 代码为一个交叉渐变图像滑块

@keyframes imageswap {
    0% { background-image: url(black-kite.jpg);  }
    20% { background-image: url(red-kite.jpg);  }
    40% { background-image: url(pelicans.jpg);  }
    80% { background-image: url(pariah-kite.jpg);  }
    100% { background-image: url(black-kite.jpg);  }
}

这将简单容易地在图像之间交叉渐变;然而,它可能不会给你想要的结果或控制程度。另一种方法是使用交叉渐变滤镜将图像带到页面上,如清单 6-11 所示。

清单 6-11 。 一个交叉渐变图像滑块的替代 CSS 代码

@keyframes slider {
    0%  { background-image: url(black-kite.jpg); }
    20% { background-image: cross-fade(url(black-kite.jpg), url(red-kite.jpg),0%); }
    25% { background-image: cross-fade(url(black-kite.jpg), url(red-kite.jpg),100%); }
    45% { background-image: cross-fade(url(red-kite.jpg), url(pelicans.jpg),0%); }
    50% { background-image: cross-fade(url(red-kite.jpg), url(pelicans.jpg),100%); }
    70% { background-image: cross-fade(url(pelicans.jpg), url(pariah-kite.jpg),0%); }
    75% { background-image: cross-fade(url(pelicans.jpg), url(pariah-kite.jpg),100%); }
    95% { background-image: cross-fade(url(pariah-kite.jpg), url(black-kite.jpg),0%); }
   100% { background-image: cross-fade(url(pariah-kite.jpg), url(black-kite.jpg),100%); }
}

第三种选择,使用“真实”图像,稍微复杂一些:最上面的图像必须淡出,然后在返回前景之前延迟。(想象一副牌,在第一张牌被放入弃牌堆一段时间之前,上面的牌和下面的牌之间发生了过渡。)CSS 变成了清单 6-12 中所示的样子。

清单 6-12 。 第三个选项 CSS 代码为交叉渐变图像滑块

@keyframes slider {
    0%, 25% { opacity: 1;  }
    30%, 100% { opacity: 0;  }
}
figure#imagestrip {
    width: 500px; height: 400px;
    background: #000; box-sizing: border-box; overflow: hidden;
    position: relative;
}
figure#imagestrip img { position: absolute; top: 0; left: 0; }

HTML 也会改变;注意,在新代码中,我已经将图像按照相反的顺序放置了(清单 6-13 )。绝对定位,图中的最后一个图像将在顶部。(或者,您可以在每个上放置一个内联的z-index属性)。

清单 6-13 。 第三选项交叉渐变图像滑块的 HTML 代码

<figure id=imagestrip>
<img src=black-kite.jpg alt="Photograph of a Black kite">
<img src=pariah-kite.jpg alt="Photograph of a Pariah kite" style="animation: slider 10s 7.5s infinite;">
<img src=pelicans.jpg alt="Pelicans on moorings at sea "style="animation: slider 10s 5s infinite;">
<img src=red-kite.jpg alt="Photograph of a Red kite" style="animation: slider 10s 2.5s infinite;">
<img src=black-kite.jpg alt=" Photograph of a Black kite" style="animation: slider 10.1s 0s infinite;">
</figure>

由于关键帧序列中的每个图像在动画长度的四分之一中是“实心”的,并且整个动画的长度为 10 秒,因此对关键帧的每个后续调用都会额外延迟总时间的四分之一。提供给第一遍(黑风筝的动画)的额外时间是为了使照片的返回不会“踩到”在图形开始处的淡入淡出。

添加字幕

您可以像在前面的图像过渡示例中一样,为幻灯片添加标题。标记如清单 6-14 中的所示。

清单 6-14 。 带标题的图片滑块的 HTML 代码

<div id=slideshow>
  <figure id=imagestrip>
      <figure>
         <img src=black-kite.jpg alt="Black kite">
        <figcaption>Black kite</figcaption>
      </figure>
  <figure>
    <img src=red-kite.jpg alt="Red kite">
    <figcaption>Red kite</figcaption>
  </figure>
  <figure>
      <img src=pelicans.jpg alt=Pelicans>
      <figcaption>Pelicans</figcaption>
    </figure>
    <figure>
        <img src=pariah-kite.jpg alt="Pariah kite">
        <figcaption>Pariah kite</figcaption>
    </figure>
  </figure>
</div>

向清单 6-2 和 6-3 添加清单 6-15 中所示的标记。

清单 6-15 。 CSS 代码给图片滑块添加标题

figure#imagestrip figure figcaption {
    position: absolute; background: rgba(0,0,0,0.4);
    color: #fff; width: 500px; padding: 8px;
    font-size: 18px; top: -42px;
    transition: 1s top linear;
   }
figure#imagestrip:hover { animation-play-state:paused; }
figure#imagestrip figure:hover figcaption { top: 0; }

暂停的点击方法

您也可以使用前面讨论的label方法来创建一个暂停幻灯片动画的替代方法,方法是在开始<div>之后添加如清单 6-16 所示的代码以及相关的 CSS。

清单 6-16 。 HTML 和 CSS 代码添加一个点击暂停到一个图像滑块

<input type=checkbox id=pause><label for=pause></label>

label {
    display: block; z-index: 24; transition: 0.3s all ease-in-out;
}
input:checked ∼ figure#imagestrip {
    animation-play-state:paused;
}
input#pause:checked ∼ label {
    background: rgba(0,0,0,0.4);
}
input#pause:checked ∼ label:before {
    content: "||"; font-size: 200px;
    color: rgba(255,255,255, 0.5);
    position: relative;
    left: 160px; top: 80px;
}

虽然以上是一个选项,但如果您选择使用它,请记住本章前面讨论的可访问性问题。

为旧版本的 Internet Explorer 创建后备

声明的overflow: hidden部分将被 Internet Explorer (IE) 9 和早期版本读取和遵循,尽管关键帧动画不会。这将模糊其他图像,意味着 IE 10 版之前的用户将看不到它们。这可以通过一个条件注释来避免,这个条件注释将图像的可见性传递给那些用户,如清单 6-17 所示。(请注意,IE 6、7 和 8 将需要 JavaScript 和稍微多一点的 CSS,以便浏览器识别 HTML5 元素,例如在第九章中讨论的<figure>。)

清单 6-17 。 有条件的 CSS 使图片在早期版本的 IE 中可查看

<!--[if lte IE 9]>
div#slideshow { overflow: visible; }
<![endif]-->

对文本使用字幕动画的警告

标签有着漫长而惨淡的历史,可以追溯到早期版本的 Internet Explorer。在 90 年代后期,<marquee>从来不是一个标准化元素,也不是任何 HTML 规范的一部分,它通常被用来为网页上的文本创建一种滚动的“滚动条”效果。除了在非常特殊的情况下,<marquee>和动画 gif 和闪烁的文字一起,成为了糟糕的网页设计的标志之一。

虽然天真的设计者可能会尝试使用这些技术来制作文本爬行动画,但是应该避免使用它们。撇开设计趋势不谈,字幕文字有许多可用性问题:

  • 人类视觉系统被运动所吸引,并且字幕文本处于不断的运动中;字幕功能在页面上非常容易分散注意力。
  • 出于同样的原因,字幕文本可能很难阅读,尤其是对于有视觉障碍的用户。
  • 在字幕文本中包含链接会让糟糕的想法变得更糟:链接很难跟踪和点击。当字幕文本循环移动时,错过一个链接意味着如果用户第一次错过它,就必须等到该链接的下一次出现,这是非常令人沮丧的。因此,出现在字幕中的任何重要链接也应该以静态形式出现在网页上。

新闻字幕/通知动画

在本节中,您将使用 CSS3 动画创建一个新闻提示序列,而不是使用 marquee 来制作文本动画。每个新的通知将堆积在页面的右下角,显示一段时间后消失。用户应该能够单击每个通知以获取更多信息,每个面板的剩余时间将显示在进度条中。(参见图 6-2 。)

9781430247227_Fig06-02.jpg

图 6-2。【CSS3 驱动的新闻收报机

对此的标记相当简单:通知是包含在一个更大的div中的div元素,每个进度条是一个内部带有spandiv,如清单 6-18 所示。

进步元素呢?

HTML5 有显示进程时间的标记:<progress>元素。虽然您可以按照自己的方式设置 progress 元素的样式,但是您不能使用 CSS 来修改标记中可视化显示的进度(这就是 JavaScript)。这样的任务超出了本章的范围,因为我们尽可能对每个特性都使用 CSS3,所以在这种情况下使用它并不合适。

清单 6-18 。CSS3 驱动的定时通知系统的 HTML

<div id=breaking-news>
    <div class=notification><a href=#><span></span>Rain expected</a>
    <div class=progress><span></span></div>
</div>

<div class=notification><a href=#><span></span>Travel plans changed</a>
    <div class=progress><span></span></div>
</div>

<div class=notification><a href=#><span></span>Light snow</a>
    <div class=progress><span></span></div>
    </div>
</div>

样式化通知的基本 CSS 如清单 6-19 所示。

清单 6-19 。 CSS 为一个通知告警序列

div#breaking-news {
    position: fixed; bottom: -20px; right: 15%;
}
div.notification {
    position: relative; width: 275px; border-radius: 10px;
    background: linear-gradient(rgb(215,215,215), rgb(165,164,169));
    padding: 60px 20px 40px; border: 2px solid #999;
    margin-top: 10px;
    box-shadow: 3px 3px 6px rgba(0,0,0,0.1) inset, 0 0 6px 2px rgba(0,0,0,0.1);
    opacity: 0.9;
}
div.notification a {
    color: white; text-stroke: 1px solid #000;
    text-decoration: none; font-family: Futura, sans-serif; font-size: 20px;
}
div.notification a span {
    font-size: 60px; padding-right: 20px; vertical-align: middle;
}
div.progress {
     height: 5px; border-radius: 2px; border: 1px solid #999;
     margin-top: 32px; background: rgb(215,215,215);
}
div.progress span {
    background: #000; display: block; width: 0; height: 3px;
}

有三个动画序列:popup,驱动每个通知向上;progress,显示剩余时间;还有fade,让每一个通知都在最后淡去。这些都显示在清单 6-20 的中。

清单 6-20 。 CSS 为一个通知告警序列

@keyframes popup {
0%, 30% { height: 0; padding: 0 20px; display: none; }
}
@keyframes fade {
     100% { opacity: 0; }
}
@keyframes progress {
     100% { width: 100%; }
}

请注意,您对这些关键帧序列采用了一种稍微不同的方法:因为元素的默认状态已经在清单 6-20 中定义了,所以您仅使用关键帧来定义从状态(在弹出的情况下)或从状态(在进度和淡入淡出的情况下)的。浏览器将根据需要自动在这些值和默认的嵌入、内嵌和链接样式之间进行补间。只有在您的@keyframes声明中包含 0%和 100%的值时,您才能控制元素的整个外观(不考虑animation-fill-mode)。

所有通知弹出窗口共享相同的动画,除了为每个弹出窗口初始化动画之前的延迟。有效地使用你的 CSS 意味着你应该在一个声明中放尽可能多的相似的 CSS,如清单 6-21 所示。

清单 6-21 。 从单个共享声明中调用关键帧序列

div.notification {
...
    animation-name: popup, fade;
    animation-duration: 2s, 1s;
    animation-timing-function: cubic-bezier(0.325, 0.730, 0.695, 1.650);
    animation-fill-mode: backwards, forwards;
    animation-delay: 2s, 14s;
}

没有任何矛盾的陈述,每个通知面板将继承清单 6-21 中的所有样式,但是动画延迟是你必须为每个改变的一件事(见清单 6-22 )。

清单 6-22 。 为后续通知面板设置不同的动画延迟值

div.notification:nth-child(2) {
animation-delay: 6s, 18s;
}
div.notification:nth-child(3) {
animation-delay: 12s, 24s;
}

你对每个面板的进度条采取类似的方法(清单 6-23 )。

清单 6-23 。为进度条设置不同的动画延迟值

div.progress span {
       background: #000; display: block; width: 0; height: 3px;
       animation: progress 12s 4s forwards linear;
       }
div.notification:nth-child(2) div.progress span { animation-delay: 6s; }
div.notification:nth-child(3) div.progress span { animation-delay: 12s; }

自然,在现实世界中,用纯 CSS3 手工制作每个通知需要花费大量的精力。正如你将在第九章中看到的,你可以使用这里的工作基础来巧妙地整合 JavaScript 的优势。

CSS3 中的 Lightbox 图像库等价物

Lightbox 是用于显示图库图像的第一个流行模态技术的通称:经典的 Lightbox 效果是页面的淡出,然后是页面中心图像的扩展和淡入。它的流行导致了在 web 上的过度使用,许多开发人员只是因为不熟悉或懒惰而使用代码自带的默认值。用 CSS 编写等价的内容允许开发人员根据自己的需求轻松定制图库的外观。

首先,你将使用一个非常相似的标记(清单 6-24 ),与你在第三章中的第一个图库示例中使用的标记相似。这一次你将使用由罗伯特·洛、乔恩·罗林森和卡米洛·鲁埃达·洛佩斯提供的图片,这些图片是在知识共享协议下获得许可的(图 6-3 )。

9781430247227_Fig06-03.jpg

图 6-3。CSS3-light box 等效值放大的大图

清单 6-24 。 在 CSS3 中相当于一个灯箱的 HTML

<body id=base>
<dl id=gallery>
    <dt><a href=#col1><img src=coliseum-at-night-small.jpeg alt="Coliseum at night"></a>
    <dd id=col1><a href=#><img src=coliseum-at-night.jpeg alt="Coliseum at Night" ></a>
    <dt><a href=#col2><img src=coliseum-forum-small.jpeg alt="Roman Coliseum and Forum"></a>
    <dd id=col2><a href=#><img src=coliseum-forum.jpeg alt="Roman Coliseum and Forum" ></a>
    <dt><a href=#col3><img src=grand-via-madrid-small.jpeg alt="Grand Via, Madrid, Portugal"></a>
    <dd id=col3><a href=#><img src=grand-via-madrid.jpeg alt="Grand Via, Madrid, Portugal" ></a>

</dl>

你需要dd是页面的全高和全宽来居中显示内容。要做到这一点,你将把 CSS 放在 HTML 元素本身上,这样dd就可以相对于 HTML 元素测量自己,并使用 flexbox 模块将 dd 的子元素居中(清单 6-25 )。

清单 6-25 。中的基本 CSS 为一个灯箱等效于 CSS3

html { min-height: 100%; position: relative; }
body { margin: 0; height: 100%; margin-right: 2em;  }
dl#gallery { float: left; }
dl#gallery  dt { width: 150px; }
dl#gallery dd {
    margin-left: 0; background: rgba(0,0,0,0);
   position: absolute; top: 0; bottom: 0;
    width: 100%; height: 100%;
    display: box; box-pack:center; box-align:center;
    visibility: hidden;
}
dd a { background: #fff; display: block; transition: 4s all ease-in; }

请注意,如果页面明显超出浏览器窗口的底部,这种方法有一个潜在的缺点,因为这种 CSS 将导致图像始终垂直居中于正文内容的高度。

为了展开并显示dd元素,您将使用一个关键帧序列来制作图像动画,并通过过渡dd ( 清单 6-26 )的背景来淡化页面。

清单 6-26 。 为灯箱效果的关键帧序列

@keyframes blowup {
    0% { width: 0;  height: 0; opacity: 0;  }
    30% { width: 640px; height: 0; opacity: 0;  }
    60% { width: 640px; height: 480px; opacity: 0; margin: 20px; }
    100% { width: 640px; height: 480px; opacity: 1; margin: 20px; }
}
dd:target {
    visibility: visible; background: rgba(0,0,0,0.6);
    transition: 2s background linear;
}
dd:target a { box-shadow: 0 0 8px 8px rgba(0,0,0,0.3); }
dd:target a img { animation: blowup 3s forwards; }

通过将dd的内容链接到bodyid,点击图像将重新定位浏览器并撤销动画。

添加字幕

向 Lightbox CSS3 代码添加标题有几个选项。第一个给现有代码添加了一个最小量,作为span元素(清单 6-27 )。效果如图图 6-4 所示。

9781430247227_Fig06-04.jpg

图 6-4。对于一个大的 CSS 灯箱图片,鼠标经过时的标题

清单 6-27 。 为灯箱效果的关键帧序列

<dl id=gallery>
<dt><a href=#col1><img src=coliseum-at-night-small.jpeg alt="Coliseum at night"></a>
<dd id=col1><a href=#><img src=coliseum-at-night.jpeg alt="Coliseum at Night">
<span>Coliseum at Night</span></a>
<dt><a href=#col2><img src=coliseum-forum-small.jpeg alt="Roman Coliseum and Forum"></a>
<dd id=col2><a href=#><img src=coliseum-forum.jpeg alt="Roman Coliseum and Forum">
<span>Roman Coliseum and Forum</span></a>
<dt><a href=#col3><img src=grand-via-madrid-small.jpeg alt="Via Grand, Madrid, Spain"></a>
<dd id=col3><a href=#><img src=grand-via-madrid.jpeg alt="Grand Via, Madrid, Portugal">
<span>Grand Via, Madrid, Portugal</span></a>
</dl>

通过将 CSS 添加到dd容器中,使其成为position: relative并将span绝对定位在其中,您可以在悬停时转换标题(清单 6-28 )。

清单 6-28 。 灯箱图库标题的 CSS

dl#gallery {
float: left; font-family: Futura, Arial, sans-serif; margin-bottom: 12em;
}
dl#gallery dd {
margin-left: 0; background: rgba(0,0,0,0);
position: absolute; top: 0; bottom: 0;
width: 100%; height: 100%;
display: box;  box-pack:center; box-align:center;
visibility: hidden;
}
dl#gallery dt { width: 150px; margin: 2em 2em 0 2em; }
dd:target { visibility: visible; background: rgba(0,0,0,0.6); transition: 2s background linear; }
dl#gallery dd a { background: #fff; display: block; text-decoration: none; }
dl#gallery dd a span {
display: block; background-color: rgba(0,0,0,0.3); color: white;
position: absolute; top: 20px; left: 20px;
padding: 10px; opacity: 0;
transition: 1s opacity ease-in;
}
dl#gallery dd a:hover span { opacity: 1;  }
dl#gallery dd:target a img { animation: blowup 3s forwards; }
dl#gallery dd:target a {
box-shadow: 0 0 8px 8px rgba(0,0,0,0.3);
transition: 4s all ease-in;  position: relative;
}

CSS3 也可用于在页面加载时制作公司标志动画(见图 6-5 )。当我们谈到响应式设计时,我会进一步探讨这个话题(第九章)。只播放一次动画是很重要的:循环播放的动画会分散观众的注意力。

9781430247227_Fig06-05.jpg

图 6-5。页面加载时添加到公司徽标的标题

页面加载上的徽标动画

由于虹膜组件不会被动画化,只有虹膜作为一个整体,你通常会创建一个图像标志(可能是一个 SVG 矢量文件)。为了便于说明,我们将使用纯 CSS 来制作它。(参见清单 6-29 。)

清单 6-29 。 HTML 标记为企业标志

<div id=container>
<span id=iris1></span>
<span id=iris2></span>
<span id=iris3></span>
<span id=iris4></span>
<span id=iris5></span>
<span id=iris6></span>
<span id=iris7></span>
<span id=iris8></span>
<div id=iris>
</div>
</div>
<h1>Avid <span>Laboratories</span></h1>

为此,您可以添加 CSS 来创建徽标的虹膜部分,并设置文本样式(清单 6-30 )。

清单 6-30 。 基本 CSS 为企业 Logo

div#container span {
display: block; width: 100px; border: 7px solid white;
height: 32px;
position: absolute; top: 90px; left: 90px;
background-color: #333;
transform-origin: top right; z-index: -4;
}
div#iris {
border-radius: 50%; border: 30px solid #fff;
width: 200px; height: 200px; position: relative;
}
div#container span#iris1 { transform: translate(−35px, 55px) rotate(0deg);  }
div#container span#iris2 { transform: translate(−70px, 90px) rotate(45deg); }
div#container span#iris3 { transform: translate(−130px, 70px) rotate(90deg); }
div#container span#iris4 { transform: translate(−160px, 20px) rotate(135deg); }
div#container span#iris5 { transform: translate(−145px, -35px) rotate(180deg); }
div#container span#iris6 { transform: translate(−95px, -60px) rotate(225deg); }
div#container span#iris7 { transform: translate(−45px, -45px) rotate(270deg); }
div#container span#iris8 { transform: translate( −20px, 5px) rotate(315deg); }
h1 {
font-family: "Univers LT 55"; text-transform: uppercase; font-size: 80px;
letter-spacing: 10px; position: absolute; top: 10px; left: 150px;
text-align: left; line-height: 50px;
}
h1 span {
font-family: "Univers CE 45 Light"; font-size: 25px; display: block;
letter-spacing: 20px; text-indent: 30px;
}

最后,你可以创建动画(清单 6-31 )。

清单 6-31 。 用于企业标志动画的关键帧序列

@keyframes spinner {
0%   {
    transform: translate(800px,-25px) rotate(378deg); opacity: 0; }
    100% { transform: translate(2px,-25px) rotate(−56deg); opacity: 1; }
}
div#container {
    position: relative; width: 200px; height: 200px;
    animation-name: spin;
    animation-duration: 2s;
    transform: rotate(−18deg);
    animation: spinner 1.5s 2s linear both;
}

请注意,您没有将动画附加到任何特定的状态,因此关键帧动画将在页面加载时自动运行。

摘要

在这一章中,你已经探索了如何使用 CSS3 关键帧为图片库和其他页面内容创建动画。关键帧序列可以包括任何形式的需要随时调用的复杂运动:鼠标点击、页面加载或其他形式的用户交互。

到目前为止,我在动画中还没有解决的一个问题是显示可伸缩性:序列中的元素越大,浏览器和 GPU 就越难对它们进行转换、过渡和动画制作。此外,位图图像占总页面大小的很大一部分,降低了连接速度,尤其是在移动设备上。图像也不能很好地适应缩放:将显示基于位图的作品的屏幕的 DPI 加倍会导致图像质量下降。

在下一章中,您将看到所有这些问题的一个潜在答案,以 SVG 矢量图形与 CSS3 集成的形式。

七、将 CSS3 动画与 SVG 和滤镜集成

每个支持 CSS 变换、过渡和动画的浏览器还支持 SVG(可缩放矢量图形),这是一种长期以来被大多数 web 开发人员忽略的图像格式。在被 Internet Explorer (IE)忽略了十年之后,SVG 正在经历一场复兴,IE9 和所有其他现代浏览器都支持它,这使它非常适合部署在移动开发和其他用例中。正如您将在本章中看到的,CSS3 转场和关键帧可以很好地与 SVG 集成。

本章后半部分讨论的过滤器对 CSS 来说是新的,但在 SVG 中是标准化的。事实上,CSS 过滤器直接源自 SVG 标准。滤镜允许对 HTML 内容(尤其是图像)进行实时和交互式的可视化编辑,这在以前只能在 PhotoShop 中实现。作为一个 CSS 属性,滤镜可以很容易地被动画化,就像其他任何东西一样。

SVG 简介

SVG 是一种开放的、基于 XML 的格式。这个事实允许在普通的文本编辑器和几乎任何 web 开发语言中创建和修改 SVG 数据。SVG 支持它自己的渐变、交互性、文本和层,但是对于我们的目的来说,最重要的特性是这种格式描述了矢量形状。这意味着 SVG 图像可以缩放到任何大小或分辨率,或者以任何方式转换,而不会有任何质量损失。这种格式提供了基于文本的矢量信息描述,这一事实也使得 SVG 文件相对较小:例如,一个简单的 UI(用户界面)形状(如播放按钮)可以在 SVG 中描述为三个点和一种填充颜色,而不是单独定义的像素。这使得这种格式具有自然的响应性,非常适合移动设计、高 DPI 显示和 CSS 操作。

例如,考虑一个 UI 播放按钮元素。简化到绝对最小值,描述这种形状的 SVG 代码可能类似于清单 7-1 。

清单 7-1 。?? 一个简单的 SVG 文件

<svg version="1.1" FontName1">http://www.w3.org/2000/svg">
<polygon points="0,0 0,400 200,200 "/>
</svg>

SVG 数据可以直接在浏览器中查看。用文件名play.svg保存清单 7-1 中的代码,并将其加载到浏览器窗口中,得到如图图 7-1 所示的可视化结果。

9781430247227_Fig07-01.jpg

图 7-1。浏览器中显示的 SVG 播放按钮

注意,SVG 多边形元素使用点来描述形状,类似于 imagemaps。最终,显示器必须将 SVG 元素呈现为像素,默认情况下,为多边形指定的点将映射到屏幕上的像素。(默认情况下,您的播放按钮将在浏览器中显示为 400 像素高、200 像素宽,并位于屏幕的最左上角。)最终,SVG 元素的最终呈现尺寸是任意的:按钮可以呈现为一英里高(如果您的屏幕足够大)或两厘米宽(例如,在打印的页面上),除了所有其他因素,质量是相同的。

同样,与 imagemaps 一样,为 SVG 手工编写所有代码通常效率不高。对于许多任务,您会发现使用绘图应用并将结果导出为 SVG 文件要容易得多。(我将很快讨论这些工具。)

将 SVG 放在网页上

在 HTML 页面上放置 SVG 文件有三种主要方法:作为图像引用、内嵌在页面上(也称为嵌入式 SVG)和作为对象引用。

SVG 作为内嵌图像

web 开发人员最熟悉的将 SVG 元素放入网页的方法是使用<img >标签。在你这样做之前,你的 SVG 代码必须包含更多关于其“自然”大小的信息(同样,保持代码绝对最小),如清单 7-2 所示。

清单 7-2 。 SVG 代码准备作为图片插入到网页上

<svg version="1.1" FontName1">http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<polygon points="0,0 0,400 200,200 " fill="rgba(90,70,80,0.5)" />
</svg>

属性指定了一个 400×400 像素的“画布”。CSS 中没有为图像元素指定宽度或高度,当 SVG 元素作为标准 HTML 的图像放在页面上时,它为自己保留了 400 × 400 像素的“空间”,如清单 7-3 所示。

清单 7-3 。?? 一个 SVG 元素作为图像插入到网页上

<img src=svg/play.svg alt=Play>

您也可以在 CSS 中通常使用图像的任何地方引用 SVG 作为图像——例如,作为元素的背景(清单 7-4 )。

清单 7-4 。 在 CSS 中应用 SVG 作为背景图片

h1 { background: url(svg/wave.svg); }

虽然以这种方式引用外部 SVG 文件是最简单和最常见的方法,但它确实有几个缺点:

  • SVG 文件仅被视为图像;代码中编写的任何交互或脚本都将被忽略。
  • 您不能“深入”SVG 代码,使用 CSS 直接改变元素的外观,这种自由度与内联 SVG 相同。

线 SVG〔??〕??㎡线

如果直接在页面上嵌入 SVG 数据,就需要在 SVG 代码中包含更多的信息。你需要提供元素的宽度和高度,要么作为属性(viewBoxwidthheight属性),要么作为样式(见清单 7-5 )。

清单 7-5 。 内嵌 HTML 应用 SVG

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title > SVG Embedded File Example</title>
</head>
<body>
<h1 > Standard content</h1>
<svg version="1.1" FontName1">http://www.w3.org/2000/svg" style="width: 200px; height: 400px">
<polygon points="0,0 0,400 200,200"  />
</svg>
</body>
</html>

内联 SVG 节省了一个额外的 HTTP 请求,这对于移动页面尤其重要,因为移动页面普遍存在延迟。与简单地将文件作为图像引用相比,其他优点是能够用 CSS 直接影响 SVG 的外观。还支持与 SVG 的脚本交互。

内联 SVG 的主要缺点是它向 HTML 页面添加了更多的代码。

SVG 作为对象或 iframe 添加

将 SVG 作为对象或 iframe 添加到 web 页面是最古老的方法,在这种方法中,脚本交互性保留在元素内部(清单 7-6 )。

清单 7-6 。 SVG 作为对象或 iframe 应用于网页

<object type="image/svg + xml" data="icon.svg">
Warning for older browsers, or alternative content
</object>

<iframe src="icon.svg">
Warning for older browsers, or alternative content
</iframe>

然而,作为一个<object><embed >标签应用,定制 SVG 元素外观的能力被最小化了。如果 SVG 内容溢出了它的容器,那么<object >或<embed >标签也可能和滚动条一起出现。

用 CSS 操作 SVG

正如可以用几种不同的方法将 SVG 放在网页上一样,也可以用几种不同的方法来处理 SVG 元素的外观。SVG 有自己的原生语法来实现某些视觉效果,这使得事情变得更加复杂。

在最简单的层面上,当 SVG 元素作为图像放在页面上时,您可以调整它的大小,如清单 7-7 所示。

清单 7-7 。 内联 CSS 用于调整 SVG 元素的大小

<img src=play.svg alt=Play style="width: 50px; height: 50px">

您还可以从嵌入或链接的样式表中改变元素的外观,就像您为任何其他类型的图像编写表示规则一样。(由于这个原因,页面上使用的 SVG 元素通常被赋予一个id属性。)

你可以在 SVG 文件中改变 SVG 形状的填充颜色,使用fill(见清单 7-8 )。(注意fill可以接受 CSS 中使用的任何颜色值:关键字、十六进制、rgb 或 hsl)。

清单 7-8 。 填充属性用于给一个 SVG 多边形元素着色

<polygon points="0,0 0,400 200,200 " fill="red" />

您还可以使用 SVG 文件中的嵌入样式表来更改填充颜色(清单 7-9 )。

清单 7-9 。 用嵌入的样式表修改 SVG 元素的外观

<svg version="1.1" FontName1">http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<style type="text/css">
polygon { fill: blue; }
</style>
<polygon points="0,0 0,400 200,200" />
</svg>

最后,如果 SVG 文件直接嵌入到您的页面中,您也可以通过 CSS 来实现这一点(清单 7-10 )。

清单 7-10 。使用嵌入的样式表修改内联 SVG 元素的外观

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title > SVG Embedded File Example</title>
<style>
polygon { fill: red; stroke: black; stroke-width: 9px;  }
</style>
</head>
<body>
<svg version="1.1" FontName1">http://www.w3.org/2000/svg" style="width: 200px; height: 400px">
<polygon points="10,19 10,390 190,200"  />
</svg>
</body>
</html>

请注意,这并不意味着您可以像您所希望的那样,神奇地为任何 HTML 元素提供新的 stroke 或 fill 属性。这些属性专门应用于 SVG 内容。

您还可以检测 SVG 元素上的悬停,并改变 SVG 内容的外观作为响应(清单 7-11 )。

清单 7-11 。SVG 元素上的 CSS 悬停检测

polygon { fill: red; stroke: black; stroke-width: 9px;  }
polygon:hover { fill: black; }

注意,对按钮使用内嵌 SVG 有一个很小但很重要的优点:悬停的“热点”区域正好是多边形的形状。在标准位图图像上,无论图像的形状如何,该区域总是矩形的。

这意味着您也可以转换这些效果,就像您可以转换受 CSS 影响的任何其他元素一样。为了使 CSS 更加清晰和具体,我在 polygon 元素中添加了一个id,并在我的样式中这样处理,如清单 7-12 中的所示。(请注意,我还将多边形从边缘“向内”移动了一点,因为 stroke 添加到了形状的外部,就像 CSS border 添加到 HTML 元素一样。如果没有这一点,笔画的尖端将被 SVG“画布”的边缘切断,因为它延伸到它们之外)。

清单 7-12 。?? 一个 SVG 元素上的 CSS 过渡

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title > SVG Embedded File Example</title>
<style>
#play { fill: red; stroke: black; stroke-width: 9px;  transition: 1s all linear; }
#play:hover { fill: black; stroke: black; stroke-width: 9px;  }
</style>
</head>
<body>
<svg version="1.1" FontName1">http://www.w3.org/2000/svg" style="width: 200px; height: 400px">
<polygon id="play" points="10,19 10,390 190,200"  />
</svg>
</body>
</html>

任何可以应用于 HTML 元素的 CSS3 变换、过渡或动画也可以应用于 SVG,这使得矢量形状和 CSS 的结合非常强大。

动画 SVG 图像映射

在本练习中,您将使用 SVG 来复制 HTML imagemap UI 的功能,但是您将添加几个进化步骤:您的 SVG“image map”的各部分将屏蔽图像内容,当 CSS3 悬停在适当的区域上时,这些内容将被过渡(参见图 7-2 )。

9781430247227_Fig07-02.jpg

图 7-2。一个 SVG 图像映射

首先,您需要一个 SVG 绘图。谢天谢地,网上有大量免费的 SVG 内容:在这种情况下,我将使用 Wikimedia Commons 提供的加拿大地图。为了便于说明,我把地图编辑成了不列颠哥伦比亚省、艾伯塔省和萨斯喀彻温省。

每个省由一条路径来区分,路径以坐标字符串的形式提供。我们首先在页面中内联 SVG,并在每个路径上创建一个简单的悬停效果。结果将类似于清单 7-13 中的。

清单 7-13 。 在 SVG 图像上简单高亮显示

<!DOCTYPE html>
<html lang=en>
<head>
<meta charset=utf-8>
<title > SVG Embedded File Example</title>
<style>
path { fill: #fdfdfd; }
path:hover { fill: red; }
</style>
</head>
<body>
<svg version="1.1"  xmlns:svg=http://www.w3.org/2000/svg
FontName1">http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="1000px" height="600px" viewBox="0 0 1000 660">
<path id="alberta" d="M1654.393,678.219 . . .>
<path id="british-columbia" d="M982.854,27.912l150.51,33.221c17.. . .>
. . .
</svg>

为了实现蒙版效果,你要在每条路径后嵌入每张“透明”图片,然后将路径转换成剪辑路径。您将通过引用图像的适当剪辑路径的 id 将元素关联在一起,并用<g>将元素分组在一起。

SVG 图像的开始代码,包括阿尔伯塔省的路径,看起来类似于清单 7-14 。

清单 7-14 。图像的 SVG 剪辑路径

<g>
<clipPath id="ab-clipper">
    <path fill="#D3D3D3" d="M1654.393,678.219 . . .>
</clipPath>
<image clip-path="url(#ab-clipper)" height="100%" width="100%" x="800" y="50"
xlink:href="lake-louise.jpeg" preserveAspectRatio="xMidYMin slice" />
</g>

clipPath在其中定义路径,作为引用clipPath id的元素的遮罩,就像lake-loise.jpe g 图像一样。图像元素被交叉链接到与地图相同位置的位图图片。图像被设置为其完整的“自然”宽度和高度,并在 x 和 y 轴上移动,直到它与路径位于相同的位置。(您可能需要将链接设置为剪辑路径,作为您对图像采取的最后一个操作;否则,当图像被遮盖并且可能不可见时,您将玩一个关于图像位置的猜谜游戏。

现在你已经创建了一个蒙版位图图像。显示这部分地图的 CSS(清单 7-15 )很简单。

清单 7-15 。 CSS 在一个 SVG 元素中显示悬停时的剪辑图像

svg image { opacity: 0; transition: 400ms opacity ease; }
svg image:hover { opacity: 1; }

只有一个问题:裁剪路径是不可见的,这意味着在你的地图上有一个阿尔伯塔省大小的缺口。悬停效果有效,但是如果您将相同的效果应用到其他省份路径,用户将看不到他们的鼠标移动到哪里。一旦变成剪贴画,路径上的填充就没用了。你可以整天改变颜色,永远看不到任何不同。

解决方案是在代码中的剪辑路径和图像之间放置一个路径的填充副本,如清单 7-16 所示。

清单 7-16 。 添加了复制填充路径的 SVG 中可见的裁剪区域

<g>
<clipPath id="ab-clipper">
       <path fill="#D3D3D3" d="M1654.393,678.219 . . .>
</clipPath>
<path fill="#FF0000" d="M1654.393,678.219\. . . />
<image clip-path="url(#ab-clipper)" height="100%" width="100%" x="800" y="50"
xlink:href="wheat.jpeg" preserveAspectRatio="xMidYMin slice" />
</g>

位图图像(由 Kenny Louie 创作,在 Creative Commons: http://flickr.com/photos/kwl/3102355428下授权)仍然不可见,但它被渲染在复制路径的“上方”,因此当用户将鼠标悬停在复制路径填充的区域上时,它仍然会显示。

最后一步是链接 SVG 图像中的每个区域。链接位于 SVG 文件本身的每个组内部,并且需要使用xlink名称空间(清单 7-17 )。

清单 7-17 。SVG 中的链接裁剪图像

<g>
<a xlink:href="http://www.hellobc.com/">
<clipPath id="bc-clipper">
    <path d=" M982.854,27.912l150.51,33.221c17.. . .>
</clipPath>
<path id="british-columbia" d="M982.854,27.912l150.51,33.221c17.. . .>
<image clip-path="url(#bc-clipper)" height="100%" width="100%" x="80" y="50"
xlink:href="false-creek.jpeg" preserveAspectRatio="xMidYMin slice" />
</a>
</g>

请注意,链接的区域沿着路径的边缘,就像真实的图像映射一样,并且过渡发生在同一区域内。

SVG 雪花动画

矢量形状的可伸缩性意味着您可以使用不同大小的 SVG 元素的多个副本,而不必担心图像质量。我将通过为季节性背景场景制作矢量雪花动画来演示这一点。(为此,我将使用在http://upload.wikimedia.org/wikipedia/commons/5/50/Snow_flake.svg. See Figure 7-3从维基共享下载的稍加修改的 SVG 雪花。)

9781430247227_Fig07-03.jpg

图 7-3。静止来自一个 SVG 飘落雪花动画

首先,您要将雪花作为多个图像放在页面上。雪花将有不同的大小,并将在不同的位置开始,但它们将共享相同的动画特征:它们将从天空落下,在微风中横向漂移。(参见清单 7-18 。)

清单 7-18 。 SVG 雪花作为图片放置在页面上

<img src="snowflake.svg" alt="" class="flake" style="top: -50px" >
<img src="snowflake.svg" alt="" class="flake" style="left: 200px; width: 60px; height: 60px; top: -120px;" >
<img src="snowflake.svg" alt="" class="flake" style="left: 640px; width: 120px; height: 120px; top: -400px;" >

接下来,您将应用 CSS 通过渐变创建冬天天空的效果,并为雪花创建基本大小。同时,您将调用两个关键帧序列:一个是在雪花向底部下落时旋转雪花(称为雪),另一个是将雪花从一边飘到另一边(漂移)。(参见清单 7-19 。)

清单 7-19 。 基础 CSS 为雪花动画

html { min-height: 100%; }
body { height: 100%; background: linear-gradient(#b5d3ff, #30509a); }
img.flake { width: 150px; height: 150px; position: relative;
animation: snow 8s linear infinite forwards,
drift 12s ease-in-out forwards infinite; }

关键帧序列以不同的长度运行,每个雪花从不同的高度开始(清单 7-20);这种组合创造了随机循环运动的印象。

清单 7-20 。 为雪花动画的关键帧序列

@keyframes snow {
   100% { top: 700px; transform: rotate(2.2turn);  }
}

@keyframes drift {
    0% { left: -5px; }
    25% { left: 55px; }
    55% { left: -15px; }
    100% { left: 0px; }
}

这是可行的,但是如你所见,有两个问题。首先,要添加更多雪花,需要在标记中添加更多图像,这很快就会变得很累。第二个问题是,较小的雪花会被解释为距离更远,因此从屏幕底部落下需要更长的时间(在这个例子中,我们假设它的高度为 700 像素)。你可以通过使用添加的具有不同动作计时的类来调用雪花,如清单 7-21 所示。

清单 7-21 。 通过创建二级类来减缓动画

img.flake { width: 150px; height: 150px; position: relative;
    animation: snow 8s linear infinite forwards,
    drift 12s ease-in-out forwards infinite;
}
img.slow {
    animation: snow 16s linear infinite forwards,
    drift 24s ease-in-out forwards infinite;
}

分开的类意味着较慢的雪花可以通过调用两个类来控制。创建更多的变化意味着创建更多的类,这又回到了添加更多雪花的问题上。当你在第九章开始整合 JavaScript 和 CSS3 动画时,你会解决这个问题。

用于 SVG 的工具

目前,广泛使用 SVG 的最大障碍之一是设计工具的相对缺乏。最受欢迎的包括:

  • Adobe Illustrator 有一个 SVG 导出选项,但是,与许多所见即所得工具一样,它创建的代码并不十分高效:生成的 SVG 文件通常包含远远多于所需的代码。
  • 开源软件 Inkscape ( http://inkscape.org/)与 Adobe Illustrator 面临同样的问题。然而,Inkscape 确实有处理本地 SVG 文件的优势,它支持 SVG 过滤器。
  • Raphaë是一个小型的 JavaScript 库,可以在 JavaScript 中轻松创建和操作 SVG。

CSS3 滤镜简介

CSS 过滤器允许在网页内容出现之前对其进行处理。最常见的(但绝不是唯一的),这些过滤器适用于位图图像。滤镜极大地改变了典型的 web 开发图像制作工作流程:设计师可以从 PhotoShop 中优化和导出图像,而不是永久地“烘焙”图像像素中的视觉效果,这将保持相对不变,将视觉变化留给 CSS。

这意味着图像可以在 CSS 中动态修改,而不是必须在 PhotoShop 中重新编辑原始图像,导出它们,然后重新上传到服务器。这也意味着这些效果可以被动画化。

黑白/灰度滤镜过渡

灰度滤镜效果非常适合在线作品集或照片库。CSS 滤镜可以轻松地将彩色图像转换为黑白图像,而不是使用复杂的 JavaScript 或 Flash 解决方案。你可以在悬停时撤销这种转换,并附加一个过渡以缓解两种状态之间的转换,如图 7-4 中所示的图像(由 Andrew Larsen 在www.flickr.com/photos/papalars/4013594219创作,经知识共享许可)。参见清单 7-22 。

9781430247227_Fig07-04.jpg

图 7-4。用 CSS(左)过滤的彩色图像(右)

清单 7-22 。应用灰度滤镜过渡

img { border: 20px solid #fff; box-shadow: 10px 10px 8px rgba(0,0,0,0.3); }
img.bw { filter: grayscale(1); transition: 1s filter linear; }
img.bw:hover { filter: grayscale(0); }

<img src=lake-louise.jpg alt="Lake Louise, Alberta, Canada" class=bw>

和我在本章中描述的其他滤镜一样,灰度滤镜采用介于 0(无效果)和 1(全效果)之间的值,浮点值介于两者之间。请注意,您不能平稳地过渡到“无”或未应用过滤器的状态;必须给过滤器一个新值。

棕褐色滤镜过渡

棕褐色滤镜可以用来创建一个“老化”的照片效果,如图图 7-5 (应用于 Robb North 的一张照片,www.flickr.com/photos/robbn1/3650713106)。

9781430247227_Fig07-05.jpg

图 7-5。用 CSS(左)过滤的彩色图像(右)

实现图 7-5 所示效果的代码与灰度非常相似(见清单 7-23 )。

清单 7-23 。在图像上过渡棕褐色滤镜的 CSS

img { border: 20px solid #fff; box-shadow: 10px 10px 8px rgba(0,0,0,0.3); }
img.old { filter: sepia(1); transition: 1s filter linear; }
img.old:hover { filter: sepia(0); }

<img src=barn.jpg alt="Old barn" class=old>

虽然图 7-5 中的谷仓照片之前已经在图像编辑器中处理过,添加了“风化”和部分晕影外观,但你只使用 CSS 为图像提供了棕褐色调。其他效果也可以用 CSS 添加。

显影宝丽来照片效果

通过用div包围图像并制作应用于容器元素的样式的动画,可以将滤镜和带有inset值的box-shadow组合起来,重新创建正在显影的宝丽来照片的外观。保存在里面的图像需要使用z-index被“推回”,这样div的内嵌内阴影就会覆盖它(见清单 7-24 )。

清单 7-24 。用宝丽来效果转换图像

div.polaroid { float: left; border: 25px solid #f3f4e3; border-bottom-width: 45px;
box-shadow: 0 0 200px 200px rgba(29,25,4,1) inset;
filter: sepia(.8);  transition: 3s all ease-in;  }
div.polaroid img { position: relative; z-index: -1; }
div.polaroid:hover { filter: sepia(.2); box-shadow: 0 0 50px 0 rgba(29,25,4,0.2) inset }

<div class="polaroid" > <img src="barn.jpg" alt="Photograph of an old barn" > </a>

模糊滤镜过渡

模糊滤镜需要小心使用;过度使用它们会使网站难以阅读或互动。模糊是为数不多的不采用 0 到 1 之间的值的滤镜之一。相反,它使用长度测量来设置模糊量。(参见图 7-6 ,其中使用了 Louise Docker 的另一幅知识共享图像www.flickr.com/photos/aussiegall/6311469113 .)

9781430247227_Fig07-06.jpg

图 7-6。使用 CSS 模糊(左)过滤的彩色图像(右)

请注意,模糊效果会延伸到整个图像,包括边框和阴影。通过使边框和阴影成为第二个父元素(如div)的属性,可以限制模糊的程度。(参见清单 7-25 。)

清单 7-25 。将模糊滤镜应用于图像

img { border: 20px solid #fff; box-shadow: 10px 10px 8px rgba(0,0,0,0.3); }
img.old { filter: blur(2px); transition: 1s filter linear; }
img.old:hover { filter: blur(0px); }

摘要

SVG 和滤镜是可以添加到 CSS 动画中的两个最强大的功能。SVG 允许无分辨率的过渡和动画,而过滤器允许快速的客户端视觉图像处理。

SVG 十几年了;CSS 滤镜是全新的。两者都立即受到你用它们创造的东西是单一的这一事实的限制:你的创造不能立即被重复。在屏幕上制作一个元素的动画很容易,您可以重用该动画来制作另一个元素的动画,但是每个新元素都必须单独创建。

您可以使用 JavaScript 来简化、增强和改变您的 CSS3 动画和过渡,轻松地复制动画元素并制作新的动画,您将在下一章中探索这一功能。

八、将 CSS3 动画与响应式网页设计和 JavaScript 整合

现在是时候把你到目前为止看到的所有元素放到你的网页上了。要做到这一点,你需要将 CSS3 转换、过渡和动画与当前的网站开发原则相结合,包括响应式网页设计(RWD) 。

在基本层面上,一个响应式网站将由一个流动的设计组成,大多数元素以百分比、rememvhvw单位来衡量,而不是像素,结合一系列在 CSS 媒体查询中定义的 CSS 断点。这些断点的位置通常由浏览器宽度(更准确地称为视窗)改变时页面设计“中断”的值来定义。为了方便起见,这些值通常用像素来度量,尽管有很好的理由用 rems 或 ems 来度量,以尽可能脱离“屏幕尺寸”的概念

使用响应式 web 设计原则设计网站,可以让访问者在使用各种设备访问网站时获得流畅、连续和不间断的体验:桌面浏览器、平板电脑、手机和其他设备。

在设计失败的宽度处指定断点是一个很好的做法,而不是使用最新 iPhone 或 iPad 型号的显示尺寸。移动设备变化很快,智能手机和平板电脑的种类比大多数人意识到的要多得多,尤其是在 Android 市场。让网站响应与你的设计相关的尺寸要比今年技术的任意分辨率好得多。

在每个断点处,您指定布局中的更改:元素被调整大小或重新定位,以及出现或消失。一个移动优先的理念颠倒了典型的开发过程:从一开始你就为小屏幕(水平分辨率为 320 像素或更低)设计一个站点,并随着视窗的扩大调整页面,让站点有更多的空间“呼吸”Mobile first 的优势在于,在大多数移动设备的空间和带宽都非常有限的情况下,它可以让你集中精力开发网站绝对需要的功能。

image 注意一般来说,移动用户在使用桌面浏览器时,应该拥有完全相同的工具、导航和网站功能。在响应站点中为移动用户删除一个特性之前,考虑一下这个组件是否是必需的。

许多 web 开发人员纯粹从@media查询的角度考虑响应式 web 设计。虽然查询是一个非常重要的组件,并且将是这里的重点,但重要的是要理解许多响应式解决方案将需要 JavaScript 和 PHP 等服务器端解决方案的额外贡献(通常称为 RESS:响应式设计+服务器端组件)。

在这一章中,我将重点介绍如何使用 CSS 动画来简化响应页面中断点之间的转换。应该注意的是,虽然设计师们喜欢这个东西——你可能会发现自己不断地来回拖动浏览器窗口的右下角来欣赏你将要创造的效果——但你的许多用户永远不会看到它。大多数访问者在访问网站时,浏览器的宽度是固定的,并且在整个访问过程中保持不变,尤其是移动用户,他们没有改变视窗大小的选项。因此,你将在本章中探索的许多技术应该被认为是“最好拥有”的,而不是必需的。

在这一章的后面,你将会看到 JavaScript 如何与 CSS3 动画和过渡集成,以使它们更加有效和高效。

在无过渡的响应式网页设计中调整元素大小

使用我上面讨论的原则,您可以在调整视窗大小时“动画化”网页内容,而根本不需要使用过渡或关键帧动画。

动态调整图像和视频的大小

首先,你将根据视窗大小调整图像和视频的大小(见图 8-1 )。

9781430247227_Fig08-01.jpg

图 8-1。页面内响应图像的两种状态

通过相对于元素的容器调整元素的大小,您可以在调整浏览器窗口大小时平滑地“激活”元素的大小。严格来说,这根本不是动画。在这个阶段,你只是通过相对于它的容器缩放来动态地调整图像的大小(见清单 8-1 )。

清单 8-1。 一个有求必应的形象

html { font-size: 62.5%; } 
p { font-size: 1rem; }
.left { max-width: 100%; height: auto; float: left; margin-right: 2rem; margin-bottom: 1rem; }
<section>
<p><img src="pentacon-bike.jpg" alt="Pentacon Bike" class="left">Lorem ipsum dolor sit amet. . .
</section>

当用户调整浏览器大小时,他们会有图像(由 filtran,www.flickr.com/photos/filtran/2978448269/)被动态调整大小的印象。如果浏览器设置得足够宽,照片将以其自然大小显示,但会缩放以适应无法包含其完整尺寸的视窗宽度。

这种方法有两个可能的缺点:根据图像相对于正文文本的初始原始大小,图像可能在大或小的屏幕宽度下显示超出比例。或者,可以将图像设置为其容器宽度的百分比,以便它在整个视口范围内缩小。例如,假设您已经确定段落的整体尺寸为 900 像素宽,每个尺寸(文本行)为 90 个字符。给定 HTML 和段落的表示规则,这意味着 section 元素的宽度等于 90rem。图像的自然大小为 425 像素宽。要使图像完全可缩放,您需要将所有这些值转换为百分比:

425 / 900 = 0.4722

这意味着图像占据了段落宽度的 47.22%,并转化为你在清单 8-2 中看到的 CSS。

清单 8-2 。 一个交替反应的形象

section { max-width: 90rem; }
.left { width: 47.22%; height: auto; float: left; margin-right: 2.5%; margin-bottom: 2%; }

CSS 声明的这种组合将创建如图 8-2 所示的页面外观。

9781430247227_Fig08-02.jpg

图 8-2。备选响应图像

剩下的一个问题是在极端的视口尺寸下创建非常大或非常小的图像的可能性。你可能希望通过设置图像的最小和最大尺寸来保护设计(见清单 8-3 )。

清单 8-3 。 具有最小和最大尺寸的响应式图像

.left { width: 47.22%; height: auto; float: left;
    margin-right: 2.5%; margin-bottom: 2%;
    max-width: 425px; min-width: 150px;
}

您可以使用相同的技术在<video>元素上实现相同的效果。(通过 YouTube 或 Vimeo 等服务嵌入视频时,让视频变得有响应性要复杂得多;我推荐 Dave Ruppert 在http://fitvidsjs.com/的 FitVids JQuery 插件来实现这一点。

image 提示不使用关键帧、过渡或媒体查询也可以动态调整文本大小。vw单位测量视窗宽度:1vw是浏览器窗口宽度的 1/100 th 。因此,如果视口宽度为 400 像素,1vw将等同于4px。当浏览器调整大小时,您可以使用此单位来缩放文本:

h1 { font-size: 4vw; }

有了这个 CSS,网页上的 h1 元素会随着浏览器的伸缩而调整大小。你也可以在其他元素上使用 vh 和 vw。

响应背景图像

通过使用background-size属性(这里使用的是 Vinoth Chandar 在www.flickr.com/photos/vinothchandar/6168933212/的一幅图像),你可以很容易地动态调整背景图像的大小,以响应视窗的变化,如清单 8-4 所示。

清单 8-4 。 一幅有求必应的背景图像

html, body { min-height: 100%; font-size: 62.5%; }
body { background-image: url(fog.jpg); background-size: cover; } 

结合一些正文,这给出了如图 8-3 所示的效果。

9781430247227_Fig08-03.jpg

图 8-3。有反应的背景图像

有关“过渡”背景图像的其他方法,请参见第三章。

使用过渡调整响应式网页设计中元素的大小

在@media 查询断点之间转换元素是完全可能的。从设计的角度来看,需要注意的主要问题是元素在调整视窗大小时可能会在不同状态之间“跳跃”,这可能会让用户感到惊讶。

让我们创建一个设计,在页面中间有一个大的 h1 元素,在一张照片的上面(清单 8-5 )。

清单 8-5 。 用于响应背景图像和过渡文本的 HTML

body { background-image: url(fog.jpg); background-size: cover;
     background-repeat: no-repeat; color: #fff; font-family: Avenir, Arial, sans-serif;
}
h1 { font-family: 'Calluna Sans', Arial, sans-serif; text-align: center;
      font-size: 10rem; margin: 8rem auto;
}

随着视窗变窄,标题文本会自然地在空格处断开,如图图 8-4 所示。

9781430247227_Fig08-04.jpg

图 8-4。一个无响应的标题元素在一个狭窄的视口下的空间上断开

相反,如果我们想让标题保持在一行,我们可以减小断点处的文本大小,并在它们之间转换,如清单 8-6 所示。

清单 8-6 。 用于响应背景图像和过渡文本的 HTML

h1 { font-family: 'Calluna Sans', Arial, sans-serif;
    text-align: center; font-size: 10rem; margin: 8rem auto; transition: 1s font-size linear; 
}
@media screen and (max-width: 1100px) { 
        h1 { font-size: 8rem; } 
} 
@media screen and (max-width: 900px) { 
        h1 { font-size: 7rem; }
} 
@media screen and (max-width: 800px) { 
        h1 { font-size: 6rem; } 
}

清单 8-6 中的代码给出了如图图 8-5 所示的结果。

9781430247227_Fig08-05.jpg

图 8-5。响应式标题元素

用 CSS3 媒体查询和过渡指示视窗大小

使用媒体查询,您可以在浏览器变窄时触发元素的外观“变形”——例如,在响应页面中显示不同的查看模式,以便用户了解他们不是在移动平台上查看桌面站点的简单解释,而是在查看根据浏览器窗口的大小进行自我定制的页面(参见图 8-6 )。

9781430247227_Fig08-06.jpg

图 8-6。三种不同状态的响应转换符号,代表三种不同的视窗尺寸

首先,您将设置一系列断点:

  • 120em 宽及以上将被视为“宽屏”。
  • 在 80em 宽的情况下,你可以假设用户正在用平板电脑浏览网站。
  • 在 40em 及以下,你应该假设用户正在使用智能手机。

接下来,您将创建用于从纯 CSS 中显示这些不同状态的元素。总共有三个元素:一个包含div的元素,它有一个绝对位置,将所有的元素保持在屏幕的右上角;一个span代表显示器,另一个span代表底座或按钮,如清单 8-7 中的所示。

清单 8-7 。 响应页面中转换显示模式的 HTML 代码

<div id="viewingmode">
        <span id="display"></span>
        <span id="buttonbase"></span>
</div>

接下来,您将为清单 8-8 中的元素创建基本 CSS。这将包括过渡设置。

清单 8-8 。 CSS 代码创建响应式设计中的查看模式符号

* { box-sizing: border-box; }
body { font-family: Avenir, sans-serif; margin: 100px 0; }
#viewingmode {
    width: 150px; height: 150px; background: rgba(0,0,0,0.2); 
    position: absolute; top: 0; right: 0; text-align: center;
}

/* screen, in default widescreen presentation */

#display {
    width: 80%; height: 50%; border: 12px solid #585858;
    border-radius: 5px; margin-top: 20px; background-color: #eee; 
}

/* base, in default monitor stand - keyboard configuration */

#buttonbase {
    width: 90px; border: 12px solid #585858; border-radius: 5px;
    position: absolute; top: 100px; left: 30px; transform-origin: 25px 5px;
}
#display, #buttonbase { display: inline-block; transition: .5s all linear; }

最后,您将创建媒体查询来改变#display#buttonbase元素的外观(清单 8-6 )。请注意,这些更改是级联的:较小的屏幕尺寸将继承在较大屏幕的媒体查询中所做的更改。

清单 8-6 。 CSS 代码创建响应式设计中的查看模式符号

@media screen and (max-width: 80em) {
    #display { width: 50%; height: 60%; border: 10px solid #585858; }
    #buttonbase { width: 8px; height: 8px; border: none; 
        border-radius: 50%; background: #fff; top: 101px; left: 70px; }
}
@media screen and (max-width: 40em) {
    #display { border-width: 23px 5px; width: 45%; height: 73%; }
    #buttonbase { top: 110px; }
}

如上所述,大多数用户——尤其是移动用户——不会看到这些动画,因为移动设备的屏幕宽度是固定的,没有什么可调整的。另一种方法可能是显示屏幕处于纵向还是横向模式,如清单 8-7 所示。

清单 8-7 。 媒体查询以在设备上显示横向和纵向模式

@media screen and (orientation: landscape) and (max-width: 80em) {
    #display { transform: rotate(90deg);    } 
   }

这就产生了你在图 8-6 中看到的变化显示,当视口根据设备的方向调整大小时,每个设备“变形”到下一个。同样的原理也可以应用于动画网页的不同方面。

为移动设备优化 CSS 过渡和动画

随着时间的推移,移动设备中的处理器不可避免地会变得更快、更强大,但它们将永远落后于全台式机型号的能力。同样不可避免的是,开发人员将倾向于在他们的鼻子前面为平台编码,而不是他们的观众可能在使用什么(正如我们在浏览器战争和供应商前缀偏见中看到的)。开发人员为他们面前的屏幕编写代码,其结果可能并不总是符合移动设备更受限制的能力。

有几种方法可以改善在移动设备上运行缓慢的 CSS 效果:

  • 尝试通过设备的 GPU 进行过渡和优化:由于其更复杂和要求更高的性质,许多浏览器会尝试通过运行 CSS 动画的设备的专门图形处理单元来平滑 3D 变换、过渡和动画(在第九章中介绍)。你可以通过一个“空的”3D 操作启动 CSS 声明块来搭这个优化流的顺风车,这个操作不会在视觉上改变元素,但会允许 GPU 访问同一个声明中的 2D 变换:

    transform: translate3d(0,0,0);
    

image 注意 Remy Sharp 在www.youtube.com/watch?v=IKl78ZgJzm4的 YouTube 上有一个非常有效的视频,展示了通过设备的 GPU 进行过渡和优化的优势。

  • 使用媒体查询限制或替换动画:您可以通过在@media查询下创建不同版本,为移动设备设置更多受限版本的动画。
  • 确保包含动画元素的页面将完全缩小到移动屏幕大小:边缘被剪掉的动画在移动设备上显然不好看或不能有效地运行。

将 CSS3 媒体查询与 SVG 集成

您还可以使用媒体查询(以及其他 CSS3 特性)来定位 SVG 中的元素。

就像 Adobe PhotoShop 和其他图形应用一样,SVG 包含了多层的概念。这意味着您可以将多个图形合并到一个 SVG 文件中,并使用 CSS 切换每个图形的可见性。

让我们回到把图标放在浏览器窗口右上角的想法,但是改为把它们做成 SVG 在这种情况下,一系列不同体型的分组 SVG 图纸,包括中胚层外胚层类型。为了节省空间,简化的清单 8-8 中只显示了第一种体型的代码。

清单 8-8 。 多个图层的 SVG 文件

<svg version="1.1" width="142px" height="340px" 
viewBox="0 0 142 340">
<style>
    g { visibility: hidden;  }
    g:target  { visibility: visible;  }
</style>
    <g id="ectomorph">
            <path d="M11.356,682.57c5.297,6.354,10.253,10.084,17.781,14.844
             C18.907,694.043,15.905,690.475,11.356,682.57z"/>
. . . .
    </g>
<g id="mesomorph">
    <path d="M9.981,679.538c0,0-8.719,7.188-8.719,17.125 . . ." />
. . . .

</g>

9781430247227_Fig08-07.jpg

图 8-7。SVG 矢量图形的不同命名层相互叠加

每个分组的 SVG 图都是一层一层的,如图 8-7 所示。然后用 CSS 隐藏这些层。如果 URL 指向某个组,嵌入样式表中的下一行将打开该组的可见性。您可以使用 CSS 将 SVG 文件作为背景图片放在div中,如清单 8-9 中的所示。

清单 8-9 。 多个图层的 SVG 文件

div#shapes { background-image: url('bodyshapes.svg#mesomorph');
position: absolute; top: 0; right: 0; width: 145px; height: 355px;  }

使用相同的定位技术,您可以交换用于div ( 清单 8-10 )背景图像的 SVG 文件中的图层的可见性。

清单 8-10 。 多个图层的 SVG 文件

@media screen and (max-width: 1000px) { 
    div#shapes { background-image: url('bodyshapes.svg#ectomorph); } 
}

最后,应该注意的是,SVG 元素可以使用<animate />元素来制作动画,如果 SVG 被直接插入到页面上,而不是被用作背景图像,那么每个层的可见性都可以使用过渡来制作动画。

用 JavaScript 触发 CSS3 转换

JavaScript 可以用来触发 CSS3 中的过渡和动画。例如,当用户到达页面底部时,你可以让元素淡入以增加他们对相关内容的兴趣(见图 8-8 )。CSS 无法检测滚动条的状态——您需要使用 JavaScript 来完成这项工作,然后使用 CSS3 将出现的元素制作成动画。

9781430247227_Fig08-08.jpg

图 8-8。用 JQuery 触发的 CSS 转换制作页脚元素动画

image 注意有一种观点认为,如果你用 JavaScript 开始制作动画,你也可以继续用同样的语言来制作动画。然而,正如在第一章中所讨论的,CSS3 过渡将会更加平滑和高效,并且将会获得比 JavaScript 更高的帧速率。JQuery Transit ( http://ricostacruz.com/jquery.transit/)和 Move.js ( http://visionmedia.github.com/move.js)等库越来越多地被用于将 JavaScript 与 CSS3 过渡和动画方法挂钩,这是有原因的。这种功能分离反映了内容、表示和行为之间的分离:在这个例子中,JavaScript 用于检测 DOM 事件,CSS 用于向内容呈现外观上的变化。

首先,让我们假设你有足够的内容来填充视窗:我将在清单 8-11 中显示一个标题和一段 Lorem ipsum 填充文本,以指示正文的开始。在页面的最底部,你会在一个footer元素中看到两个链接。第一个链接将引导用户到逻辑上“先前”于他们当前所在页面的内容;右边的第二个链接将引导他们进入当前页面之后的“下一个”页面。为了节省空间,我在链接中使用了 Unicode 黑色的向左和向右的三角形:你应该分别使用合适的 HTML 实体(&#9664;&#9654;

清单 8-11 。 超长页面的 HTML 代码,页脚中的内容采用 JavaScript 和 CSS3 转换

. . .
   <script src="//ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script>
</head>
<body>
<article>
    <header><h1>A History of the Roman Empire</h1></header>
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. . .

<footer id="articlefooter">
    <a href=# id=prevpage><img src=cicero.png alt=Cicero>Cicero and Claudius</a>
    <a href=# id=nextpage>Caligula and Ceasar <img src=caesar.png alt=Caeasar></a>
</footer>
</article>
</body>

文章中的内容应该将footer推到视窗底部边缘以下。您将设计页面样式,稍微缩进footer中的链接,并通过降低它们的不透明度使它们不可见(清单 8-12 )。

清单 8-12 。 带页脚导航页面的基本 CSS 代码

body { font-family: Avenir, sans-serif; margin: 100px 0; }
article { width: 768px; margin: 0 auto; }
footer#articlefooter { padding: 0 25px; } 
footer#articlefooter a { 
    text-decoration: none; color: #000; opacity: 0;  position: relative; 
} 
footer#articlefooter a img { width: 77px; height: 77ps; vertical-align: middle; }
a#prevpage { padding-left: 70px; float: left; transition: 1s 1s opacity linear, 1s 1s translateX ←linear; }
a#nextpage { padding-right: 70px; float: right; transition: 1s .5s opacity linear, 1s 1s ← translateX linear; }

您已经将 CSS3 转换代码与链接相关联:如果它们同时被触发,与#nextarticle元素相关联的.linkmoveright将首先移动。短暂的延迟之后,紧接着是与#prevarticle相关的.linkmoveleft级。

请注意,通过声明您正在更改的属性,您已经使转换更加有效:因为它们是多个属性,所以您使用了由逗号分隔的重复。

与其将元素的变化与:hover:focus伪选择器相关联,不如将它们定义为一个新的类(参见清单 8-13 )。

清单 8-13 。 变换为页脚导航元素

.linkmoveleft { transform: translateX(-70px); opacity: 1; }
.linkmoveright  { transform: translateX(70px);  opacity: 1; }

最后,您将在页面的最底部添加一个脚本,它将查看一些变量并判断何时将这些类添加到元素中。

如清单 8-14 中的所示,articleheight变量决定了主体的总高度,包括其所有内容。scrollTop测量页面中有多少像素比浏览器窗口的顶部边缘高:这将是页面加载时的0,随着用户向下滚动,该值增加。通过将articleheight除以 2 并将结果与scrollTop,进行比较,您可以确定用户何时滚动了半个页面,然后应用这些类(**清单 8-14 )。

清单 8-14 。 JQuery 代码将类放置在导航页脚元素上

<script>
$(function() {
    var articleheight = $("body").height();
    $(window).scroll(function() {
        if ($(this).scrollTop() > (articleheight / 2)) { 
              $("#prevpage").toggleClass("linkmoveleft"); 
              $("#nextpage").toggleClass("linkmoveright");

    });
}); 
</script>

CSS3 transitions 将响应于与它们相关联的元素状态的任何适当变化而触发,无论这些变化是由 CSS、JavaScript 还是其他任何东西强加的。在这种情况下,使用 JQuery 放置包含元素不透明度和位置更改的新类就足以引发转换。

虽然这是可行的,但仔细观察结果会发现这种方法有几个可能的缺点:

  • 特别长的文章的正文可能会超过浏览器窗口高度的两倍。清单 8-14 的脚本中的比较意味着对于这样的文章,过渡可能会在用户到达页面底部之前触发(也就是说,在阅读了一半以上的文章后,他们可能仍然看不到页脚)。
  • toggleClass函数意味着当用户向上滚动时,JQuery 将尝试撤销对这些类的应用,当用户返回页面底部时,JQuery 将再次触发它们。这种反复的转变可能会令人讨厌。
  • 最后,我们假设页脚总是与页面底部一致。这不一定是真的:页脚下面可能会有注释,这会显著增加文章的整体高度,导致 JavaScript 过早地应用这些类。

image 注意在 HTML5 规范下,嵌套在另一篇文章中的文章元素被假定为包含对父文章的评论。

另一种方法是,当页脚清楚地显示在页面上时,只应用一次过渡(清单 8-15 )。

清单 8-15 。 改进了 JQuery 代码,将类放置在导航页脚元素中

$(function() {
    var footerBottom = $("#articlefooter").offset().top + $("#articlefooter").height(); 
       $(window).scroll(function() {
            if ($(this).scrollTop() > (footerBottom - $(window).height())) { 
                     $("#prevpage").addClass("linkmoveleft"); 
                     $("#nextpage").addClass("linkmoveright"); 
                 }
           });
});

如果您想支持 Internet Explorer 6 到 8,您可以使用 Modernizr ( http://modernizr.com/)来检测浏览器对 CSS 转换的支持。如果浏览器缺乏支持,JQuery 可以依靠动画元素本身(见清单 8-16 )。

清单 8-16 。 改进了 JQuery 代码,将类放置在导航页脚元素中

<script src=//ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js></script>
<script src=scripts/modernizr.js></script>
</head>
<body>
<article>

. . .

</article>
<script>
$(function() {
    var footerBottom = $("#articlefooter").offset().top + $("#articlefooter").height();
    $(window).scroll(function() {
        if ($(this).scrollTop() > (footerBottom - $(window).height())) { 
             if (Modernizr.csstransitions) {
                         $("#prevpage").addClass("linkmoveleft"); 
                         $("#nextpage").addClass("linkmoveright");
                             } else { 
                        $("#prevpage").animate({ opacity: 1, left: '-=70'}, 1000, function() { });
                        $("#nextpage").animate({ opacity: 1, left: '+=70'}, 1000, function() { });
                           }
                 }
    });
}); 
</script>

如果你想创建一个更复杂的效果,你可以编写关键帧动画,或者将它们作为类应用,如清单 8-16 中的所示,或者直接使用 JQuery 调用动画。最后一个例子,您将使用后一种方法,调用关键帧动画来复制您刚刚创建的带有过渡的效果(清单 8-17 )。

清单 8-17 。 JQuery 代码用于应用 CSS3 动画

@keyframes leftmove { 
        100% { transform: translateX(-70px);  opacity: 1; }
}

@keyframes rightmove { 
        100% { transform: translateX(70px);  opacity: 1; }
}

<script>
$(function() {
    var footerBottom = $("#articlefooter").offset().top + $("#articlefooter").height();
    $(window).scroll(function() {
        if ($(this).scrollTop() > (footerBottom - $(window).height())) { 
              $("#prevpage").css('animation', 'leftmove 1s 2s forwards');
              $("#nextpage").css('animation', 'rightmove 1s 1s forwards');
    });
});
</script>

image 注意通过使用form标签和checkbox按钮,清单 8-17 中显示的技术可用于避免第四章中演示的语义可疑的交互方法。您可以简单地使用 JavaScript 来检测任何元素上的 DOM 事件,并启动其他元素上的 CSS3 转换、过渡和动画,而不是跳过标记环来获得您想要的 CSS 结果,如清单 8-18 所示。

清单 8-18 。 JQuery 代码用于在点击时应用 CSS3 动画

$(function() {
    $("#at").click(function() { $(".box").toggleClass("wobble"); });
});

用 JavaScript 定制 CSS3 过渡

在第六章中,你看到了用 CSS3 制作多个 SVG 元素的动画。当你这样做的时候,你会遇到一个主要的问题:为了制作元素动画,你必须在页面上将它们创建为单独的元素,这使得创建随机性的外观变得困难(见图 8-9 )。

9781430247227_Fig08-09.jpg

图 8-9。用 CSS3 制作的随机元素动画

为了减少您必须在任何页面中进行的手工编码,您将使用 JavaScript 来解决这两个问题。为了简单起见,您使用红色的div元素作为动画对象。在页面底部,你将添加清单 8-19 中的脚本。

清单 8-19 。 JavaScript 代码创建随机分散元素

<script>
var html = [];
for (i = 0; i < 30; i++) {
    var randomX = Math.random() * (100 - 1) + 1;
    var randomY = Math.random() * (1200 - 1) + 1;
    var randomZ = Math.random() * (100 - 1) + 1;
html.push('<div style="left:'+randomX+'%;top:'+randomY+'px;width:'+randomZ+'px;height: ←'+randomZ+'>
</div>');
}
    $("body").append( html.join('') );
</script>

您可以使用一个 JavaScript 循环来创建任意多的div元素的副本。对于每个元素,您将使用三个变量来确定其水平位置、距视口顶边的偏移量以及水平和垂直大小。

然而,你拥有的许多元素都将遵循相同的关键帧动画规则,如清单 8-20 所示。

清单 8-20 。 JavaScript 代码创建随机分散元素

html { height: 100%; }
body { min-height: 100%; margin: 0; }
@keyframes snowflake { 
        100% { transform: translateY(1800px) rotate(1200deg);  }
}
div { background: red; position: absolute; animation: snowflake 40s linear infinite;  }

虽然这种方法可行,但有几个问题:所有的形状都以相同的速度下落,并同步转动。小的元素看起来离得更远,应该下落得更慢,而所有的元素都应该以随机旋转开始。为了实现这一点,您将创建几个类,这些类将调用具有不同计时的关键帧动画,并根据元素的大小用 JavaScript 应用这些类(清单 8-21 )。

清单 8-21 。 CSS 和 JavaScript 代码创建随机化的分散元素

<style>
@keyframes snowflake { 
    100% { transform: translateY(1800px) rotate(1200deg);  }
}
div { background: red; position: absolute; 
animation-name: snowflake; 
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.small { animation-duration: 40s; }
.medium { animation-duration: 20s; }
.large { animation-duration: 10s; }
</style>

<body>
. . .
</body>

<script>
var html = [];
for (i = 0; i < 30; i++) {
    var randomX = Math.random() * (100 - 1) + 1;
    var randomY = Math.random() * (1200 - 1) + 1;
    var randomZ = Math.random() * (100 - 1) + 1;
    var randomR = Math.random() * (360 - 1) + 1;
    var sizes = ['small','medium','large'];
    var dim = sizes[Math.round(randomX/50)];
    html.push('<div style="left:'+randomX+'%;top:- ←
'+randomY+'px;width:'+randomZ+'px;height:'+randomZ+'px;transform:translateY(0px) ← 
rotate('+randomR+'deg)" class='+dim+'></div>');
}
$("body").append( html.join('') );
</script>

这段 JavaScript 代码是基础的,还可以做得更深入,但是需要注意的重要方面是,您正在利用每种技术的核心优势:您使用 CSS 提供外观规则,使用 JavaScript 对 DOM 进行快速更改。

摘要

本章介绍了 CSS3 动画、转换和过渡与响应式 web 设计、JavaScript 和 SVG 的集成。通过使用百分比和 vw 单位缩放内容,并使用@media查询在断点处动画化元素,您可以创建“动画”元素的印象来响应视窗大小调整。

您还可以使用 JavaScript 为 CSS 本身无法检测的动画提供触发点,并使用脚本语言为动画序列制作多个随机的“克隆”元素。这些技术的集成可以更进一步:一个很好的例子是 Sebastian Markbå ge 通过使用 SVG 路径数据生成关键帧动画声明(http://csspathanimation.calyptus.eu/)来解决让元素以恒定的运动速度跟随复杂路径的技术难题。

在本书中,到目前为止,您一直在使用 CSS3 在页面的平面上移动元素。在下一章中,你将在 3D 空间中操作 HTML 元素。

九、CSS3 3D 变换、过渡和动画

到目前为止,您已经在视口的平面空间中操作了图像、UI 元素和其他 web 内容。但是使用scale变换并不一定意味着一个元素离观察者更远,只是意味着它更大或更小;使用标准的 CSS 无法传递真实的透视感或深度感。

CSS 变换模块的 3D 属性改变了这一切。3D 变换允许您在投影的 3D 空间中操作内容。然后,可以使用您在前面章节中探索过的转场或关键帧语法来制作这些 3D 投影元素的动画。

3D 转换是 CSS3 的一个方面,在浏览器中往往而不是降级:如果客户端不理解 3D 转换声明,元素通常会堆叠出现。在旧浏览器中呈现元素之前,您应该仔细考虑这一点

尽管 CSS 3D 转换可以这样使用,但它并不打算使整个网站成为一个“3D 环境”,在这个环境中,浏览器窗口在一个页面和另一个页面之间旋转。更确切地说,新属性的使用通常与 CSS 的其他部分非常相似:为网页上的一些元素做出表示选择。通过 WebGL 之类的技术,创建 3D 内容的整个“世界”并与之交互最好是留给canvas元素的上下文。

由于计算要求更高,3D 变换被直接传输到客户端的 GPU,从而在动画过程中提供高帧速率。

视角

在 3D 空间转换 HTML 元素的关键是perspective,可以指定为 CSS 属性:

#ngc-1763 { perspective: 600px; } 

也可以在transform中指定一个值:

#ngc-1763 { transform: perspective(600px); } 

这两种方法完全等效,并且产生相同的结果。自然,这两种方法都需要厂商前缀来获得旧浏览器的支持。

注意,单独应用perspective后,你不会看到任何区别。设置perspective是 3D 操作的必要前提,但不会改变元素本身的外观。

perspective可以取任何正的 CSS 长度值,并定义从视点到 3D 元素的距离。这可能是 3D 变换最难理解的方面,这也是为什么这个属性比其他属性更值得考虑的原因。perspective属性如图图 9-1 所示。(此处显示的图像来自www.flickr.com/photos/powi的 Per Ola Wiberg,与本章中使用的所有照片一样,经许可使用)。

9781430247227_Fig09-01.jpg

图 9-1。在 3D 变换中改变视角会产生不同的视觉效果

在左边的图像中,视点相对靠近受影响的元素;通过设置为 200 像素获得的视角类似于通过相机的微距镜头观看场景。3D 变化很可能会出现戏剧性和扭曲。在右边的图像中,视点(设置为 2000px)远离受影响的元素,使内容相对“平坦”,就像通过长焦镜头观看一样。3D 空间中的视觉变换更可能是微妙和低调的。

虽然单个元素可能应用了单独的perspective属性,但这样做意味着每个元素都有自己的视觉原点,并且将与 3D 空间中的其他元素无关地显示。元素的变换意味着每个元素将显示不同的消失点,同时可能会增加浏览器的负担,因为它会计算每个元素的独立方向。除非你有意要达到类似 Inception- 的效果,否则建议你只对包含你想要在 3D 空间中操作的内容的元素应用一次perspective。包含div或者可能是body元素本身都可以很好地工作。随着perspective声明在右边元素上就位,它的子元素的 3D 变换将创建一个一致的视觉外观,如图 9-2 的右边图像所示。

9781430247227_Fig09-02.jpg

图 9-2。在 3D 变换中改变视角会产生不同的视觉效果

正如 2D 变换有一个transform-origin,3D 变换有一个perspective-origin,默认为元素的中心。虽然将perspective-origin放置在其他地方没有错(使用任何 CSS 长度或适当的关键字,水平后跟相对于元素的垂直位置),但是您应该知道在这样做时使用较高的值可能会产生极端的视觉失真,例如等距效果。一个单独的元素有自己的perspective,它的perspective-origin被“埋”在里面,屏蔽了大多数 3D 操作的效果。将perspective——通过关联,perspective-origin——放在父元素中通常会提供更好的视觉效果。

让我们从视觉上来看看这些效果。在图 9-2 中的两个截图共享在清单 9-1 中显示的相同的基本代码。

清单 9-1 。 HTML 和 CSS 共享一个简单的 3D 操作图像库

<style>
    html { height: 100%;  }
    body { min-height: 100%; background: #333;  margin: 60px; }
   img {  width: 300px; height: 300px; margin: 30px; }
</style>

<body>
    <img src=waterlily.jpg alt="Gul Näckros Waterlily">
    <img src=red-tulip.jpg alt="Red Tulip">
    <img src=dahlia.jpg alt=Dahlia>
    <img src=tulips.jpg alt=Tulips>
    <img src=tarda-tulip.jpg alt="Tarda Tulip">
    <img src=applebloom.jpg alt="Sweet applebloom">
    <img src=yellow-tulip.jpg alt="Yellow tulip">
    <img src=orchid.jpg alt=Orchid>
    <img src=poppy.jpg alt="Blue Himalyan poppy">
</body>

在图 9-2 中,左边的截图将perspectiveperspective-origin应用于单独的图像,而右边的截图显示了应用于身体的相同属性。两个示例对图像应用了相同的旋转。

在左边的图像中,图像向内旋转到自己,没有显示透视的变化。在左边,图像相对于身体视角旋转,从一致的消失点转换。

有趣的是,在第二个示例中,3D 效果是有响应的:因为perspective-originbody的右侧,调整浏览器窗口会改变原点的位置,从而改变所有 3D 元素的消失点。扩大和缩小浏览器将导致图像元素旋转,因为它们与变化的透视原点保持对齐。

放置perspective-origin时,要特别注意 CSS 中元素的默认行为:例如,容器元素的浮动子元素没有高度,或者默认情况下body是其内容的高度。当在隐含的 3D 空间中放置原点和操纵内容时,这些方面会有显著的影响。

为了演示这一点,以清单 9-1 中的 HTML 代码为例,但是替换清单 9-2 中的 CSS。

清单 9-2 。 CSS 在 3D CSS 透视上表现出意料之外的局限性

body { perspective: 1200px; perspective-origin: center center; margin: 2rem; }
img { width: 500px; height: 375px; float: left; margin-right: 2rem; margin-bottom: 2rem;  }
img {  transform: rotateY(45deg); }

CSS 代码将body元素的perspective-origin设置为 X 轴和 Y 轴的默认值center,但是正如您从图 9-3 中看到的,图像的效果显示原点不在文档的中心,而是在顶部。

9781430247227_Fig09-03.jpg

图 9-3。由于透视原点未对准,图像方向不正确

为了使图像的透视正确,必须使body元素至少和它包含的内容一样高。在这种情况下,你将在 html 上使用标准的min-height: 100%,在 body 方法上使用height: 100%,你可以在清单 9-3 中看到。一旦浏览器支持 CSS3 值,您将能够单独在 body 元素上使用min-height: contain-floats

清单 9-3 。??【CSS 3D 透视】校正身体高度

html { height: 100%; }
body { perspective: 1200px; perspective-origin: center center; margin: 2rem; 
margin-top: 8rem; min-height: 100%; }
img { width: 500px; height: 375px; float: left; margin-right: 2rem; margin-bottom: 2rem;  }
img { transform: rotateY(45deg); }

CSS 的改变为图像提供了正确的变换,正如你在图 9-4 中看到的。

9781430247227_Fig09-04.jpg

图 9-4。用校正的身高校正图像的方向

如你所见,在代码和网页的笛卡尔空间中正确放置perspectiveperspective-origin,,可以对内容的显示方式产生显著的影响。

旋转

现在,您已经在 3D 中完成了一点旋转,您应该花点时间来完全探索它。2D 变换只有一次旋转;毫不奇怪,3D 有三个。令人困惑的是这三个轴的方向和效果,如图 9-5 所示。

9781430247227_Fig09-05.jpg

图 9-5。3D 空间旋转选项

如你所见,rotateX实际上与 2D CSS 旋转相同,并像风车一样围绕轴移动rotateY像门一样左右摆动元素,rotateZ像猫门一样绕水平轴移动。自然,这些变换的视觉效果会随着perspective-origin的改变而不同。

如果元素一次绕多个轴旋转,使用rotate3d快捷键通常更有效:

img  { transform: rotate3d( 0, 1, 0, 45deg); }

您可以将rotate3d视为每个轴(x,y,z)的矩阵乘数:如果前三个槽中的任何一个有任何类型的数值,元素将围绕适当的轴旋转最后一个值。例如,上面的声明将图像绕 y 轴旋转 45 度。通过为多个轴启用 bits,可以组合多个旋转:

img  { transform: rotate3d( 1, 1, 0, .15turn); }

翻译

3D 变换元素也可以沿 X、Y 和 Z 轴移动。请注意,如果元素绕 X 或 Y 轴旋转或沿 Z 轴移动,这样做会使元素移向或远离其消失点。例如,清单 9-4 中的代码可以为一部电影创建一个开场爬行的视觉效果,片尾字幕消失在无限的空间中。

清单 9-4 。 代码、内容、CSS 进行一次期初信用抓取

<style>
body { background: #000; perspective: 700px; }
div#crawl { width: 80%; text-align: center; color: #fff;
font-family: 'Franklin Gothic Medium', sans-serif; 
font-size: 4rem; margin: 0 auto; 
transform: rotateX(30deg) translateY(−200px); }
</style>
<body>
<div id="crawl">
<h1>Blue Harvest</h1>
<p>The waves of grain moved like the surface of the ocean under the light of the moon, stirred faintly by a susurrus of wind from the east. Caleb hoisted the worn wooden shaft of a scythe over his shoulder and peered out into the darkness, dirt-grimed thumbnail scratching under the brim of his straw hat, just above the sun-seared terminator of skin.</p>
</div>

自然地,这也很容易被动画化(清单 9-5 )。

清单 9-5 。 CSS 为动画开场信用抓取

@keyframes crawl { 
    100% { transform: rotateX(40deg) translateY(−2000px);  }
}
div#crawl { transform: rotateX(40deg) translateY(1000px); animation: crawl 30s linear; }

这就产生了你在图 9-6 中看到的结果。

9781430247227_Fig09-06.jpg

图 9-6。仍然来自用 CSS3 创建的动画信用抓取

您也可以像前面使用rotate3d属性一样使用translate3d

image 注意translateZscaleZ在视觉上几乎没有区别:假设没有应用其他变换,它们都实现了相同的结果。除此之外,scale的工作方式与其他属性相同,包括scale3d

卡片标题翻转

您可以使用这些 3D 变换的组合,在图库图像的“反面”创建几个图像标题的变体,通过鼠标悬停显示(图 9-7 )。

9781430247227_Fig09-07.jpg

图 9-7。 3D 翻转图像字幕库

您将创建的第一个示例将对标准列表中的图像使用过渡。所有的图片大小完全相同,每张图片后的标题编码为 span 元素,如清单 9-6 所示。

清单 9-6 。 代码为一个简单的 3D 图库

<ul id=gallery>
    <li><img src=tulips.jpg alt="Tulips">
    <span>Tulips</span>
    <li><img src=hepatica-nobilis.jpg alt=Nepatica-nobilis>
    <span style=padding-left:4rem>Nepatica nobilis</span>
    <li><img src=ekebyhosparken.jpg alt=Ekebyhosparken>
    <span style=padding-left:4rem>Ekebyhosparken</span>
</ul>

在这个例子中,每张图片在鼠标滑过时都会水平翻转,显示出背面,就好像你是从另一面透过透明的图片看一样。暂停之后,span内容将淡入这个反转图像的顶部(行内填充仅用于movespan空间内的文本)。将鼠标从图像上移开会颠倒这个顺序。(参见清单 9-7 。)

清单 9-7 。 CSS 用于简单的 3D 图库

body { background: #fff; font-family: Avenir, Arial, sans-serif;
    font-size: 1.5rem; text-shadow: 3px 3px 2px rgba(0,0,0,0.6); }
ul#gallery { margin-top: 400px; perspective: 1000px;  }
ul#gallery li { display: inline-block; margin: 20px;  }
ul#gallery li img { width: 320px; height: 244px;
    box-shadow: 0px 0px 16px rgba(0,0,0,0.3); 
    transition: 1s all linear;
}
ul#gallery li:hover img { transform: rotateY(180deg); }
ul#gallery li span { position: absolute; width: 320px; height: 244px;
    margin-left: -320px; color: #fff; opacity: 0; background: rgba(0,0,0,0.8); display: inline-block; 
    box-sizing: border-box; padding-top: 6rem; padding-left: 8rem;  }
ul#gallery li:hover span { opacity: 1; transition: 1s 1s opacity linear; }

旋转完成后,span元素立即使用transition-duration值。每次旋转都是围绕图像自身的中心;如果你想引入更多的可变性,你可以改变每个元素的transition-origin

作为一个实验,让span元素在你的 CSS 中可见并且不被转换;你会看到旋转的图像旋转标题文本,这个效果你以后会有机会用到。与z-index很相似,未转换的内容被认为存在于 3D 投影内容可以穿过的表示的“基础层”,这取决于其位置和视角。

同样值得注意的是,图片的box-shadow而不是显示在你的正文内容的白色页面上;相反,阴影作为图像的一部分围绕着它旋转。虽然理论上可以操纵单独的“阴影”div来提供投影的印象,但这需要相当大的额外努力。

作为一个整体,画廊运作良好,但游客看到图像的“另一面”可能会感到困惑。(参见图 9-8 。)给人的印象是,你的图像是真正的卡片,背面有一个普通的标题,所有这些元素一起移动,这需要更多的工作。

9781430247227_Fig09-08.jpg

图 9-8。背面为实心的 3D 翻转图像字幕库

首先,您将更改标记以提供具有更多语义值的页面变体,如清单 9-8 所示。

清单 9-8 。 代码为更复杂的 3D 图库

<figure>
    <figcaption>Tulips</figcaption>
    <img src=tulips.jpg alt=Tulips>
</figure>
<figure>
    <figcaption>Nepatica nobilis</figcaption>
    <img src=hepatica-nobilis.jpg alt="Nepatica nobilis">
</figure>
<figure>
       <figcaption>Ekebyhosparken</figcaption>
    <img src=ekebyhosparken.jpg alt=Ekebyhosparken>
</figure>

注意源的顺序:每个图片标题出现在它所引用的图片之前。这在 HTML5 中完全有效,对你的 CSS 动画也很有用。您可以将标题放在图像之后,但是这需要更改标题的 z-index 值。CSS 代码以类似于上一个例子的方式开始(见清单 9-9 )。

清单 9-9 。 基本 CSS 代码,用于更复杂的 3D 图库

body { background: hsl(100,0%,100%); font-family: Avenir, sans-serif; font-size: 1.5rem;
    margin-top: 400px; perspective: 1000px;     }
figure { margin: 20px; transition: 1s all linear;
    box-shadow: 0px 0px 16px rgba(0,0,0,0.3); float: left; }
figure, figure img, figcaption { width: 320px; height: 244px; box-sizing: border-box; }
figure img, figcaption { position: absolute; }
figcaption { background: #fff; text-align: center; padding-top: 6rem;   }
figure:hover { transform: rotateY(180deg);  } 

图像-标题对的大小完全相同,位置绝对一致。因为照片出现在标题之后,所以它们显示在文字的“顶部”。但是,在此阶段将每个图形作为一个整体进行旋转只会显示图像的反面,而不会显示文本。

背面可见度

围绕 Z 和 Y 轴旋转元素带来了一个有趣的问题:当您将元素旋转超过 180 度时会发生什么?到目前为止,图像的有效“厚度”为 0,那么图像的另一边是什么呢?

此状态下的外观由backface-visibility属性决定,该属性的默认值为visible。这意味着当一个元素翻转超过 180°时,在另一侧显示的是在元素原始方向看到的反转:图像实际上变成了透明的,在两侧同样可见,文本呈现镜像。将背面可见性设为hidden会导致渲染器在元素旋转超过 180 度时忽略元素的另一侧;在大多数情况下,这意味着渲染器的工作量更少,结果是动画更平滑、更干净。

变换风格

默认情况下,浏览器将假设 3D 变换元素的子元素采用其父元素的 3D 变换,但是被投影到同一平面上:对于这样的子元素没有“前”或“后”的感觉。形式上,这将被声明为应用于父元素的transform-style: flat

如果您希望 3D 操作元素的子元素在与其父元素相同的 3D 空间中移动,但投影到它们自己的平面上,则必须将值preserve-3d 应用到父元素。这允许您将一个子元素放在另一个的后面,这样您的卡片就可以有两个可见的“面”

在这种情况下,代码中还需要添加一项内容——这些属性本身不足以给人一种双面卡片的感觉。为了在图像的另一侧正确显示字幕,必须在任何动画发生之前水平翻转。(想象两张扑克牌背对背放在一起,两面都可以看到它们的正面)。

您的代码会变成您在清单 9-10 中看到的样子。

清单 9-10 。 为更复杂的 3D 图库完成 CSS 代码

body { background: hsl(100,0%,100%); font-family: Avenir, sans-serif; font-size: 1.5rem;
    margin-top: 400px; perspective: 1000px;     }
figure { margin: 20px; transition: 1s all linear;
    box-shadow: 0px 0px 16px rgba(0,0,0,0.3); float: left;
    transform-style: preserve-3d; }
figure, figure img, figcaption { width: 320px; height: 244px; box-sizing: border-box; }
figure img, figcaption { position: absolute; backface-visibility: hidden; }
figcaption { background: #fff; text-align: center; padding-top: 6rem;
    transform: rotateY(180deg);  }
figure:hover { transform: rotateY(180deg);  }

还有一种变化需要考虑:如果你想让照片的另一面透过标题隐约可见,该怎么办?关闭backface-visibility: hidden本身不足以产生这种效果。你需要在三维空间中更精确地定位每个元素(见清单 9-11 )。

清单 9-11 。 替换完整的 CSS 代码,用于更复杂的 3D 图库

body { background: hsl(100,0%,100%); font-family: Avenir, sans-serif; font-size: 1.5rem; 
    margin-top: 400px; perspective: 1000px;     }
figure { margin: 20px; transition: 1s all linear;
    transform-style: preserve-3d; box-shadow: 0px 0px 16px rgba(0,0,0,0.3); float: left; }
figure, figure img, figcaption { width: 320px; height: 244px; box-sizing: border-box;   }
figure img, figcaption { position: absolute;  }
figcaption { background: #fff; text-align: center; padding-top: 6rem;
    transform: rotateY(180deg) translateZ(1px); opacity: 0.9;
}
figure:hover { transform: rotateY(180deg);  }

标题沿 z 轴的轻微平移足以将标题放置在图像的“后面”,这样就可以看到下面照片的反面,如图图 9-9 所示。

9781430247227_Fig09-09.jpg

图 9-9。背面部分透明的 3D 翻转图像字幕库

圆形 3D 图库

您可以将目前使用的所有照片转换成一个全圆形的 3D 图库,并在悬停时旋转(图 9-10 )。如清单 9-12 所示,标记非常简单。

9781430247227_Fig09-10.jpg

图 9-10。动画圆形 3D 图库

清单 9-12 。?? 圆形 3D 图库的 HTML 代码

<div>
    <figure> 
       <img src="färentuna-church.jpeg" alt="Färentuna church in Färingsö, Sweden"> 
       <img src="winter-trees.jpeg" alt="Trees in winter, Sweden">
       <img src="view-from-rastaholm.jpeg" alt="View From Rastaholm, Sweden">
       <img src="fall-park.jpeg" alt="Park in fall"> <img src="sunset2.jpeg" alt="Sunset">
       <img src="tulips2.jpeg" alt="Tulips">
       <img src="hepatica-nobilis.jpg" alt="Nepatica-nobilis">
       <img src="sunset.jpg" alt="Sunset">
       <img src="ekebyhosparken.jpg" alt="Ekebyhosparken">
    </figure>
</div>

您将通过绝对定位这些图像来将它们推入一个 3D 圆,以便它们都堆叠在彼此之上,在 3D 空间中定位它们的公共变换原点 z“back ”,并围绕 Y 轴独立旋转每个图像。由于有八幅图像,每幅图像将以 45 度的增量旋转,以创建一个均匀分布的照片圈(清单 9-13 )。

清单 9-13 。 一个圆形 3D 图库的基本 CSS 代码

div { perspective: 1000px; margin-top: 400px; width: 1400px; }
figure { transform-style: preserve-3d; height: 244px; transform-origin-x: 660px; }
img { width: 320px; height: 244px; position: absolute; left: 500px; }
figure, img { transform-origin-z: -500px; }
div img:nth-child(1) { transform: rotateY(0deg); }
div img:nth-child(2) { transform: rotateY(−45deg); }
div img:nth-child(3) { transform: rotateY(−90deg); }
div img:nth-child(4) { transform: rotateY(−135deg); }
div img:nth-child(5) { transform: rotateY(−180deg); }
div img:nth-child(6) { transform: rotateY(−225deg); } 
div img:nth-child(7) { transform: rotateY(−270deg); }
div img:nth-child(8) { transform: rotateY(−315deg); }

注意,改变figure元素的height会改变画廊原点的Y坐标,在 3D 空间中上下倾斜图像圆。在照片的一半高度上,照片的圆圈看起来与观众的“眼睛高度”相同。

还要注意,您可以使用 JavaScript 来自动分发图像——这将在下一节中进行。

悬停时有两种方法可以旋转图库。一种是将每张图像的rotateY值增加相同的量:这是一种过于复杂的方法,不需要借助脚本。正如你所看到的,你已经设置了图像和围绕它们的figure具有相同的z原点,所以你的第二个选择是动画人物本身(清单 9-14 )。

清单 9-14 。 CSS 动画代码为圆形 3D 图库

@keyframes spin { 100% { transform: rotateY(360deg);  }  }
figure:hover  { animation: spin 12s linear infinite;  }

虽然 3D 和动画效果很好,但画廊缺乏现实主义的另一个方面:在现实生活中,远处的物体不仅更小,而且更暗。隐藏图像的背面是行不通的:这将使图像消失,而不是褪色,而且根据第一个画廊的解决方案,在每个图像后面添加跨度是太多的额外标记。模糊滤镜也不能处理 3d 转换图像的像素值,至少在撰写本文时不能。

有几种可能的方法来实现这种效果:可以在画廊圈的“后面”看到的第四个和第六个图像可以动态地设置为不透明,并在它们出现在最前面时变成实心的。或者,可以应用一个均匀应用于每幅图像所有侧面的无模糊的方框阴影(清单 9-15 )。

清单 9-15 。?? 圆形 3D 图库的 CSS 底纹效果

img { box-shadow: 0px 0px 0px 48px rgba(0,0,0,0.8); }

这种方法的局限性在于包含divfigurebackground-colorbody本身必须是纯黑色;任何更亮的东西都会显示阴影的边缘。(参见图 9-11 )。

9781430247227_Fig09-11.jpg

图 9-11。带阴影效果的圆形 3D 图库

由于每张图片都作为自己的元素有效地保持独立,你可以将第三章第一节中探索的标题技术与圆形画廊中的照片结合起来,尽管对标记做了一些改变(见清单 9-16 )。

清单 9-16 。 带弹出字幕的圆形 3D 图库代码

<style>
@keyframes spin { 
    100% { transform: rotateY(360deg); } 
} 

body {  background: black; font-family: Georgia, serif; font-style: italic; font-size: 1.2rem; } 
div#gallery { perspective: 1000px; margin-top: 400px; width: 1400px; }
div#inner{ transform-style: preserve-3d;
    transform-origin-x: 660px; transform-origin-z: -500px; height: 244px; }
figure, img { width: 320px; height: 244px; }
figure { left: 500px; position: absolute;  overflow: hidden; transform-origin-z: -500px; }
figcaption { background: hsla(0,0%,0%,0.5); color: #fff; position: relative; top: 0; padding: 8px; 
    transition: 0.6s top linear; } 
figure:hover figcaption { top: -38px; }

div#gallery:hover div#inner { animation: spin 24s linear infinite; }
div#gallery figure:nth-child(1) { transform: rotateY(0deg); }
div#gallery figure:nth-child(2) { transform: rotateY(−45deg);  }
div#gallery figure:nth-child(3) { transform: rotateY(−90deg); }
div#gallery figure:nth-child(4) { transform: rotateY(−135deg); }
div#gallery figure:nth-child(5) { transform: rotateY(−180deg); }
div#gallery figure:nth-child(6) { transform: rotateY(−225deg); }
div#gallery figure:nth-child(7) { transform: rotateY(−270deg); }
div#gallery figure:nth-child(8) { transform: rotateY(−315deg); }
</style>

<body>
<div id="gallery">
    <div id="inner"> 
    <figure>
        <img src="färentuna-church.jpeg" alt="Färentuna church in Färingsö, Sweden">
        <figcaption>Färentuna Church, Färingsö, Sweden</figcaption>
    </figure> 
    <figure> 
         <img src="winter-trees.jpeg" alt="Trees in winter, Sweden">
         <figcaption>Trees in winter, Sweden</figcaption>
     </figure>
     <figure>
          <img src="view-from-rastaholm.jpeg" alt="View From Rastaholm, Sweden">
         <figcaption>View From Rastaholm, Sweden</figcaption>
     </figure>
     <figure>
          <img src="fall-park.jpeg" alt="Park in fall">
          <figcaption>Swedish park in Fall</figcaption>
      </figure>
      <figure>
          <img src="sunset2.jpeg" alt="Sunset">
          <figcaption>Sunset</figcaption>
       </figure>
        <figure>
             <img src="tulips2.jpeg" alt="Tulips">
             <figcaption>Tulips</figcaption>
         </figure>
         <figure>
               <img src="hepatica-nobilis.jpg" alt="Nepatica-nobilis">
               <figcaption>Nepatica nobilis</figcaption>
          </figure>
          <figure>
               <img src="sunset.jpg" alt="Sunset">
               <figcaption>Sunset</figcaption>
          </figure>
          <figure>
               <img src="ekebyhosparken.jpg" alt="Ekebyhosparken">
               <figcaption>Ekebyhosparken</figcaption>
          </figure>
      </div>
</div>
</body>

你可以在图 9-12 中看到结果的静止图像。

9781430247227_Fig09-12.jpg

图 9-12。带有弹出式标题的圆形 3D 图库

用 4 级选择器和 JavaScript 增强图库

有许多方法可以增强您用 JavaScript 创建的图库。显而易见的主要方法是用脚本来处理图像的初始旋转,而不是手工操作。(为了简单起见,我假设你已经回到了清单 9-17 中显示的图库的基本标记)。

清单 9-17 。 JQuery 代码自动将图片分发到 CSS3 圆形图库中

<script>
var numberOfImgs = $("figure img").length;
var degreeSep = 360 / (numberOfImgs - 1);
var angle = 0;
for (i = 1; i < numberOfImgs; i++) { 
    $("figure img:nth-child(" + (i) + ")").css('transform','rotateY('+ angle +'deg)'); 
    angle = angle + degreeSep;
}
</script>

这将消除 CSS 的八个重复行,并产生更加灵活的结果:如果在图形中添加或删除图像,它们的分布将自动调整。更高级版本的脚本可能使用基本的三角学来确定图像的大小和数量以及 origin-z 距离是否足以在照片之间提供可接受的间距;否则,图像的宽度、高度和/或原点 z 距离可以由 JavaScript 修改。

第二,您可以允许用户通过检测图形元素内的鼠标位置来手动旋转图库,并使用其相对于中心的水平偏移来确定图库的旋转量(清单 9-18 )。

清单 9-18 。 JQuery 代码基于鼠标位置旋转 CSS3 圆形图库

<script> 
$("figure").mousemove(function(e) {
    var relativeX = e.pageX - (this.offsetLeft + 660); 
    $(this).css('transform','rotateY('+ relativeX +'deg)'); 
});
</script>

这将意味着移除 CSS3 动画并在过渡中替换,如清单 9-19 所示。

清单 9-19 。 CSS 代码用于 JQuery 鼠标位置旋转圆形图库

figure { transform-style: preserve-3d; transform-origin-x: 660px; 
    transform-origin-z: -500px; height: 244px; transition: 2s transform linear; }
figure:hover { cursor: ew-resize; }

image 注意这在某种程度上也可以使用纯 CSS 来实现,两个元素分别是图的高度和宽度的一半,放置在figure的左右两侧,每个元素上有一个悬停伪选择器,分别驱动顺时针和逆时针动画。然而,有两个明显的缺点:不能与下面的图库直接交互(即没有弹出字幕),因为两个重叠的元素会捕获所有的鼠标事件;2)使用纯 CSS 会将动画限制在一个固定的旋转速度,而不是我们之前看到的 JavaScript 解决方案的“越远=旋转越快”。

该 JavaScript 的更高级版本——以及与移动 UI 约定更兼容的版本——可能包含一个脚本来测量鼠标和/或指尖在屏幕上的拖动运动,将圆形图库旋转相应的度数。您还可以添加左右按钮,以增量方式旋转图库。

添加 CSS 四级选择器

一旦浏览器支持它,您可以通过使用父选择器使图库更具探索性:

$figure img:nth-child(2):hover { transform: rotateY(−45deg); }

这将旋转圆形画廊作为一个整体,使当前悬停的图像前面和中心。

UI 元素的 3D CSS 变换和过渡

一般来说,清晰导航的要求意味着 UI 元素应该尽可能少地使用视觉“技巧”。下面的技术源自哈基姆·艾尔·哈塔布(Hakim El Hattab)(http://hakim.se,经许可使用)的开创性工作,使用了相反的方法:当导航被聚焦时,页面的其余部分以 3D 方式过渡。清单 9-20 中显示了代码的一个变体。你可以在图 9-13 中看到结果。

9781430247227_Fig09-13.jpg

图 9-13。使用带侧拉导航的 CSS3 转换正文内容

清单 9-20 。 用于侧拉导航的 HTML 代码

<!doctype html>
<html lang="en">
<head>
     <meta charset="utf-8">
     <title>3D fold-away menu</title>
    <link rel="stylesheet" href="wedge.css">
</head>
<body>
    <div class="meny">
    <h2>Other Demigods</h2>
    <ul>
        <li><a href="#">Aegir</a>
        <li><a href="#">Balder</a>
        <li><a href="#">Bragi</a>
        <li><a href="#">Eostra</a>
    </ul>
</div>
<div class="meny-arrow"> </div>
<div class="meny-contents">
    <div class="cover"></div>
    <article>
    <h1>Deigods of Asgard</h1>
    <p>HWÆT, WE GAR-DEna in geardagum, þeodcyninga þrym gefrunon. . . . . 
    </article>
</div>
</body>
<script src="meny.js"></script>
</html>

附加的样式表如清单 9-21 所示。

清单 9-21 。 CSS 样式表用于侧拉导航

*{ margin: 0; padding: 0; }
html, body { height: 100%; overflow: hidden; }
body { background-color: #222;  font-family: Lato, Helvetica, sans-serif;
    font-size: 16px; color: #222; } 
.meny-wrapper {perspective: 800; perspective-origin: 0% 50%; }
.meny, .meny-contents { box-sizing: border-box; transition: transform .5s ease;
    transform-origin: 0% 50%; }
.meny { display: none; position: fixed; height: 100%; width: 300px;
    z-index: 1; margin: 0px; padding: 20px;
    transform: rotateY( −30deg ) translateX( −97% ); }
.meny-ready .meny { display: block; }
.meny-active .meny { transform: rotateY( 0deg ); }
.meny-contents { background: #eee; padding: 20px 40px; width: 100%; height: 100%;
    overflow-y: auto; }
.meny-active .meny-contents { transform: translateX( 300px ) rotateY( 15deg ); }
.meny-contents .cover { display: none; position: absolute;
    width: 100%; height: 100%; top: 0; left: 0; visibility: hidden; z-index: 1000;
    opacity: 0;     background: linear-gradient(left,  rgba(0,0,0,0.15) 0%,rgba(0,0,0,0.65) 100%); 
    transition: all .5s ease; }
.meny-ready .meny-contents .cover { display: block; }
.meny-active .meny-contents .cover { visibility: visible; opacity: 1; }
.meny-arrow { position: absolute; top: 45%; left: 12px; z-index: 10;
    font-family: sans-serif; font-size: 20px; color: #333;
    transition: left 0.8s cubic-bezier(0.680, -0.550, 0.265, 1.550); }
.meny-active .meny-arrow { left: -40px; opacity: 0; }
.meny-fold .meny, .meny-fold .meny-contents {transition: transform 0.6s ease; }
.meny-fold .meny-contents { position: fixed; z-index: 3; }
.meny-fold .meny {transform-origin: 50% 50%; }
.meny-fold .meny.right .cover { position: absolute; 
    width: 100%; height: 100%; left: 0; top: 0; opacity: 1;
    background: linear-gradient(to right,  rgba(0,0,0,1) 0%,rgba(0,0,0,0) 90%); } 
.meny-ready .meny-fold .meny.right .cover { transition: opacity 0.6s ease; } 
.meny-active .meny-fold .meny.right .cover { opacity: 0; } 
.meny-fold .meny.left { clip: rect( 0px, 150px, 10000px, 0px );
    transform: translate3d( −150px, 0, -300px ) rotateY( 90deg ) scale(1.25); } 
.meny-active .meny-fold .meny.left { clip: initial; }
.meny-fold .meny.right { clip: rect( 0px, 300px, 10000px, 150px );
    transform: translate3d( −150px, 0, -300px ) rotateY( −90deg ) scale(1.25); } 
.meny-active .meny-fold .meny.left, .meny-active .meny-fold .meny.right { 
    transform: rotateY( 0deg ); }
a { color: #c2575b; text-decoration: none; transition: 0.15s color ease; }
a:hover { color: #f76f76; }
h1 { font-size: 24px; }
.meny { background: #333; color: #eee; }
.meny ul { margin-top: 10px; }
.meny ul li { list-style: none; font-size: 20px; padding: 3px 10px; }
.meny ul li:before { content: '-'; margin-right: 5px;
   color: rgba( 255, 255, 255, 0.2 ); } 
.meny-contents>article { max-width: 400px; }
.meny-contents p { margin: 10px 0 10px 0; font-size: 16px; line-height: 1.32; }

最后,覆盖悬停、触摸和滑动事件的 JavaScript 如清单 9-22 所示。

清单 9-22 。 用于侧拉导航的 JavaScript

(function(){
    var meny = document.querySelector( '.meny' );
    if (!meny || !meny.parentNode ) { return; }
    var menyWrapper = meny.parentNode;
    menyWrapper.className += ' meny-wrapper';
    var indentX = menyWrapper.offsetLeft,
    activateX = 40, 
    deactivateX = meny.offsetWidth || 300,
    touchStartX = null,
    touchMoveX = null,
    isActive = false,
    isMouseDown = false;
    document.addEventListener( 'mousedown', onMouseDown, false );
    document.addEventListener( 'mouseup', onMouseUp, false );
    document.addEventListener( 'mousemove', onMouseMove, false ); 
    document.addEventListener( 'touchstart', onTouchStart, false );
    document.addEventListener( 'touchend', onTouchEnd, false );
    window.addEventListener( 'hashchange', onHashChange, false );
    onHashChange();
    document.documentElement.className += ' meny-ready';
    function onMouseDown( event ) { isMouseDown = true; }
    function onMouseMove( event ) {
        if( !isMouseDown ) { var x = event.clientX - indentX;
        if (deactivateX ) { deactivate(); }else if( x < activateX ) {activate(); } }
} 
    function onMouseUp( event ) { isMouseDown = false; }
    function onTouchStart( event ) { touchStartX = event.touches[0].clientX - indentX; 
    touchMoveX = null;
    if (isActive || touchStartX < activateX ) {
        document.addEventListener( 'touchmove', onTouchMove, false ); }
    }
function onTouchMove( event ) {
    touchMoveX = event.touches[0].clientX - indentX;
    if ( isActive && touchMoveX < touchStartX - activateX ) { 
        deactivate(); event.preventDefault();
    }else if ( touchStartX < activateX && touchMoveX > touchStartX + activateX ) {
         activate();
        event.preventDefault(); } }
function onTouchEnd( event ) {
    document.addEventListener( 'touchmove', onTouchMove, false );
    if (touchMoveX === null ) { 
        if (touchStartX > deactivateX ) { deactivate(); } 
        else if (touchStartX < activateX * 2) { activate(); }}}

function onHashChange( event ) {
    if( window.location.hash.match( 'fold' ) && !document.body.className.match( 'meny-fold' ) ) {
         addClass( document.body, 'meny-fold' );
        var clone = document.createElement( 'div' ); 
       clone.className = 'meny right';
clone.innerHTML = meny.innerHTML + '<div class="cover"></div>';
document.body.appendChild( clone );
addClass( meny, 'left' );
    } else {
removeClass( document.body, 'meny-fold' );
var clone = document.querySelector( '.meny.right' );
if (clone ) {
    clone.parentNode.removeChild( clone ); } } }

function activate() { if (isActive === false ) {
    isActive = true;
    addClass( document.documentElement, 'meny-active' ); }}

function deactivate() { 
    if( isActive === true ) {
    isActive = false;
    removeClass( document.documentElement, 'meny-active' ); }
}

function addClass( element, name ) {
    element.className = element.className.replace( /\s+$/gi, '' ) + ' ' + name; }

function removeClass( element, name ) {
    element.className = element.className.replace( name, '' ); 
} 
})();

HTML、JavaScript 和 CSS 结合在一起,为桌面浏览器和移动设备创造了你在图 9-10 中看到的效果。

摘要

3D 变换、过渡和动画可用于增加网页内容的深度和视角。虽然在平面 2D 屏幕的环境中很难看到 z 轴,但使用这里和前面章节中讨论的原则(包括围绕一个点操纵原点和变换、使用强制透视、背面可见性和变换样式)会有很大帮助。

到目前为止,您已经手工生成了所有的代码。虽然这是最好的学习方法,但是使用配置良好的工具可以使 CSS 代码的生成更快更有效,在下一章你会找到相关的建议。您还将了解 CSS 中的下一个创新以及相关技术可能来自哪里。

十、CSS 动画的工具、技术和未来

作为一组 W3C 模块,它们才刚刚开始从工作草案进入候选推荐状态,CSS 转换、过渡和动画规范还没有旧的最终规范所拥有的健壮的行业工具集。软件开发人员不能因为工具的相对缺乏而受到指责:规范一直是一个移动的目标,使得应用开发具有挑战性。与此同时, W3C 在新技术上向前发展,使得工具开发更加困难,而 CSS 本身变得更加强大。

尽管变化的速度很快,但有许多解决方案可以加速和简化 CSS3 动画的工作流和开发,既可以向后兼容旧浏览器,也可以为现在和未来的开发提供前瞻性的应用。然而,在我们开始之前,你应该花一点时间来欣赏如何有效地使用你到目前为止学到的技能。

编写有效的 CSS3 动画和过渡:避免回流

对于浏览器来说,CSS 中有两个处理起来计算量很大的操作:重画和重流。

当页面内容的布局改变时,页面重排 被启动:想象一下当浏览器窗口变窄时,一个流畅的站点的外观发生变化。当一个元素改变它的可见性时,会发生一个 重画,但是不会影响它的邻居的布局:例如,当一个元素的可见性、不透明度或者背景颜色改变时。

在这两种情况中,回流通常对性能更不利,因为回流会在 DOM 树中从受影响的元素向下通过所有子节点和之后的子节点“波及” ,迫使多个元素改变它们的位置。在许多情况下,回流实质上可以重绘整个页面。回流操作对现代台式机的性能可能不太重要,但对智能手机等功率较低的设备可能会造成严重影响。与我们的兴趣最相关的是,使用任何伪元素,比如:hover,或者一个操纵 DOM 的脚本,都会启动一个回流。

image 注意如果你是一个更注重视觉的人,你可以在 Firefox 中看到一个非常缓慢的回流过程,因为它在www.youtube.com/watch?v=nJtBUHyNBxs首次在 YouTube 上展示了google.co.jp主页。

虽然浏览器回流是不可避免的,但是通过遵循一些规则,它们的影响可以被最小化和本地化:

  • 尝试直接影响你想要设计的元素,而不是它的父元素。也就是说,尝试限制任何回流的范围:与其改变容器元素的类来影响其子元素,不如尝试直接影响子元素本身。这并不能避免所有的回流,例如,改变元素的高度可能会影响其父元素的尺寸,导致回流波动,但这是一个很好的通用规则。
  • 避免设置内嵌样式。最重要的是,避免创建多个内联样式。相反,将相关的 CSS 外部化到一个类中,然后更改该类。强调相反方面的工作流程(例如,试图操作内联样式,或者在嵌入、链接和内联样式之间合并样式)可能会在每次调整时导致多次重排。
  • 使用 变换**将动画应用于元素,或应用于绝对定位或固定的元素。具有这些特征的元素不会影响其他元素的位置,这意味着只有受影响的元素会被重新绘制,而不需要重新绘制。
  • 创建具有固定高度和宽度的元素的“内部”动画和/或应用了 溢出:隐藏**的动画。这些元素中的动画不会影响其他元素,避免了回流的机会。
    ** 指定设定图像尺寸。如果浏览器知道图像元素的宽度和高度,那么当图像被放置在页面上时,它就不必四处移动内容。显而易见,这被当前的响应式设计趋势复杂化了。* 避长后代选择器。带有许多标签的长后代选择器往往计算量很大。* 避免使用通用选择器。通配符()选择器是所有选择器中计算量最大的选择器。 尽量指定你希望过渡的属性,而不是使用【全部】。虽然与重排没有直接关系,但在转换中使用“all”选项是浪费,因为浏览器被迫跟踪元素的每一个可能的变化。指定您希望跟踪和更改的单个属性,比如opacity,效率要高得多。** 使用风格分析器。(参见图 10-1 。)

*9781430247227_Fig10-01.jpg

图 10-1。一个剖析工具,比如 Chrome 中的时间轴开发工具或者 Opera 蜻蜓中的风格剖析工具,可以帮助你突出你的 CSS 特别低效或者缓慢的地方

自动前缀工具:客户端

为了在旧版本的浏览器中获得支持,CSS3 转换、过渡和动画必须作为单独的声明,使用正确的浏览器厂商前缀,如第一章中所述。虽然为单个转换维护五行不同的代码肯定是可以实现的,但是维护任何更复杂的代码都是一场噩梦。虽然 Prefixr (http://prefixr.com)等工具可以向现有代码添加前缀,但它们对于开放更改的代码来说并不现实:对原始 CSS 的任何更改都意味着您需要再次经历相同的过程来添加前缀。这个问题有几种可能的解决方案,一种是服务器端的,另一种是客户端的,每种都有自己的优缺点。

-无前缀

希腊开发人员 Lea Verou (http://lea.verou.me)编写了一个流行的、轻量级的、有效的脚本,将它放入一个页面中,将根据查看页面(http://leaverou.github.com/prefixfree/)的浏览器的需要定制任何无前缀的 CSS 代码。

这是我个人对于轻量级工作的首选解决方案(比如在一篇博文的页眉制作一个 CSS3 动画);它允许我编写符合预期最终规范的单行代码,从而最小化文件大小,并让脚本处理向后兼容性。但是,有几个问题需要注意:

  • 有一个强有力的论点是,这种 CSS 声明转换不是客户端脚本的角色,而是服务器端脚本的角色,如下所述。
  • 浏览使用-prefix-free脚本但关闭了 JavaScript 的站点的用户——直接或通过诸如 NoScript(http://noscript.net)SPI_ AMP _ AMP;并且正在使用仍然依赖于供应商前缀的浏览器,将看不到任何转换、过渡或动画。然而,这个特殊的受众群体很小,尤其是考虑到支持无前缀 CSS3 的浏览器数量,这个群体的规模正在迅速缩小。此外,如果你遵循了第二章中的渐进增强和优雅降级的原则,缺少 CSS3 应该不会影响用户享受或使用你的网站的能力。
  • 在某些情况下,从服务器交付带有标准前缀的 CSS3 可能会稍微快一些,因为-prefix-free必须先处理 CSS 客户端才能使用。实际上,这通常由其他解决方案中所需的服务器端处理来平衡,或者与全前缀 CSS 代码相关联的较大文件大小。
  • 对于 Firefox 3.6 或更低版本,内联样式中出现的无前缀属性不会被转换为无前缀属性(这是一种非常罕见的情况,至少对于大多数站点及其访问者来说是这样)。

萨斯、莱斯、指南针和工具包

SASS (http://sass-lang.com)和 LESS (http://lesscss.org)可能最好被描述为 CSS 的“元框架”,允许诸如变量、函数、循环、自动验证、优化和代码精简、嵌套规则以及(与我们的兴趣最相关的)通过“mixins”自动添加 CSS3 前缀等功能两个框架都将自己宣传为 CSS 扩展,尽管这不应该被认为是 W3C 的认可。(也就是说,CSS 框架推动的许多创新,比如变量,正在新的 CSS 模块中被采用。)

LESS 通过 JavaScript 工作,在运行时将一个注入较少的样式表(styles.less)翻译成浏览器就绪的 CSS:结果,它分享了-prefix-free 的许多优点(和缺点)。SASS 采用的方法是把用 SASS ( styles.scss)编写的样式表预编译成一个完整的.css文件,每个浏览器都可以使用。

Compass (http://compass-style.org/)将 SASS 的许多最佳附加功能捆绑在一起。管理不同的 SASS 工具和扩展有些困难,因为它们必须像 Ruby gems 一样通过命令行来控制。CodeKit (http://incident57.com/codekit)是一个用于 Mac OS X 的框架管理器,它将所有功能(包括 LESS、Stylus 和 Compass)整合在一个图形用户界面中,还提供了一些其他不错的功能,比如当 CSS 发生变化时,在打开的浏览器中自动刷新页面。

最后,包含一个“mixin”有助于进一步简化代码;像 Bourbon (http://thoughtbot.com/bourbon/)或 Compass 这样的脚本库将允许您以这种方式在 SASS 中输入一个简单的过渡。(清单 10-1 中的代码以 Compass 语法显示。)

清单 10-1 。 使用 SASS Mixin 生成厂商前缀代码

#element { 
@include transition-property(width);
@include transition-duration(2s);
@include transition-timing-function(ease-in); }

#element:hover {
  width: 180% 
}

清单 10-4 中的代码在编译时会自动扩展以覆盖所有浏览器厂商的前缀。

自动前缀工具:服务器端

CSS Prefixer (http://cssprefixer.appspot.com)采用服务器端的方法:作为 Python 脚本运行,当提供一个.css文件时,它将非前缀的 CSS 转换成供应商声明。虽然它比客户端解决方案 like -prefix-free 或 LESS 更可靠,但它不尝试任何类型的客户端检测:为每个可能的浏览器生成的 CSS 都有前缀,这大大扩展了代码库和文件大小。

基于 GUI 的 CSS3 动画工具

随着 CSS3 动画变得更加雄心勃勃和复杂,文本编辑器开始受到挑战:虽然它们非常适合小型项目,但可视化工具在分别制作多个元素的动画时具有显著的优势。该领域发展迅速,以下仅是一个选择。

Sencha 动画师

Sencha Animator (www.sencha.com/products/animator)是最受欢迎的工具之一,它使用熟悉的时间轴 UI 和一整套变换和关键帧工具来创建 CSS 动画(见图 10-2 )。

9781430247227_Fig10-02.jpg

图 10-2。Sencha 动画师截图

然而,应用的输出有些混乱,使得结果很难在任何其他应用中使用;它呈现作品的默认方式(通过 JavaScript,并且只使用 Firefox 和 Webkit 的供应商前缀代码)意味着结果必须经过大量编辑才能完全跨浏览器兼容。

Adobe Edge 动画

Adobe Edge Animate (http://html.adobe.com/edge/animate)是 CSS 动画工具系列的最新成员(几乎还在测试阶段),是一个非常有前途的应用,它建立在标准的 Adobe UI(和 Adobe 的 Creative Suite 6 的默认深灰色主题,如图 10-3 所示)上,但它增加了许多重大改进。它还使用 JavaScript 作为框架来支持 CSS3 动画,但它支持所有现代浏览器和带有供应商前缀的旧版本。

9781430247227_Fig10-03.jpg

图 10-3。Adobe Edge Animate 截图

可制作动画

在为 AMC 电视台的《广告狂人》(见http://stuffandnonsense.co.uk/content/demo/madmanimation/ and Figure 10-4) )的片头制作了一部非常受欢迎的 CSS3 动画而引起轰动之后,的可动画制作(《http://animatable.com》)的发展似乎已经停滞,或者至少已经沉寂;然而,关注产品的突破性变化仍然是值得的。

9781430247227_Fig10-04.jpg

图 10-4。还是出自《广告狂人》演员表由 Animatable 创作的 CSS 动画序列

喧嚣炒作

在这里描述的所有工具中,另一个 web 动画 GUI 是对 JavaScript 投资最多的:该应用将自己描述为“HTML5 动画工具”,而不是 CSS3 开发程序。这很遗憾,因为它的用户界面可能是最直观的,如图 10-5 所示。

9781430247227_Fig10-05.jpg

图 10-5。骚动炒作动画 UI 截图

未来趋势:CSS 自定义滤镜

之前被称为 Web Shaders 的 Adobe 技术,W3C 已经采用了这项新技术作为一项名为 CSS 自定义过滤器的提案。

在第九章的中探讨的标准滤镜可能最好被描述为简单的图像转换器:hue-rotateblursepia始终如一地移动受影响图像的所有像素,仅此而已。标准 CSS 滤镜不能影响单个像素:你不能在半幅图像上使用滤镜,也不能使用滤镜扭曲图像。自定义滤镜将这一过程明确拆分为两个独立的功能:可编程的片段着色器 可用于调整像素的颜色,动画擦拭,以及创建自定义过渡;顶点着色器将每个 DOM 元素的区域视为一个可视网格允许设计者对图像和其他元素的表面进行波纹、弯曲、扭曲和变形。

如当前规范中所提议的,对定制过滤器的调用看起来像清单 10-2 中的。

清单 10-2 。 一个利用 CSS 自定义滤镜的过渡

#shaded-element { 
filter: custom(url(‘wobble.vs’) 
      40 40,
      amplitude 60,
      amount 0.0);
)
transition: filter ease-in-out 2s;
}

数字对40 40用于定义元素被划分成的虚拟网格的密度:更多的划分将创建更平滑、更流畅、更细致的效果。amplitude是效果的强度,amount是元素受影响的程度。

第一行中提到的wobble.vs(顶点着色器)文件是用 OpenGL ES 着色语言编写的,使用与 WebGL 相同的语法在网页上创建浏览器原生 3D,如清单 10-3 所示。

清单 10-3 。 在 OpenGL 上是着色器

precision mediump float; 
attribute vec3 a_position; 
attribute vec2 a_texCoord; 
uniform mat4 u_projectionMatrix; 
uniform float amplitude;
uniform float amount;
varying vec2 v_texCoord; 
const float rotate = 20.0;
const float PI = 3.1415926; 
mat4 rotateX(float a) {. . .} 
mat4 rotateY(float a) {. . .} 
mat4 rotateZ(float a) {. . .} 
void main() { 
    v_texCoord = a_texCoord.xy; 
    vec4 pos = vec4(a_position, 1.0);
    float r = 1.0 - abs((amount - 0.5) / 0.5); 
    float a = r * rotate * PI / 180.0;
    mat4 rotX = rotateX(a);
    mat4 rotY = rotateY(a / 4.0);
    mat4 rotZ = rotateZ(a / 8.0);
    float dx = 0.01 * cos(3.0 * PI * (pos.x + amount)) * r;
    float dy = 0.01 * cos(3.0 * PI * (pos.y + amount)) * r;
    float dz = 0.1 * cos(3.0 * PI * (pos.x + pos.y + amount)) * r;
    pos.x += dx;
    pos.y += dy;
    pos.z += dz;
    gl_Position = u_projectionMatrix * rotZ * rotY * rotX * pos; 
}

如你所见,这与你所熟悉的 CSS 非常不同:这是一种全新的语言。然而,将所有这些作为#shaded-element(如清单 10-4 所示)的过渡,很大程度上回到了你在第二章中探索的原则。

清单 10-4 。 一个利用 CSS 自定义滤镜的过渡

#shaded-element:hover { 
    filter: custom(url(‘wobble.vs’)
    40 40, 
    amplitude 60, 
    amount 1.0); 
}

过滤器上的所有控件保持不变,除了amount;原始默认状态的转换将确保元素平滑地转换到新的悬停状态。

自定义过滤器承诺对 HTML 内容进行高度的可视化控制,这是标准 CSS 无法实现的,并且有可能彻底改变 web 上的动画和交互。然而,这个过程需要一些时间:规范非常新,在撰写本文时,只在 Chrome 的最近版本中得到支持。最终确定规范、获得跨浏览器支持以及处理诸如安全等重要问题可能需要几年时间。

未来趋势:混合和合成

Adobe 还在混合和合成领域推进 CSS,采用您可能在 Adobe PhotoShop 和 Illustrator 中熟悉的控件(如乘法、变暗、变亮和高级剪辑)并将它们转换为 CSS。

虽然这项工作只是在建议阶段,但如果实现的话,它有望成为一个视觉上更加生动的网站,特别是如果属性可以被动画化的话。可以想象,从长远来看,位图和矢量插图工具将越来越多地成为制作过程早期阶段的内容创造者,而大部分编辑工作将使用 CSS 在浏览器中实时完成。

未来趋势:协调 CSS3 和 SVG

对于两种可以很好地协同工作并相互影响的 web 技术(特别是在转换和过滤领域),CSS 和 SVG 仍然存在大量的冲突。

虽然 CSS 可以用来制作许多 SVG 表示属性以及 SVG 图像本身的动画(正如你在第九章中看到的那样),虽然 SVG 可以制作自己的动画——使用<animate>标签,这是 SMIL(同步多媒体集成语言)标准的一部分——但是将两者结合起来目前是非常困难的。CSS 关键帧动画规则会覆盖 CSS 过渡和 SVG (SMIL)动画,但在涉及 CSS 过渡和 SMIL 动画时会发生冲突。由于 Internet Explorer 10 不支持 SMIL,兼容性问题变得更加复杂。

W3C CSS-SVG 特效工作组正在解决这些问题,但是这个过程可能带来的发展和变化目前还不清楚。

摘要

从 Flash 和 JavaScript 是在网页上实现运动的唯一方式的时代开始,Web 动画技术已经走过了很长的路,而且随着您在这里看到的工具和语法的出现,以及那些即将出现的工具和语法的出现,它们肯定会走得更远。

这本书提供了对基于现代标准的 CSS3 动画的介绍和深入研究。一路上,您探索了 CSS 变换、过渡、关键帧动画和 3D 操作,并将它们与 SVG、JavaScript 和响应式设计等其他技术结合起来。使用这种混合语言进行开发的支持工具正在出现,但是最可靠的——也是唯一能让您自由地保持在前沿的工具,如果您选择追求它的话——是不起眼的文本编辑器。

编写带有供应商前缀的跨浏览器兼容性 CSS 声明的漫长时期即将结束。最近的浏览器版本完全放弃了你在本书中看到的属性。

这种快速采用技术的新环境正在形成——“下一个网络”——承诺比任何已经成为的事物都更加开放、可能性更加丰富、更具创造性。我很兴奋地想看看它可能会发现什么新的前景,我希望你也是。

我期待着看到你的作品并得到你的反馈——并从你对 CSS3 动画的探索和创新中得到启发。*

posted @   绝不原创的飞龙  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示