百度前端技术学院是一个为大学生创办的免费的前端技术实践、分享、交流平台。由百度校园招聘组、百度校园品牌部、百度前端技术部以及多个百度的前端团队联合创办。学院组织了一批百度在职工程师,精心编写了数十个实践编码任务,将技术知识点系统有机地串联在各个充满趣味与挑战的任务中,同学们通过实际地编码练习来掌握知识,再辅以互相评价、学习笔记等方式,加深对于学习内容的理解。在过去的三年中,百度前端技术学院累积吸引了上万名同学参加,并且有数十名同学在学习后,顺利加入了百度,成为了百度的前端工程师。

CSS动画学习笔记

作者王旻晨课程有趣的鼠标悬浮模糊效果2360次浏览62017-02-24 18:07

看到贴吧里面有同学觉得课程对初学者不是很友好,我就把自己以前学 CSS 动画时候的一篇笔记贴出来吧。。可能对于本题不一定能直接解决问题,但是应该会比较有启发性。由于这个 markdown 不能直接贴 jsfiddle,就劳烦大家一一点开吧。。

原文地址:CSS 动画学习笔记

一直以来,我对于 CSS 的好感度是要略小于 Javascript 的,它给我的感觉是对网页的作用只有布局上,似乎用途只有老生常谈的 N 栏布局之类,不像 Javascript 负责交互、后端开发负责逻辑。我之前阅读的一本书《精通 CSS》,书虽然是好书,但解决问题的思路停留在 CSS2 时代,涉及的多是网页布局方面,几乎没有对CSS3中动画的介绍。这些看法在我接触过 CSS 动画之后有所改变,甚至开始爱上 CSS 动画了❤。

通过CSS动画,我们可以做出一些有趣的特效。至少有以下几点让我们可以优先考虑使用CSS动画:

  • CSS动画的语法相比与 Javascript 动画、JQuery 动画的语法要容易的多;

  • CSS动画表现效果较 Javascript 更好。CSS 动画甚至可以在低性能的设备上流畅运行,渲染引擎会使用一些技术使动画尽可能流畅运行,而 Javascript 动画表现通常不佳;

  • 由浏览器控制动画序列,浏览器可以优化性能;

  • 在一些情况下,我们甚至可以用 CSS 动画来代替图片和 Flash,大大减少了文件大小,减少了服务器压力;

  • 支持 Chrome、IE 10、Firefox、Opera 等现代浏览器,随着 Windows XP 份额的减少,我们已经几乎不用考虑兼容性问题;即便是不支持该属性,动画也只是突变发生,不会对显示结果带来影响(特别为了动画效果而使用 CSS 动画的除外)。

Transition

简介

一般来说,当 CSS 有元素的属性发生变化时,这个变化会立刻体现在元素上,也就是“突变”。transition 可以控制属性变化的动画的速率,让变化过程从“突变”改变为持续一段时间的过程。

例如,在不加 transition 时,我们把鼠标移动到 wrapper上时是“突变”的:

https://jsfiddle.net/wmc54321/qfyf2ghs/embedded/result,css,html/

当我们添加了 transition 属性,为动画添加一个时间,变化就圆润多了:

https://jsfiddle.net/wmc54321/a8k4no9p/embedded/result,css,html/

我们甚至可以为wrapper的边框和阴影添加动画:

https://jsfiddle.net/wmc54321/r49pn31f/embedded/result,css,html/

指定属性

当然,仅仅这样是不够用的。我们还可以指定动画只在指定的属性上发生。例如,我们给时间加上属性width、height,那么动画就只在width和height上发生,其他的属性仍然是“突变”:

https://jsfiddle.net/wmc54321/m2L6ky0u/embedded/result,css,html/

时间

我们还可以给动画加上延时。我们在原有的时间后面加上我们希望它们在被触发后开始运行的时间,就可以看到动画依次发生在height、width、border、border-radius、box-shadow上:

https://jsfiddle.net/wmc54321/rbvk5avs/embedded/result,css,html/

