Welcome

“Tell me and I forget. Teach me and I remember. Involve me and I learn.” Benjamin Franklin

欢迎来到 CSS Animation 101,感谢你选择这本书。

很高兴你选择学习 CSS Animation,本书会以轻松有趣的方式来介绍这个话题,希望能够带给你帮助。

我们会学习 CSS 中的 transitions 以及 animations 。我相信,当你读完本书之后,你会对 CSS animations 有一个更深的理解,也会在工作中更好地使用它。

在本书中,我们会学习如何搭建自己的开发环境,然后学习一些 animation 的例子。

Hello,I’m Donovan

Donovan Hutchinson
Donovan Hutchinson

大家好,我叫 Donovan ,是一名设计师和前端工程师。工作时间,我会依照 UX 的设计原则进行网站动效设计,以提升网站的用户体验。业余的时候我就会写一些文章。我写过很多关于 CSS 的文章,也在 Smashing Magazine, Net Magazine, Tuts+, Adobe Inspire 上发表过很多。这是我的个人网站 Hop.ie

今年以来,我一直在 cssanimation.rocks 上写教程,主要是关于网页动效的,欢迎大家一起交流。

本书主要介绍 CSS 中的动画 (CSS animation) ,目的就是让大家了解 transitionanimation 这些属性是干嘛的,内部的原理,以及如何使用。

等读完这本书,我相信大家一定可以在开发过程中运用这些技巧了。

Book structure

本书涵盖以下内容:

  1. 什么是动画(animation)?我将解释一下为啥我们需要动画,并且会简单介绍 transitionanimation 属性,然后给大家看一些例子。
  2. transition 属性。我们将会学习 transitions 的原理,以及如何控制它来制作动效。
  3. animation 属性。我们将学习怎样使用 keyframe 来制作比 transition 复杂的多的动效。
  4. 通过几个复杂的例子学习如何将 transition 和 animation 结合起来使用。还会向大家介绍一些有用的 CSS 资源和 JavaScript 工具。

Help and support

如果大家有什么想法或者疑问,欢迎大家通过邮件(donovan@cssanimation.rocks),或者 Twitter ([@donovanh](https://twitter.com/donovanh))联系我。

Need to brush up on your CSS?

如果你是一个 CSS 新手,那你需要熟悉一下 CSS 的基础知识。基本上你只要了解什么是 CSS,什么是 CSS 属性就可以了。

这里有一些不错的入门资源推荐给大家:

Homework

每一章节后面都会有一个课后作业的部分,我会给大家出一些小题目,目的是让大家更好的学习以及巩固知识。做不做完全取决于你,当然,我建议大家最好都去想一下做一下,你会发现自己对 CSS 动画的理解会更加深刻。

准备好了么?让我们开始吧!

Why Animation?

“Animation is about creating the illusion of life.” Brad Bird

在深入学习 CSS 动画之前,我们先想想为啥需要动画。

More than words alone

人们对会动的东西更加关注,所以在网站的设计和开发中,如果能适当地添加一些动画,不光可以丰富网站的视觉和交互体验,还能更有效地抓住用户的眼球,吸引他们的注意力,从而更加关注和沉浸在我们的网站里,这可比只用简单的文字好多了。而且现代浏览器的性能越来越高,对动画地支持也越来越好,更有利于我们使用动画了。【Tips:也不能滥用动画。如果滥用反而会造成注意力的分散。】

What is animation on the web?

动画可以吸引用户注意力,同时完成信息的传递,这对网站有莫大的好处呀。

比如 CodePen 里面的保存按钮就有一个很别致的动画效果:当你修改文件之后,按钮就会抖动,提醒用户有文件需要保存。这样子的效果非常醒目,如果什么都不加,可能不少人会忘记要保存。

Animation Saved Button
Animation Saved Button

人类天生就对移动的物体敏感,这是人类进化的结果。在编写网页时花点小心思,添加点别致的小动画,会让人感受到你的匠心独运。

当元素在网页上出现时我们也可以添加动画。

Animating list items (https://cssanimation.rocks/list-items/)
Animating list items (https://cssanimation.rocks/list-items/)

上面的例子中,通过动画让用户更加明显和生动地感受到有新内容添加到列表里了,而不是很生硬的一下子就出现,这样子体验会更好一些。多看几个例子:

游戏 Portal

Portal animation
Portal animation

sprout.js

Animated chart from Sprout
Animated chart from Sprout

With great power comes great responsibility

给元素添加动画很简单,但要切记,在同一“时刻”不能添加太多。不然,不仅不能吸引注意力,让用户关注当前的内容或者操作,反而会让他们没有具体的关注点,不知道该干嘛。

当然,这只是大多数情况下的一种准则。【Tips:“不能添加太多”更多的是指不能让效果显得杂乱】

你完全可以使用大量的动画来创作炫目的效果。如果真的需要这么做的话,请注意:当用户需要关注的”点“(可能是某些文字、图片这种内容性的东西或者需要点击某个按钮这种操作性的东西)出现时,你应该考虑可以暂停这些效果,让他们好好的关注这些需要关注的东西。

下面的例子就很好的说明了这点:当需要指引用户去查看按钮的的时候,动画就停止了。

National Parks from Rally Interactive
National Parks from Rally Interactive

Inspiration

动画制作有着悠久的历史。我写过一篇文章 Principles of Animation for the Web。文章里的很多内容取材于迪士尼1981年出版的书 The Illusion of Life: Disney Animation.

如果你想更深入了解,可以查看 youtube 上的 Animator’s Survival Kit videos

有个网站推荐给大家 Hover States,上面有很多关于网页动画的例子。Dribbble.com 也很不错。

比如 Dribbble 上有展示 Google’s Material Design principles的例子。在搜索栏出入 animation 查看更多信息。

大家也可以多关注下 CodePen,上面有很多很棒的 canvas 和网页动画的例子。

Summary

Homework

试着在工作中使用 animation 吧。

我们不能让所有的东西都”动起来“,但可以在一些关键的地方添加一些合理精致的小动画,让用户更好的使用我们的网站和服务。想一想,是不是有些需要操作的地方没有引起用户的注意?是不是有些内容的变化太突兀,太生硬?如果有,那就可以考虑使用 animation 来优化。

多去一些设计网站(Hover StatesLittle Big DetailsDribbble)看看,会给你带来不少的启发呢。

Creative environments

“You don’t learn to walk by following rules. You learn by doing, and by falling over.” Richard Branson

现在我们来看看如何在浏览器中构建和查看CSS animations。 在开始敲代码之前,我们先来创建一套工作流。

我们将介绍两种方法:在浏览器中(线上)开发和离线(本地)开发。

In the browser

最简单的就是直接在线上开发然后看效果。我经常使用的是CodePen,还有一个叫JS Fiddle

在本课程中,我将使用CodePen编写示例,所以大家有必要熟悉下它的使用。

CodePen是一个在线写代码的平台,你可以在上面编写 HTML、CSS 和 JavaScript ,然后立刻就能看到结果。屏幕被分成四个区域,分别是结果预览区,HTML,CSS 和 JavaScript编辑区。每个区域中都有一个设置选项可以进行不同的设置,比如设置用 Sass 代替 CSS。

Local development

对于复杂的项目,我更喜欢在本地开发。

Basic option: Simple HTML/CSS

最简单直接的就是创建一个 HTML 文件(filename.html)和一个 CSS 文件(filename.css),然后在 HTML 文件中链接 CSS 文件。这种方法虽然简单,但是写的时候要不断的在浏览器和编辑器直接来回切换,很麻烦。

我已经创建了一组基本的 HTML 和 CSS 文件,大家可以下载使用,下载地址:https://github.com/cssanimation/starter/archive/master.zip

Starting files
Starting files

Dreamweaver / Macaw / Muse / Coda / Sublime

编辑器方面你可以选择任何一个你喜欢的用,这无所谓的。有一些编辑器可以对动效进行可视化编辑,如果你想用,也没问题的。

就我个人而言,我还是建议你自己去敲这些代码。这样子会加深对 CSS 的理解,以后遇到问题解决起来也容易,写复杂动效的时候也会更顺手。

Gulp

如果你熟悉 Github、Node,你会想在自己的电脑上搭建一套开发的脚手架。

Gulp 是以 Node 为基础,它的处理速度非常快。

它可以将 Sass 编译成 CSS ,自动添加浏览器前缀,同步浏览器渲染(这样你就不需要每次更新代码后要刷新浏览器再看效果了)。

如果你使用过Grunt或其他构建工具,你就会发现过程很类似。

我已经创建了一个Github库。如果你习惯使用Git,你可以去下载然后根据readme文档来进行配置。

如果愿意,大家可以一起改进它,欢迎 pull request。

In summary

在学习 CSS 动画的时候,你可以尝试上面提到的不同的方法。你可以自己搭建环境,也可以使用CodePen,都可以。

Homework

注册CodePen,然后尝试添加一些HTML和CSS来看一下效果。 也可以在首页上查看流行的CodePens。

Optional::如果你想本地开发,请下载下面的文件:

下一篇: 我们将学习 transitions!

Transitions

我们来看下 transition 这个属性。

以前的浏览器功能比较简单,那时候无法显示图片,也只能处理一部分字体的渲染。后来出现了 CSS ,它的出现给网页带来了无限的可能。

在浏览器上进行动画制作也不是什么新鲜事了,Flash,Canvas 还有 JavaScript 都可以进行制作动画。现在我们又有了新选择:CSS。

Transitions

使用 CSS 制作动画的一种方式就是使用 transition 属性。啥是 transition ? transition 指从一个“状态”到另一个“状态”的动画模拟。

Transitions: A to B
Transitions: A to B

当我们告诉浏览器,我们想在某个元素上使用 transition 时,就是让浏览器在状态的变化过程中对属性的值进行自动插值。

Animated transition from A to B (http://codepen.io/donovanh/pen/RNdxqw)
Animated transition from A to B (http://codepen.io/donovanh/pen/RNdxqw)

举个例子,我们可以在一个元素鼠标悬停的时候,使用过渡(transition)来改变元素的样式,让浏览器产生从起始状态到终止状态的平滑的过渡效果。

Animated button (http://codepen.io/donovanh/pen/MYQdZd)
Animated button (http://codepen.io/donovanh/pen/MYQdZd)

Transition properties

我们可以在元素的很多属性上创建过渡效果。我们可以控制过渡的快慢,延迟,还可以用 timing function 控制过渡具体的变化速度。来看几个例子。

Combining transitions (http://in-ni.com/)
Combining transitions (http://in-ni.com/)
More transitions (http://codepen.io/suez/pen/XJGOyL)
More transitions (http://codepen.io/suez/pen/XJGOyL)

In summary

transition 是指从一个状态到另一个状态的变化。比如当鼠标在某个元素上悬停时,我们会修改它的样式,采用 transition 可以创建一个平滑的动画效果。

Animations

目前为止,我们讨论了为什么需要动画,介绍了一些激发灵感的资源,也介绍了一些对开发有帮助的工具和网站,并且简单了解了过渡的概念。

下一步,让我来介绍一下 animation 属性。

Animation in the browser

过渡(transition)和动画(animation)是相似的。两者都是 CSS 的属性,并且都可以通过持续时间(duration),延迟(delay)以及其他属性控制浏览器制作动画效果。

当然也有不同,过渡指从一个状态到另一个状态的平滑的变化过程,而动画可以是多个“状态”间的变化。

Transitions: A to B
Transitions: A to B
Animations: A to B to C
Animations: A to B to C

动画更适合相对复杂的场景。上面的例子中有三种状态(A,B,C)。transition 只会从A开始一直到C结束,而 animation 允许我们添加状态B,并且从A到B再到C经历完整的3个状态。

动画还有一点不同,它可以自动开始。过渡一般需要通过添加样式类或更改状态(如悬停)来触发,但动画可以在页面加载时自动启动。

Examples

Codepen 的“Save”按钮就是一个很好的例子。它能很好的让人们注意到这个按钮。

Save Button on CodePen
Save Button on CodePen

该效果是由一系列的keyframes组成,它们将告诉浏览器从左到右如何去摆动按钮。后面我们会深入研究 keyframes。

另一个示例是来自 Twitter 的 app 构建平台Fabric

Fabric hero image animation
Fabric hero image animation

最后,是我去年做的一个例子,这是一个 CSS Mac Plus,用来在网上 theWeb.is teaser site 展示欢迎信息。

Mac Plus created using CSS
Mac Plus created using CSS

CSS Mac Plus 可以在 CodePen 上面看到,这里是关于如何实现的指导。

Transitions vs. Animations

transition 是指从一种状态到另一种状态(A 到 B)的变化,通常是由某种“动作”触发,比如鼠标悬停,或者用 JavaScript 添加或删除样式类。

animation 更加复杂一些,它允许你按照实际需求添加很多的 keyframes 来创建动画。它可以自动触发,并且可以循环。

Transition vs Animation
Transition vs Animation

后面我们会学习 animation 属性。多去找一些实际的应用例子,如果有不错的例子,记得告诉我!

Homework

浏览网页时要多多留意动画。当某物以某种方式移动以引起你的注意的时候,这通常就是一个 animation。

如果你已经下载 HTML 和 CSS 的脚手架,找到 animation 看一下,与 transition 不同,animation 还需要第二部分,称之为 keyframe。试着改变其中的一些值,看看会产生什么效果。

Transitions in action

前面我们介绍了 transitionanimation 这两个属性,这一节我们来看看具体的代码。

Transitions

在浏览器中,一个元素从一个状态转变成另一个状态,我们称发生了过渡(transition)。浏览器负责来渲染状态变化过程中的每一帧从而创建一个动画效果。

transition 是 CSS 中的属性,就像给元素设置 heightwidthborder 一样,我们也可以给元素设置 transition

transition 怎么用呢?来看下面代码:

transition: background 0.5s linear;

在上面的代码中,我们告诉浏览器,我们希望在 0.5 秒的时间里,按照 linear 的时间函数(timing-function)来改变某个元素的 background 属性。

下面结合具体的例子来看一下:我们希望当鼠标在按钮上悬停时(hover)改变按钮的 background

button {
  background: white;
  transition: background 0.5s linear;
}

button:hover {
  background: green;
}

这里有一点要注意,transition 属性的位置要放到 button 中。这样会告诉浏览器,不光按钮从初始状态变成悬停(hover)的时候要添加过渡效果,当从悬停状态变回初始状态时也要添加过渡效果。

如果我们把 transition: background 0.5s linear; 这句放到下面 button:hover 里,那么当按钮从初始状态变成悬停状态时会有过渡效果,但当从悬停变回初始状态时,就立刻改变了 background,而没有过渡的效果。

Example: Button transition

你可以查看 CodePen 上的代码,并尝试修改代码来体会不同的效果。

请注意 CodePen 代码里以 transition- 开头的属性。这里用了全写的方式。

transition-property: all;
transition-duration: 0.4s;
transition-timing-function: ease-out;

上面的代码的意思希望浏览器在0.4s的时间里改变all所有的属性,包括 colours, size, position 等。

可以将 transition-timing-function 设置成下面的贝塞尔曲线函数形式,试试效果会发生什么改变。

transition-timing-function: cubic-bezier(0.59, -0.26, 0.33, 1.42);

Prefixes and browser compatibility

上面的代码,为了书写和阅读的方便,都没有添加浏览器前缀,如果要发布正式版,请在属性前加上对应的浏览器前缀。

可以使用 Autoprefixer(Codepen 上 css 设置的一个自动添加选项),或者手动添加。

    -webkit-transition: ...;
    -moz-transition: ...;
    transition: ...;

Homework

大家可以试着修改上面的代码来看看会有什么效果。

这有一个好玩的例子,你可以试一下:awesome hover style

Transitions properties

前面我们简单介绍 transition,下面我们来具体的看下它有哪些属性和对应的含义。

Shorthand vs Longhand

在写 CSS 样式的时候我们经常将多个属性写成简写( Shorthand )的形式。比如设置元素的 padding 值我们就可以这么写:

    padding: 10px 20px 15px 25px;

上面和下面的代码是等价的:

    padding-top: 10px;
    padding-right: 20px;
    padding-bottom: 15px;
    padding-left: 25px;

同理,transition 也有其简写形式:

    transition: all 0.5s 1s linear;

transition 的简写形式对应各属性含义如下:

    transition: [property] [duration] [delay] [timing-function];

上面的例子中,各属性也可以单独写::

    transition-property: all;
    transition-duration: 0.5s;
    transition-delay: 1s;
    transition-timing-function: linear;

让我们来看下各个属性具体的含义。

transition-property

通常是简写形式的第一个属性,规定应用过渡的 CSS 属性的名称。比如要修改 background ,就可以在这里写 background 。也可以使用 all ,所有适用的CSS过渡的属性上创建过渡效果(不是所有的属性都可以创建过渡效果的)。

transition-duration

transition-duration 表示过渡效果的持续时间。transition-duration 设置成3s的持续时间是指设置3倍的1000ms

transition-delay

transition-delay 表示过渡效果的延迟时间(效果开始前的等待时间),单位可以是秒或者毫秒。3s 表示3秒,100ms表示100毫秒,也可以写成0.1s

transition-timing-function

transitionanimation 都会使用时间函数(timing function),时间函数有很多可选值,这里就不一一列举了,后续会详细说明。

Things transitions don’t work on

过渡效果(transition)可以应用在很多的属性上,比如 positionsize,colour,border,background-position,但有些属性是不能应用过渡的,比如 font-family

用CSS创建的背景图像(例如渐变效果),不能对其属性使用动画。这意味着浏览器用每帧动画重新创建背景图像,因此不支持。

不过你可以opacitybackground-position上使用过渡。通过移动背景图(background images)或者隐藏背景图可以创建很丰富的效果。

举个栗子说明下:Baymax example

Source: http://cssanimation.rocks/baymax/
Source: http://cssanimation.rocks/baymax/

再来一个:button sheen effect

Source: https://cssanimation.rocks/pseudo-elements/
Source: https://cssanimation.rocks/pseudo-elements/

Homework

我创建了一个简单的 transtion 效果(Codepen),你可以尝试修改不同的属性来创造不同的效果。

Timing functions

时间函数(timing function)是用来描述过渡过程中,属性值变化速度的。如果过渡过程中属性值一直以一个固定的速度变化,那就会显得千篇一律,不那么生动。有了时间函数(timing function)的加持,我们可以制作更加生动有趣的效果。

举个例子:

第一个例子,我们使用 linear

Linear transition
Linear transition

第二个例子,我们使用 cubic-bezier

Cubic-bezier timing function
Cubic-bezier timing function

通过 cubic-bezier,我们让边框开始时先往里缩一下,然后再开始改变。结束的时候先变大一点然后再缩回到正确的大小。

下面我们来具体看下 timing-function

我在CodePen上写了一个例子,大家可以一边看,一边修改例子来查看效果。

Linear

Linear
Linear

linear 表示属性值按照一个固定的速度线性的变化,中间不会有突变,所以不会出现加快或减慢的状态。非常适合速度不变的场景下使用,比如车窗外不断飞过的风景或者一直旋转的月亮。

Ease-in

Ease-in
Ease-in

ease-in 表示属性值先以较慢速度变化,然后速度越来越快,就好比一个球从高处落下,一开始下降的速度很慢,然后越来越快。

Ease-out

Ease-out
Ease-out

ease-out 刚好跟 ease-in 相反,一开始速度快,然后速度越来越慢。最适合元素从屏外进入屏内进行显示的情况。

Ease-in-out

Ease-in-out
Ease-in-out

ease-in-out 是上面两个的合成,一开始慢,然后变快,然后又变慢。做加载的效果时用这个时间函数效果会很不错。

Cubic-bezier

Cubic-bezier (custom)
Cubic-bezier (custom)

上面所讲的时间函数本质上都是贝塞尔曲线。利用 cubic-bezier 我们可以自定义具体的变化曲线。

cubic-bezier 有4个参数,代表两个控制点的坐标。

    transition-timing-function: cubic-bezier(1,-0.49,.13,1.09);

两个控制点坐标为 (1, -0.49)(.13, 1.09),画个坐标系来看一下:

Source: http://cubic-bezier.com/#1,-0.49,.13,1.09
Source: http://cubic-bezier.com/#1,-0.49,.13,1.09

有个在线工具cubic-bezier.com可以实时看到通过拖动控制点生成不同的曲线。

把控制点坐标设置大于1,看看会有啥效果。:)

Steps

Steps
Steps

目前为止讲过的时间函数(速度的变化)都是连续的曲线,steps 可以将过渡时间分成大小相等的时间时隔来运行。比如使用 steps(4),效果就会变成如上图那样不连续的效果。

这适合做精灵动画(sprite animation)。比如一个精灵动画有4帧,设置steps,就可以通过改变background position 来创建动画了。

举个栗子:Twitter fave button

You can also specify whether the transition holds the first frame for the fragment of the duration or whether it holds the final frame. The default is end, as this assumes that the first frame in the sprite is already showing before the animation begins.

steps有两个参数,第二个参数默认值是endstart 表示要过渡的属性值会在开始时就立马变成第一个步进点(this first step)对应的属性值,并保持一个步进的时间(step duration),而 end 表示要过渡的属性值在开始的时候并不会立马改变,而是在保持一个步进时间之后,变成第一个步进点的属性值。【Tips: 按照原文翻译有点不好翻,就用自己的理解写了下。】

可以按下面的形式去指定 end 还是 start

    transition: all 2s steps(10, start);
    transition: all 2s steps(10, end);

More examples

有关 timing function 的更多问题,我已经在medium上写了一篇文章可供参考。

Homework

尝试修改上节的例子,修改 transition-timing-function 属性来查看不同值的不同效果。

这里还有一个例子,虽然这个例子使用的是 animation,但它里面 timing function 的使用是跟 transition 一样的。

Multiple transitions

到目前为止,我们都是一次在元素上使用 transition 修改一个属性值,接下来我们将看一些复杂的例子:如何使用一个 transition 来修改很多属性,如何使用多个 transition 来创造更好的效果。【Tips:使用多个 transition 并不是像下面那样写多个 transition。要在一个元素上使用多种过渡,可以在一个 transtion 里写,具体看本节末尾处的说明】

// 错误的例子。并不是预想的 width 和 background 同时添加过渡效果。
    transition: width 1s ease-in-out;
    transition: background 1s ease-out;

Example 1: Fancy button

前面我们提到的 button 的例子比较简单,这里我们来看个复杂的例子。

Source: http://codepen.io/donovanh/pen/YPMGpJ
Source: http://codepen.io/donovanh/pen/YPMGpJ

在这个例子里我们创造了一个比较复杂的 hover 效果,但我们其实关键的样式只有一句话:

    transition: transform 0.4s cubic-bezier(0.72, -0.61, 0.25, 1.51);

接下来我们分析下这个效果是怎么做的。

本例中的按钮由两个 icon 和两个 text 组成。初始状态(鼠标未悬停)显示 follow me 和 twitter 的 icon,@ 标志和 cssanimation 不显示。

当鼠标悬停时再显示 @ 标志和 cssanimation 文本。

我们使用 CSS 中的 transform 来实现上面的显示和隐藏。对 twitter icon 进行绝对定位,设置其 lefttop

    .icon {
      position: absolute;
      left: 0.75em;
      top: 0.75em;
    }

鼠标悬停时添加 transform 属性将其移出 button。在外层的容器上添加overflow: hidden 就可以将 twitter icon 隐藏了。

    a:hover .icon {
      transform: translateY(3em);
    }

如果不添加 transition,元素就会突然消失,效果并不好。在这个例子里,button 里的元素都是 span,所以可以写一条 transition 然后应用到所有的 span 上。span 的状态发生变化时都会使用这条 transition

    span {
      transition: transform 0.4s cubic-bezier(0.72, -0.61, 0.25, 1.51);
    }

CodePen 链接

Example 2: Background reveal

再看一个例子。在本例中,当鼠标在卡片上悬停时,下方会显示文字。

Source: http://codepen.io/donovanh/pen/LEvjJg
Source: http://codepen.io/donovanh/pen/LEvjJg

分析下这个效果:初始时其实 text 也是显示的,只不过设置了 opacity 为0,让它变得透明,所以看不见。鼠标悬停时,把 opacity 改为1,同时修改文本外层容器的高度。【Tips:初始时外层的 info 容器设置了 overflow:hidden, 同时对文本设置了 transform, 将其从可视区域移出去,并且设置其 opacity 为0,所以文字就被隐藏了】

如果不添加 transition,文字的出现就会显得很突兀,可以看下效果对比下。CodePen链接

我们把所有的 transition 整合到一起,就有了如图的效果。链接

这里我们用了两个 transiton 语句。

第一条告诉浏览器在0.5s的时间里,在所有可以添加过渡效果的属性上应用过渡效果。效果的变化速度用 cubic-bezier(.48,-0.28,.41,1.4) 来设定。在本例中用这句来改变了文本外层容器的高度。

    transition: all 0.5s cubic-bezier(0.48, -0.28, 0.41, 1.4);

第二条让文本移动了。

    transition: all 0.4s ease-out;

鼠标悬停时我们可以做很多事,比如本例中我们改变了 info 这个 div 元素的高度,还改变了 p 元素的位置。

本例中我们对不同的元素添加了不同的过渡,在实际工程中这样子做会给页面效果增色不少的。

Multiple transitions on a single element

我们不光可以在多个元素上使用多个 transition,我们还可以在一个元素上使用多个 transtion

比如有一个元素,我们希望它的背景和边框有不同的过渡效果,显然对所有的属性写一条单一的 transition 不能满足我们的需求。【Tips:比如希望背景的过渡持续时间和时间函数跟边框的不一样,那么 transition: all 1s linear 这样子显然是无法满足需求的。】

我们可以在一条 transition 语句里设置多个属性,语句间用 , 分开。

    transition: background 1s ease-out, border 0.5s linear;

上面的 transition 应用到某个元素上后,元素的 background 会和 border 采用不同的过渡效果。background 过渡持续时间1s,时间函数 ease-outborder 的过渡持续时间0.5s,时间函数是 linear

Transitions and JavaScript

到目前为止,前面我们举过的例子,都是使用 CSS 中的 transition 在鼠标悬停时和不悬停时添加过渡效果。

这些效果都需要被动地触发,就是要鼠标悬停在元素上或者从元素上移开。当然这不是触发这些效果的唯一方式,我们还可以使用 JavaScript 代码来触发这些效果。

Add or remove classes

transition 的作用就是在两个状态之间创建平滑的变化效果,不至于显得太突兀。既然是两个状态,那我们可以把这两个状态用不同的 class 来对应,然后通过 javascript 来控制添加和删除这些 class,从而触发效果。

看下面的例子,具体代码可见CodePen

Source: http://codepen.io/donovanh/pen/YPbxqa
Source: http://codepen.io/donovanh/pen/YPbxqa
<button id="show-element">Show it</button>
<div id="to-show" class="hide">
  <h1>Some hidden content</h1>
  <p>Pressing the button shows this content. Nice!</p>
</div>

在这个例子中,页面结构主要有一个 button 和一个 div 容器。

.hide {
  opacity: 0;
  top: calc(50% + 8em);
}
.show {
  opacity: 1;
  top: calc(50% + 6em);
}

初始时给容器添加了一个类名是 hide,设置其 opacity 为0,视觉上就不显示了。样式表里还有要给 show,设置 opacity 为1,为可见状态。

更复杂的例子可以看这篇文章Adding Appeal to Your Animations on the Web

在本教程的末尾我们还会学习怎么在滚动时触发 transitionanimation 来改变样式。

Controlling transitions with JavaScript

除了像上面那样给元素添加或者移除 CSS 类名,我们还可以像下面这样直接用 javascript 修改 CSS 属性。

    element.style.transition = 'opacity 1s ease-out';

实际应用里,假设我们有个 ID 是 js-show 的元素,我们可以这样设置:

    document.getElementById('js-show').style.transition = 'opacity 1s ease-out';

值得注意的是,如果采用上述方式去设置 transition,那要带上浏览器前缀:

    document.getElementById('js-show').style.webkitTransition = 'opacity 1s ease-out';
    document.getElementById('js-show').style.transition = 'opacity 1s ease-out';

Let’s recap

这一章我们系统地介绍了 transition,包括它的几个属性分值(duration,delay,timing function),还介绍了如何组合使用多个 transition 来创造复杂的效果,最后我们还尝试了用 javascript 直接控制 transition

下一章我们将讨论 animation 这个话题。

Homework

Before we start looking at the animation property, take some time to think about how you use transitions.

Can you think of ways they could help smooth the interactions or state changes on your pages? How might they add appeal?

Animations in action

前面我们讲了 transition 属性,现在让我们来学习下 animation 属性

A symbiotic relationship

给元素添加 animation 跟添加 transition类似。不过它还需要 keyframes

.element {
  animation: ...
}

@keyframes animation-name {
  /* Keyframes go here */
}

单独定义 keyframes 的好处是我们可以复用这些动画。

The animation property

我们通过 animation 属性可以将编写的 keyframes 应用到元素上。animationtransition 很类似,不过多了一些其他的选项。下面是 animation 的简写方式:

animation: change-background 4s linear infinite;

分开写就是下面这样:

animation-name: change-background;
animation-duration: 4s;
animation-timing-function: linear;
animation-repeat: infinite;

transition 需要指定一个目标属性,例如 “background” 或 “all”,animation 则需要带 keyframes 的名字来描述动画。

animation 拥有一些 transition 没有的属性。例如,我们可以告诉动画来回交替循环,而不是每次从头开始循环。

Keyframes

keyframes 是用来描述动画过程中一系列变化的。

我们用一个简单的例子来说明下:在网页上有一个 div 标签,它的背景颜色不断地在变,像下面图中显示的那样。

怎样描述这种变化呢?我们可以说“开始时蓝色,到一半时变成橙色,最后变成绿色”

如果再精确一点描述,我们可以用百分比来描述:

“0%的时候蓝色背景,50%的时候橙色,100%的时候绿色”

我们可以概括为:

0% Blue
50% Green
100% Orange

这样子我们就创建了动画整个过程中包含的“路径点”(waypoint)。 现在要做的就是将这些百分比按照 keyframes 的规则去写并命名。 结果如下:

@keyframes change-background {
  0% {
    background: blue;
  }
  50% {
    background: orange;
  }
  100% {
    background: green;
  }
}

这个动画名字叫 “change-background”。稍后我们会用到它。

结合下面的例子,我们可以看出,上面的百分比指的是在动画过程中,其对应的 keyframe 发生的“时间点”。还可以知道,我们只要告诉浏览器开始、中间和结束时的颜色就可以了,在这些状态之间变化时,浏览器会自动去计算颜色值的插值。

Source: http://codepen.io/donovanh/pen/WbqNwd?editors=110
Source: http://codepen.io/donovanh/pen/WbqNwd?editors=110

CodePen 链接

前面提到过,使用 animation-direction 可以让动画来回交替变化,看下面的例子,直观地感受下:

代码放到CodePen上了。 animation-direction 属性已经更改为 alternate

Prefixes

虽然我写的代码里没有加 -webkit- 等前缀,但如果要在实际工程里应用 animation,还是要添加对应的浏览器前缀。

在 CodePen 中,你可以使用 CSS 设置中的 “Autoprefixer” 选项。对于本地开发,我使用 Gulp 版本的 Autoprefixer。 Prefix Free也是一个不错的选择。

Homework

Open up this keyframes example and try changing the code. See if you can break it, and fix it. Even better, if you come up with something cool, let me know!

I love seeing how you’re getting on. You can email me or get in touch on Twitter.

Animation properties

在我们看更多的例子之前,先来了解下 animation 的各个属性。

transition 一样,animation 可以使用简写形式,也可以分开单独指定属性值。

animation-delay

transition-delay 类似,此属性表示在开始之前动画的等待时间。在定义多个动画的情况下特别有用。

如果定义的动画是不断循环的,在这种情况下,delay 属性并不会每次循环都有效,只有在给元素添加上动画效果的时候才有效。(只有第一次循环前会有等待时间,其余的就没有了)

实际上可以给这个属性一个负值,比如-1s。动画会直接从第1s开始执行,就好像这1s时间已经过去了。

animation-direction

动画通常从 0% 开始,到 100% 结束。animation-direction 使用 normalreversealternatealternate-reverse 来控制动画变化的方向。(从开始到结束我们可以看作是一个有向的变化)

“Reverse”是指从 100% 播放(或循环)到 0%,而 “alternate” 指动画轮流反复播放,即从 0% 播放到 100% 然后再播放到 0%。

animation-duration

动画完成一个周期所需要的时间。类似于 transition-duration,以秒或毫秒计,如1s200ms

animation-fill-mode

默认情况下,动画播放完成元素返回其正常状态。使用 animation-fill-mode,我们可以定义元素在动画结束或开始前的状态。

使用 forwards 表示当动画完成后,元素属性保持最后一个关键帧的值。使用 backwards 表示动画完成后,元素属性变成第一帧(这个第一帧不是关键帧的第一帧,CodePen Demo)的值。【Tips:animation-fill-mode 除了这里说的两个之外还有多个可选值。】

例子:bouncer animation on Hop.ie。 使用 forwards,动画播放一次并在最后一帧结束。【Tips:这个例子貌似没有啊,我翻遍了也没找到】

这里添个例子来说明下 forwards 和 backwards(原作者并没有写)。
在这个例子里使用了 animation-delay 和 animation-fill-mode。从效果上来看,设置 backwards,点击“开始动画”之后,backwards 会立刻变成动画真实过程(animation-duration)第一帧的样子,一直持续整个 animation-delay 时间,然后开始变化,最后动画结束后又变回了最一开始没有添加动画时的状态。

animation-iteration-count

这是动画播放的次数。默认情况下,它将播放一次。也可以指定一个数字,或指定 “infinite” 以使其永久循环。

animation-name

animation-name 指的是动画使用的 keyframes 的名字。例如,如果 animation-name 设置为 “foo”,它将使用一组下面这样的关键帧,如:

@keyframes foo {
  ...
}

animation-play-state

如果您需要暂停或恢复动画,则可以使用此属性执行操作。值为 runningpaused,默认为 running。可以使用 JavaScript 设置此值,控制动画播放状态。

animation-timing-function

此属性与 transitions 中定时函数属性的值相同,但略有不同。在 transition里时间函数(例如 ease-out)是作用于整个 transition,但 animation 里是作用于关键帧之间。

这意味着以下关键帧将看到动画快速启动并减速至50%,然后快速开始并在100%之前减速。

@keyframes foo {
  0%{
    / *动画开始时变化速度很快,然后按照ease-out的时间函数,到50%之前越来越慢* /
  }
  50%{
    / *然后又开始的时候很快,然后慢慢减速至100%的时候* /
  }
  100%{
    / * 结束 * /
  }
}

这看起来有些复杂。通常在创建关键帧动画时,我会选择 linear,用使用 keyframes 控制动画的节奏。

cubic-bezier 与动画一起使用可以产生一些很好的效果,大家可以尝试一下。

Using timing functions within keyframes

值得注意的是,当为动画指定时间函数时,这个函数会应用到动画的每个关键帧之间。

也就是说如果有四个关键帧,并且使用 ease-out,那么在上一帧与下一帧之间,变化速度会越来越慢。

所以我们通常会将动画的计时功能定义为 linear,然后在每个关键帧的上控制速度:

@keyframes my-animation {
  0%{
  ...
  animation-timing-function: linear;
  }
  50%{
  ...
 animation-timing-function: ease-out;
  }
}

在这种情况下,动画的前半部分将是线性的,而后半部分将使用 ease-out 计时功能。

Homework

这里有一个例子。尝试更改其中一些属性,看看会发生什么。

Keyframes in action

前面章节我们学习了 animation 属性,并且初步了解了 keyframes。这一节我们来深入学习下 keyframes

Things to look out for

下面是一个简写方式,只有两个状态,初始状态和终止状态,与 0% 和 100% 的写法是等价的。

    @keyframes name {
      from {
        ...
      }
      to {
        ...
      }
    }

有时候我们会像下面这样,在一行内写好几个百分比数值,这类似一个暂停的效果。下面的 0%, 20% 的意思是,在 0% 的时候,元素的 opacity 的值为0,然后保持这个“状态”直到 20%,然后 opacity 开始改变,并在 100% 的时候变为1。后面我们会用到这个知识点。

    @keyframes name {
      0%, 20% {
        opacity: 0;
      }
      100% {
        opacity: 1;
      }
    }

Example: Save button wiggle effect

还记得之前讲过的“Save”按钮吗?我们再重新回顾一下:

Source: http://codepen.io/donovanh/pen/KwEQdQ
Source: http://codepen.io/donovanh/pen/KwEQdQ

在开始添加 animation 之前,我先在页面上添加了一个按钮,然后设置了它的基本样式,让它看起来像 CodePen 的按钮。在这里我用了绝对定位让它显示在屏幕的中间。

然后我给按钮添加了 animation:将添加名为 “wiggle” 的 keyframes,持续2s时间,时间函数用 linear

    button {
      animation: wiggle 2s linear infinite;
    }

最后的 infinite 是新属性,它是 animation-iteration-count 的一个可选值。我们可以通过设置 animation-iteration-count 让动画效果重复我们想要的次数,默认是1次。这里设置为 infinite 表示动画将一直重复。

来看下 keyframes 的完整代码:

    @keyframes wiggle {
      0%, 7% {
        transform: rotateZ(0);
      }
      15% {
        transform: rotateZ(-15deg);
      }
      20% {
        transform: rotateZ(10deg);
      }
      25% {
        transform: rotateZ(-10deg);
      }
      30% {
        transform: rotateZ(6deg);
      }
      35% {
        transform: rotateZ(-4deg);
      }
      40%, 100% {
        transform: rotateZ(0);
      }
    }

在上面的代码里我们设置了一系列的关键点(waypoint),在每一个点都将按钮绕z轴(z-axis)旋转一定角度。

具体怎么旋转和变化的我们看下面的动图,我们发现浏览器自动完成了每个关键帧之间的插值。

Source: http://codepen.io/donovanh/pen/pvXJqp
Source: http://codepen.io/donovanh/pen/pvXJqp

CodePen链接

Homework

看下面的例子:a new CodePen with a single animated element。该例子综合使用了 animation 里的 “animation-timing-function” 和 “keyframes”。

尝试删掉几个 frame,或者修改下百分比的数值,看看会有什么效果。

Multiple animations

这一节我们看一下怎样同时使用多个 animation

Traffic lights

有这么种情况:一个页面上会有好几个 animation,每个 animation 都有自己的时间设置,我们希望这些 animation 保持同步,最好的例子就是交通灯了。【TIPS:同步的意思是说,希望这些 animation 之间保持一种确定的时间关系。】

Source: http://codepen.io/donovanh/pen/ogRRdR?editors=010
Source: http://codepen.io/donovanh/pen/ogRRdR?editors=010

这里有3盏灯,我们为每一盏灯写了一个 animation

    .red {
      animation: red 10s linear infinite;
    }
    .amber {
      animation: amber 10s linear infinite;
    }
    .green {
      animation: green 10s linear infinite;
    }

从上面样式里看出,每盏灯的 animation 持续时间都是10s,那动画不断循环播放的时候,它们之间就会一直保持同步的时间关系。

参照下面的图,从功能出发,很容易理解3盏灯的动画之间的逻辑关系(在这里逻辑关系就是指的它们之间的时间关系)

从图中看,一共分5个阶段或者说5个步骤,在每个阶段,不同的灯处于 on 或者 off 的状态。那么我们很明显就是将0% - 100%的时间跨度分成5份,每20%为一个状态,设置不同状态下的参数。

我们从红灯开始看。0%-20%20%-40%,这两个阶段红灯一直亮的,其余的时间都是黑的。那我们可以这么设置:

    @keyframes red {
      0% {
        background: black;
      }
      2%, 40% {
        background-color: red;
      }
      42%, 100% {
        background: black;
      }
    }

这里有2%的间隙,是为了让灯看起来有点渐变的效果。可以按照20%``40%去写

同理,黄灯是20%-40%80%-100%亮,其余时间不亮。这里也加了2%的间隙。

    @keyframes amber {
      0%, 20% {
        background: black;
      }
      22%, 40% {
        background: #FF7E00;
      }
      42%, 80% {
        background: black;
      }
      82%, 100% {
        background: #FF7E00;
      }
    }

绿灯也很简单,按照图上显示的,来设置它。

    @keyframes green {
      0%, 40% {
        background: black;
      }
      42%, 80% {
        background: green;
      }
      82%, 100% {
        background: black;
      }
    }

Further reading

想了解更多,欢迎阅读 CSS tricks article on the subject

Homework

例子中的交通灯是按照 UK 的规则来的,你可以尝试修改参数,将其改成其他规则的,看看效果怎么样。

Animation recap

目前为止,我们已经讨论了很多细节,我希望这对你们是有帮助的。

当我学习这个的时候,我必须承认我花了一些时间来深入了解动画和关键帧。如果到现在你还不是特别了解,不要灰心沮丧。坚持下去,你将会逐渐掌握使用动画的技巧。

在本章中,我们将花一点时间来回顾一下之前学习过的内容。首先,让我们来看看作业挑战!

Homework challenge: Traffic lights

如果你知道该怎么做的话,这个家庭作业挑战应该很简单。我已经写了一个英国交通灯的示例,请更改顺序,删除「红灯—黄灯」的阶段。

看这里,我已经使颜色组合符合美国交通灯的样子。

Recap: Animations

在这一章节,我们学习了 animation 属性,以及该如何使用它和 keyframes

Like a transition, only different

虽然 animation 属性的表现效果以及工作原理与 transition 类似,但是它还是有一些细微的差别。过渡仅在元素发生变化时才会发生,而动画可以立刻开始。

使用各种属性,动画可以循环一定次数(或者永远循环下去),甚至可以从一个负值开始延迟,这就会以已经进行的动画开始。

默认情况下,动画都会从头到尾播放,然后跳到它们的默认状态。我们可以使用 forwardanimation-direction 属性让动画在它结尾时定格。

动画用到了 timing-function,这一点很像过渡。然而,timing-function 是用在每一个的 keyframe并不是整个的 keyframes。相反地,你可以在 keyframe 中指定 animation-timing-function 进行更细粒度的控制。

最后,动画可以用简写方式来指定,就像过渡一样:

animation: keyframe-name 2s forwards linear;

Keyframes

每一个动画都需要引用一组的 keyframes。这些 keyframe 是一系列百分比,描述了动画的每个“阶段”。而浏览器会自动填充其间隙。

当您只想从一个状态转换到另一个状态时,keyframe 有它们自己的名称(to 和 from)。

在这段时间里,相互叠加的百分比可以让动画暂停。

最后,可以忽略0%关键帧,而浏览器可以使用元素默认的样式。例如,想让某样东西渐渐消失,我们不需要设置它的初始透明度为1(假设元素已经存在):

@keyframes name {
  100% {
    opacity: 0;
  }
}

Putting them together

如果想要使用动画,必须按照如下的格式:

.element {
  animation: keyframe-name ...
}
@keyframes keyframe-name {
  ...
}

Homework

目前为止,我们应该清楚了动画属性和过渡属性的区别了吧。

看看 Principles of Animation for the Web 上面的例子。每一个例子都包含了 HTML 和 CSS,以及关键帧动画。尝试着去修改一个吧。

Storytelling

现在我们已经介绍了 transitionanimation 属性,让我们将它们组合成一个具有悬停效果的动画。

Heroes

许多网站都喜欢在主页顶部使用一个引人注目的大图像。有时称为 “hero image”,通常是横向大图样式。

我最近发现的一个很好的例子是 Fabric 登陆页面。CSS animatiom 显示了 Fabric 如何为模块化框架工作。

Source: https://get.fabric.io/
Source: https://get.fabric.io/

另一个有趣的例子是 Mailchimp 主页。在这里,hero image 讲述了如何创建电子邮件的故事。

Source: http://mailchimp.com
Source: http://mailchimp.com

您可能还在 my CSS Animation 101 email course 登录页面上看到了它:

Source: https://cssanimation.rocks/courses/animation-101/
Source: https://cssanimation.rocks/courses/animation-101/

在以上示例中,他们都使用动画来设置页面的色调并说明网站的内容。

Example: Scrolling background

让我们创建一个例子。在这个例子中,我创建了一个在网页上下移动的 “web page” 样式图形。

Source: http://codepen.io/donovanh/pen/LEwedW?editors=110
Source: http://codepen.io/donovanh/pen/LEwedW?editors=110

对于一些交互、动画暂停、鼠标悬停在屏幕上时显示消息等都是利用 animations 和 transitions 来实现的。

See it in action here

Part 1: Background animation

要设置此示例,我们从 HTML 元素开始:

<div class="screen"></div>

我们可以使用某些样式使 “screen” 容器看起来像显示器或 iPad:

.screen {
  background: #e25865 url(//cssanimation.rocks/screen/images/screen_bg.png) no-repeat top center;
  background-size: 100% auto;
  border: 2em solid #fff;
  border-radius: 1em;
  width: 40em;
  height: 30em;
}

我们有一些定义大小和边框的样式,以及 setting a background image

我们创建的效果基于移动背景图像。背景图像比屏幕高,并且 background-size 设置为 100% auto。这意味着背景将自适应容器的宽度并能同比例调整高度。

增加背景图像的动画处理,我们现在可以编写 keyframes,使其看起来像某人正在滚动网页:

@keyframes scroll {
  0%, 10% {
    background-position: 0 0;
  }
  20%, 30% {
    background-position: 0 -22em;
  }
  50%, 60% {
    background-position: 0 -44em;
  }
  90%, 100% {
    background-position: 0 0;
  }
}

这里设置动画的属性是 background-position。有了这个属性,我们可以上下移动它。它从0 0开始,这意味着从左上角开始。

在接下来的帧中,我们将背景移动22 ems,然后是44 ems,然后返回到页面顶部。让我们创建一个动画属性,将其应用于“screen”元素。

.screen {
  animation: scroll 5s infinite cubic-bezier(.52,-0.39,.3,1.43);
}

这个CSS应用了一组名为 “scroll” 的关键帧,动画时长5秒,循环播放并使用 cubic-bezier 计时功能。在这种情况下,立方贝塞尔函数给动画增加了弹性效果,没有它,运动看起来就不那么逼真了。

我在 cubic-bezier.com 上创建了这个 bezier。如果您尚未为该网站添加书签,我强烈建议您加上!

Part 2: Adding the hover transition

在动画结束后或者希望人们专注于其他动画时最好暂停或停止动画。循环播放的动画可能会分散注意力,所以我们可以使用 animation-play-state 属性在悬停时暂停动画。

.screen:hover {
  animation-play-state: paused;
}

上述代码表示当光标悬停在动画上时,它将暂停。当光标再次移开时,它将恢复其默认的 playing 状态。

您也可以使用 JavaScript 实现此目的。一种可能性是当用户与页面的另一部分交互时,或者当它们滚动时,让一些 JavaScript 禁用动画。我们将看一下如何在以后滚动时启用动画。

Adding a message

当用户将鼠标悬停在元素上时,我们可以使用 transition 来显示消息。要做到这一点,我们需要更多的 HTML:

<div class="screen">
  <div class="message">Hover message!</div>
</div>

the CodePen CSS 中,我们将此消息放在 “screen” 的中并使其不可见。

.message {
  /*... positioning styles ...*/
  opacity: 0;
  transition: all 0.4s ease-out;
}

然后我们可以使用 transition 在悬停时显示它:

.screen:hover .message {
  opacity: 1;
}

由于我们在 “message” 样式上设置了 transition,因此当光标悬停在元素上和离开时,它都会创建动画。暂停的动画和过渡效果如下所示:

Source: http://codepen.io/donovanh/pen/LEwedW?editors=110
Source: http://codepen.io/donovanh/pen/LEwedW?editors=110

Summary

在本章中,我们将 animation 和 transition 组合在一起,创建了用于登录页面和产品导览的效果。我们利用 animation-play-state 来确保动画在我们想要时停止。

Homework

花一点时间思考我们到目前为止所涵盖的内容。

我们讲述了很多。结合 animation 和 transition 是将页面变为现实的有效方式。

在考虑如何将其应用于您的工作时,请考虑如何控制它。什么时候动画可以为您的用户带来好处,什么时候可以起作用呢?很高兴知道如何制作动画,但更好的是知道什么时候不使用动画。

Star Wars

可乐爆米花准备好了么!在这章中我们要做一个有意思的 SVG 动画。我们将在 “The Force Awakens”(《星球大战7:原力觉醒》)电影预告片中制作 “Star Wars” 的片名。。

Source: https://www.youtube.com/watch?v=ngElkyQ6Rhs
Source: https://www.youtube.com/watch?v=ngElkyQ6Rhs

这个例子是将 CSS 动画与其他一些 CSS 属性相结合后呈现的,特别是 transformsscaletranslaterotate

Transform: Not an animation property

虽然听起来它可能会创建动画,但 transform 属性实际上对元素进行旋转、缩放、移动或倾斜。我们可以使用它来创建出色的效果但是为了做到这一点,我们需要对每个关键帧或动画状态进行不同的变换。

Transform: scale(), translateZ() and rotateY()

我们可以使用 scale 来控制元素缩放。使用 translateZ,我们可以在 Z 轴上移动元素。Z 轴就是从你到屏幕画一条线来表示的轴。

在这种情况下,我们将使用 scale 和 translateZ 的组合使其看起来像一些单词在太空中飞行。

最后,我们将使用 rotateY 来旋转标语的字母。围绕 Y 轴旋转将需要在浏览器中进行一些 3D 工作。

SVG,HTML和CSS

为了准备这个例子,我为徽标 StarWars 制作了两个 SVG 文件。如果你想试试,可随意使用。

演示的 HTML 如下:

<div class="starwars-demo">
  <img src="//cssanimation.rocks/demo/starwars/images/star.svg" alt="Star" class="star">
  <img src="//cssanimation.rocks/demo/starwars/images/wars.svg" alt="Wars" class="wars">
  <h2 class="byline" id="byline">The Force Awakens</h2>
</div>

静态图像 of some stars 用于背景。副标题中的字体很难找到,所以我在本例中引用了 Web 字体 “Lato”。

通过一些绝对定位将内容定位在屏幕中间,我们从这开始:

Animating the Star and Wars

我们希望较大的文本淡入视野,同时随着时间推移开始变大后变小。这是 scale()变换的一个很好的例子。让我们在 “Star” 这个词上使用以下关键帧:

@keyframes star {
  0% {
    opacity: 0;
    transform: scale(1.5) translateY(-0.75em);
  }
  20% {
    opacity: 1;
  }
  89% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: translateZ(-1000em);
  }
}

在此动画过程中有两个属性会发生变化。opacitytransform。opacity 属性使其开始透明,并在最后逐渐消失,以便我们可以循环动画。

通过将 scale 设置为1.5倍大小。这意味着文本的初始大小比正常大150%。在89%时,我们将 transform 的 scale 属性设置为1。这意味着在0%和89%之间,比例从150%到100%。

最后的 transformZ 使单词快速缩小。

我们可以将这些关键帧应用于单词 “Star”,如下所示:

.star {
  animation: star 10s ease-out infinite;
}

同样,“Wars” 一词也是这样处理。

Making it 3D

在 CSS 中使用 3D 变换,无论是沿 Z 轴平移,还是围绕 Y 轴和 Z 轴旋转,都需要为 3D 设置一个平台。在 HTML 术语中,这意味着我们创建一个容器,并告诉浏览器将发生一些 3D 效果。

我们通过在 .starwars-demo 容器中添加以下内容来实现:

.starwars-demo {
  perspective: 800px;
  transform-style: preserve3d;
}

这两个属性告诉浏览器指定子元素定位在三维空间内,而不是平面。CSS Tricks 详细介绍了该属性。

其次,persective 属性告诉浏览器场景需要 “deep”(深度)。以防万一我们将深度定为800px。由于场景较短,较小的值会产生更多 “extreme”(极端)的透视效果。

有了这个,我们开始介绍标语。

The Force Awakens

标语 “The Force Awakens” 出现在预告片中,每个字母都旋转到位。我们可以使用 rotateY 变换创建这个效果。在这种情况下,我们将每个字母包裹在 span 元素中,以便我们可以将动画应用于每个字母。

我很快发现的一个问题是,没有一种简单的方法来为副标题中的每个字母设置动画。我的第一种方法是手动将每个字母包装在 span 标签中。这有效,但使 HTML 有点混乱。当前的演示包括一些 JavaScript(感谢Tady的帮助),它将每个字母自动包装在 span 中。

我们将为每个字母应用动画。

首先,关键帧:

@keyframes spin-letters {
  0%, 10% {
    opacity: 0;
    transform: rotateY(90deg);
  }
  30% {
    opacity: 1;
  }
  70%, 86% {
    transform: rotateY(0);
    opacity: 1;
  }
  95%, 100% {
    opacity: 0;
  }
}

首先,字母旋转90度,然后动画旋转70%转为0度,即字母转为面向观众。

我们可以将这组关键帧应用于每个span,如下所示:

.byline span {
  animation: spin-letters 10s linear infinite;
}

结果是,每个字母的每个 “span” 容器都会逐渐淡入并慢慢旋转到位,然后在动画结束时逐渐消失。

把它放在一起就是 finished demo

Source: http://codepen.io/donovanh/pen/pJzwEw?editors=110
Source: http://codepen.io/donovanh/pen/pJzwEw?editors=110

Homework

如果你有时间我会鼓励你看一下 CodePen version

你可能会注意到 CSS 中的一些 “media” 查询。我们使用 “media” 来调整适应较小的设备。尝试更改一些动画关键帧,或 transform 值来查看会发生什么。

Revealing content on scroll

Web动画的一种常见用途是在浏览器滚动时向元素添加动作。在本章中,我们将了解如何执行此操作。

这是 today’s demo on CodePen。尝试向下滚动页面,看看引用文本和猫是如何淡入的。

Wow.js

当您的鼠标滚动到某个点时,许多站点会触发自定义动画。他们或者开始播放视频、触发复杂的关键帧动画,或只是将项目淡入到某位置来吸引访问者的注意力。

每一种情况通常是,当元素在屏幕上可见时 JavaScript 为其添加一个 class 类来控制其动作。然后我们可以将动画附加到 class 中,当浏览器滚动时动画从正确的时间开始。

有许多 JavaScript 选项可以添加类,我发现了一个好用的是 Wow.js。让我们用 Wow.js 来创建一个简单的例子,当我们滚动鼠标时,内容会淡入视图。

Source: http://codepen.io/donovanh/pen/gbVMjm">

Using Wow.js

使用 Wow.js 涉及两个步骤。第一个是 download the JavaScript。将 wow.min.js 文件放在项目的 JavaScript 文件夹中。下一步是从 HTML 中引用此文件:

<script src="javascripts/wow.min.js"></script>

(假设您的文件夹名为 javascripts - 根据需要更改)

然后,我们使用以下命令调用 JavaScript(将其粘贴到上一个代码之后):

<script>
 new WOW().init();
</script>

我们现在可以为我们的内容添加 “wow” 类,Wow.js 将负责确定我们的内容是否显示。

Adding “wow” classes

如果我们有一个想要在元素上添加滚动动画,首先要确保它具有 “wow” 类:

<p class="wow">...</p>

这意味着当浏览器将此内容滚动到屏幕上时,Wow.js 会向该 class 添加 “animated”,如下所示:

<p class="wow animated">...</p>

如果我们的 p.animated 元素上有动画,动画只会在添加这个 class 时发生。

Hiding and showing

对于我们的示例,我们将使用 wow 样式隐藏所有元素,并在 animated 时显示它们。首先,我们隐藏它们:

.wow {
  opacity: 0;
  transition: all 0.5s 0.5s ease-out;
}

我们在这里也应用了一个 transition,这样元素就会淡入。请注意第二个0.5s。在这种情况下,我们还增加了半秒的“延迟”。这样元素在淡入之前能正确滚动到视图中。

下一段代码定义了添加 Wow.js 的 animated 时元素的外观:

.animated {
  opacity: 1;
}

现在我们应该会遇到这样的情况,当用户滚动时,项目会淡入 Animate.css

Using Animate.css

Wow.js 与 CSS 框架 Animate.css 配合使用效果更好。我还没有在这个例子中使用过,因为理解如何创建我们自己的 transitions 是有好处的,但是值得看一下 Animate.css 提供的开源的 transitions。

this example 我使用了 Animate.css。请注意 CSS 中没有 animations 或 transitions。相反,我在HTML中添加了一个 class 告诉 Animate.css 要应用哪个动画:

<section class="image wow bounceInUp">

bounceInUp 是对 Animate.css 的许多内置动画之一的引用。如果在示例中的 CSS 部分选择 “cog”,您将看到我在 “External CSS file” 下引用了 Animate.css 框架。

Using Modernizr

通常情况下一般先隐藏内容再使用 JavaScript 显示内容。人们可能因为某种工作原因对 JavaScript 并不熟悉。诸如 Modernizr 之类的脚本可用于处理此问题。它会在文档正文中添加一个 js 类,然后我们可以将它们添加到我们的样式中。

这个 demo 中包含了 Modernizr。

Homework

让内容逐渐淡出是一个很好的开始,但是您是否可以想象用这种方式来为您的设计和网站增加价值?当用户浏览时,请注意滚动出内容时开始动画的时间。

它何时起作用,什么时候又不那么好用?

Accessibility

目前为止,我们已经学习了网页动画,以及如何创建它。在结束这门课程之前,我们来花点时间思考一下我们可以做点什么来确保读者正确使用动画。

动画可以丰富我们的内容,也可能适得其反。

Make sure content is accessible

之前章节用过的例子,使用动画显示内容。假如该内容区域的初始状态是不可见的,这时候就需要注意它是否会正确显示。因为老版本的浏览器对 CSS 动画的兼容性不是很好,同样地,JavaScript 在老版本的浏览器上的运行效果也不是一直都不会出错的。我们可以使用像 Modernizr 这样的工具来规避潜在的问题。

在设计中,我们使用动画来传达我们想要表达的意义和意图。当你在设计动画时,一定要把浏览器的兼容性考虑进去。因为有的人可能正在使用屏幕阅读器或者浏览器有不同的设置,这些都有可能导致你的动画无法正常工作。但是无论动画是否正常工作,都要确保重要信息不会丢失。

好比自动播放的视频带给用户极差的体验,自动播放的动画可能会分散用户的注意,带来不好的用户体验。当你想用动画去吸引用户的注意时,试着限制一下动画发生的位置和时机。这意味着可能需要限制动画播放的时间,或确保用户在关注其他内容之前已经停止动画。

Give control

W3C 建议,任何闪烁、滚动或自动更新时间超过5秒的内容都应该有暂停或删除动画的方法。使用 animation-play-state 是一种暂停动画的方法,具体例子看这里

Allow for alternate inputs

越来越多的用户使用手机来访问网页。在手机上,即没有光标,也没有悬停状态。所以我们需要围绕这个来设计动画。我经常用到的解决方案是:检测 tap 并向目标添加一个 ‘class’,然后,将 transitionanimation 添加到 :hover.active 状态。

Confusion

有时候网站背离了设计的初衷,它试图让所有的东西都动起来。这样不仅会混淆网站的信息,还会让人感到困惑。特别是 UI,当向页面元素添加动画时,请确保动画被触发的方式是显而易见的。因为用户没有时间去解读复杂的设计以及移动方式,所以请尽可能的清晰。

Don’t make me sick

太多的动画,或是错误的动画,都会降低用户体验。

当苹果公司推出新的操作系统 iOS7 时,它支持更多的动作和动画。其中一些的用户体验并不好,有些人喜欢在车上用手机阅读,如果有过多的动画会让人觉得更容易晕车。

这就会牵扯到我们的前庭神经系统是如何工作的。我们的耳朵里有三对半规管帮助我们确定头部在三维空间中的位置。简单解释为什么会晕车,当人坐在移动的车或船里面,内耳的前庭已经感知到身体在运动,但眼睛却以为身体是静止不动的。前庭已经向各部门发送信号了,但身体却没有做出反应,于是平衡调节就出错了!这种刺激一旦超过了个体承受的极限,就会导致晕车。这种症状在你望向左右的窗外、刷手机、看书的时候更强烈,因为这些行为让身体更加肯定自己是静止的,跟前庭传递的信号起了更大的冲突。

我们会生病是进化产生的副作用。为什么一晕车就会呕吐呢?当身体产生不良反应时,交感神经就会兴奋,想通过调节其他器官反应来应付环境变化、维持内环境的相对稳定。于是,肠胃就受到刺激,引发呕吐。

随着可穿戴技术的发展和开发,这可能会成为一个更大的问题。在设计浮动大的动画时,一定要考虑人们是否适应各种形态的运动类型。

Vestibular.org 是了解这方面内容的一个很好网站。

Accessibility is for everyone’s benefit

可访问性不只是为使用屏幕阅读器或浏览我们内容的用户准备的。我们难免会有分心的时候。我们应该知道人们如何使用我们的产品来确保我们的动画不会适得其反。

Homework

如果你的工作涉及到设计或构建界面,那么一定要花时间阅读这篇文章 NNGroup’s Animation for Attention and Comprehension。想想人们可能会如何使用你的作品,如果他们看不到动画,这可能意味着什么。

Now you know CSS animation!

你已经完成了 CSS Animation 101!希望这本书对你有帮助。

在我们结束之前,让我们来看看一些你可能想要收藏的资源,并进一步地学习 CSS 动画。

CSS Animation cheatsheet

我准备了一个备忘录清单,总结了过渡和动画的不同属性。它正好有一张 A4 纸的大小,尽情享受它吧。

Resources to bookmark

知道如何创建 CSS 动画和过渡是件好事,但有时在现有平台上构建是很方便的。这里有一些很棒的工具,我们可以用它们来节省开发时间,提升开发效率。

Animate.css

Animate.css 给自己的定位是—just add water.你可以引用 CSS 文件并添加任何动画类来查看它们的运行情况。这里有一些例子.

Hover.css

是一个不错的替代品,Hover.css 是另一种可用于链接、按钮、徽标或任何其他 HTML 元素的动画。

Other tools

CSS 动画很强大,而且不需要借助 JavaScript 等其他技术就可以实现很多功能。然而,它并不是适合所有的情况。有时候需要更复杂的动画,JavaScript 能够帮助我们提高效率。最好的包都是构建在 CSS 之上,可以利用它的速度以及浏览器兼容性,但这会让你做更多的工作。

GSAP

Greensock Animation Platform 能够提供基于 JavaScript 的方法,以便创建出更高级的动画。它能够提供友好的操作接口以及稳定的性能。虽然它的学习曲线比较陡峭,但是它是一个很强大的工具。

Snabbt.js

Snabbt 能够以强大、优雅的方式、用自定义的定时函数去创建更复杂的动画。它能为浏览器生成动画转换矩阵,从而获得非常好的性能。

CSS Animate

CSS Animate 是一个生成关键帧动画的工具。它可以通过拖拽一个对象并使用时间轴来设计动画。

Cubic-bezier.com

如果你想创造出一种生活的感觉时,我推荐的工具是:Cubic-bezier.com.这个简单的工具可以帮助你优化时间函数,另外,Chrome浏览器的检查器中也内置了类似的工具。

Next steps

一些人提出的一个问题是:“我们如何才能越过101个阶段?”

我的建议是「挑战自己」。去这些网站上找寻灵感—Dribbble.comCodePen.io。从一些流行产品、电影或电视节目中寻找创意。我会思考,我该如何在 Web 上实现这种效果?CSS 会是一种好的方法么?

你还可以去阅读这些网站上的博客—CSS TricksSaraSoueidan.comCSSAnimation.rocks

所以,如果你不想遗忘这些知识,那就开始练习把。找到你感兴趣的东西,试着去做一些改变,那么你会发现这些知识对于你来说是非常简单的。

Don’t be a stranger, now

你是否受到了启发,想去尝试一下 CSS 动画?如果你有一些很炫酷的动画或者任何疑问,请让我知道。我很期待你的来信。

你也可以在 twitter 上与我交流(@donovanh)。

最后,感谢你阅读本书。

Level up your CSS animation skills!

恭喜你完成了本书的所有教程,希望你能有所收获。你还可以观看视频:Level Up Your CSS Animation Skills

你将会学到以下内容:

学习完本课程之后,希望你能够创造出一个令人印象深刻的登录页面。