我们发现,当我们把鼠标移走的时候,动画仍然会按照我们所设定顺序的发生,这样看起来似乎比较奇怪。我们可以把鼠标移入的动画写在 .wrapper:hover 里面,由于其在文档中位置靠后,因此当 :hover 发生时该属性发生作用;我们把鼠标移出的动画写在 .wrapper 里面,这样当鼠标移出时 :hover 中的属性不起作用,该属性起作用。

https://jsfiddle.net/wmc54321/buch8a1z/embedded/result,css,html/

调速函数

我们可以为transition设定速度变化函数。默认的情况是ease,是逐渐放慢。除此之外,还有linear(线性)、ease-in(加速)、ease-out(减速)等。例如:

https://jsfiddle.net/wmc54321/h3muzmhy/embedded/result,css,html/

我们发现 wrapper 的宽度变化变为了匀速改变。

特殊情况

transition 能够应用在我们所能见到的大多数属性上,具体可以查看CSS动画属性表。不过,在实际应用中,我们常常会发现有一种情况下transition失灵了:

https://jsfiddle.net/wmc54321/bthg9rb8/embedded/result,css,html/

我们明明给 wrapper 加了 transition,元素却没有像想象中那样“渐变”,而是“突变”,transition 失灵了!

查阅资料,我们发现,当我们为 width、height 属性设置 transition 时,如果起始状态(或结束状态)是 auto,那么 transition 是无效的。解决方法是,为元素设置一个合适的 max-height:

https://jsfiddle.net/wmc54321/t2e6bbux/embedded/result,css,html/

Transition的各个子属性

最后,我们再来仔细学习一下各个属性的用法。

  • transition-property – 触发动画的属性。

    允许值:none | all | <属性名>

    初始值:all

    none表示无属性。all表示所有可以触发动画的属性。或者,可以指定属性触发动画效果。

  • transition-duration – 动画的持续时间。

    允许值:<时间>

    初始值:0

  • transition-timing-function – 转变时使用的调速函数(比如, linear、ease-in 或自定义的 cubic bezier 函数)。

    允许值: ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier(x1, y1, x2, y2)

    初始值: ease

    linear – 线性函数,返回值一个输入值一样的结果(匀速)。

    ease – 减缓函数, 是缺省值, 等同于 cubic-bezier(0.25, 0.1, 0.25, 1.0)(逐渐放慢)。

    ease-in – 等同于 cubic-bezier(0.42, 0, 1.0, 1.0)(加速)。

    ease-out – 等同于 cubic-bezier(0, 0, 0.58, 1.0)(减速)。

    ease-in-out – 等同于 cubic-bezier(0.42, 0, 0.58, 1.0)

    cubic-bezier - 自定义贝塞尔曲线

  • transition – 三种属性的合体简写。

局限

transition 的动画效果已经让我们感到惊叹。但是,transition 仍然有相当的局限性。

  • transition 是有触发条件的(有属性发生改变);

  • transition 只和开始时属性状态和结束时属性状态有关,不能定义中间状态;

  • 动作是一次性的,动画执行一次就没有了。

有没有更灵活的动画呢?

Animation

简介

使用 animation,需要用到 @keyframes 规则。使用 @keyframes 规则时,需要把它绑定到选择器上。绑定的方式是,至少要定义动画的持续时间和动画的名称。

例如,如下面的例子,我们定义一个动画时间2s,定义了一个动画jumping,并让该动画在 :hover 时发生。我们用 @keyframes 定义动画在各个时间节点的属性(关键帧)。

https://jsfiddle.net/wmc54321/5mg0zgc2/embedded/result,css,html/

加上 infinite 关键字可以让动画无限循环(或者是动画播放次数):

https://jsfiddle.net/wmc54321/5o3xtyo5/embedded/result,css,html/

Animation的各个子属性

我们再来介绍一下Animation的各个属性,下文中我们就不详细介绍了。

  • animation-delay - 设置延时,也即从元素加载完成之后到动画序列开始执行的时间。

  • animation-direction - 设置动画在每次运行完后是反向运行还是重新回到开始位置重复运行。

    允许值:normal, alternate, reverse, alternate-reverse

    默认值:normal

    normal:动画循环播放时,从结束状态回到起始状态

    浏览器对其他值的支持情况不佳,应该慎用。

  • animation-duration - 设置动画一个周期的时长。

  • animation-iteration-count - 设置动画重复次数(可以指定infinite无限次重复动画),默认为一次

  • animation-name 指定动画名称,即由 @keyframes 描述的关键帧名称。

  • animation-play-state - 允许暂停和恢复动画。

    允许值:paused, running

    running:动画停止后停止动画,动画开始时重新开始

    paused:当动画突然停止时,保持暂停状态,当动画开始时继续播放动画

  • animation-timing-function - 设置动画速度, 即通过建立加速度曲线,设置动画在关键帧之间是如何变化。

    允许值:ease, ease-out, ease-in, ease-in-out, linear, cubic-bezier(x1, y1, x2, y2)

  • animation-fill-mode - 指定动画执行前后如何为目标元素应用样式。

    允许值:forwards, backwards, both, none

    默认值:none

    none:回到动画还未开始前的状态

    backwards:动画回到第一帧的状态

    forwards:动画停留在结束时的状态

    both: 根据 animation-direction 轮流应用 forwards 和 backwards 规则。

分层动画——曲线运动

我们使用 transition 和 animation 可以非常容易地做出元素从 A 到 B 的直线运动,当然运动轨迹也是直线。如果我们想要做出曲线运动的效果,似乎就无从下手了。即便是上文中提到的贝塞尔曲线也只是负责时间曲线,而不是空间曲线。

我们回忆一下高中物理中的抛物线:

  • x = v t

  • y = ( g t ^ 2 ) / 2

将单维度的运动转化为两个维度的运动,问题就迎刃而解了。

我们可以使用 CSS 中的一个有趣的存在——伪元素。我们在选择器中,加上 :before、:after,二者就会分别在元素内部的最前面和最后面出现。例如:

https://jsfiddle.net/wmc54321/p5s5zk8g/embedded/result,css,html/

因此,我们可以以元素容器作为 X 轴,容器中的 :after 伪元素作为 Y 轴,实现曲线动画。

如下面的例子,我们让左上角的白色球向右下方运动时,在 X 方向加速、Y 方向减速,就会创造出一个加速度方向斜向右上的曲线;向左上方运动时,在 X 负方向加速、Y 负方向减速,就创造出了加速度方向斜向左下的曲线。

https://jsfiddle.net/wmc54321/ew7e6t48/embedded/result,css,html/

Animation实战

animation 显然要比transition要灵活得多。我们就来着手写一个加载动画吧。下面的例子展示了我写的一个加载动画,目前已经用在了我的相册展示页面上。

https://jsfiddle.net/wmc54321/907rxt4v/embedded/result,css,html/

思路非常简单。我们为四个颜色的球分别做一个包含 [向外发射, 向内恢复位置, 在原位置暂停一段时间] 的动画,再对四个球的父元素做一个旋转的动画 [加速转动120°, 加速转动120°, 加速转动120°]。

我们再来看一个 CSS 动画播放按钮。这个按钮已经应用到了我做的 HTML5 播放器 NyaPlayer 中。

https://jsfiddle.net/wmc54321/o41um2r2/embedded/result,css,html/

这个按钮实现的原理要点如下:用 CSS 的 border 绘制伪元素 :before、:after。当显示为播放时,前者绘制为三角形,后者为宽度为0的长方形;当显示为暂停时,前者绘制为正方形,后者绘制为某宽度的白色长方形遮挡住正方形的一部分,这样看起来就像是暂停键了。

看了这么多,你是不是也想亲手试一下了呢?

参考文献

阮一峰 - CSS动画简介

Alon's Blog - CSS分层动画可以让元素沿弧形路径运动

MDN - 使用 CSS transitions

MDN - 使用 CSS 动画

0条评论