7 CSS3过渡、变形和动画

    在前面两章中,我们学习了一些CSS3的新特性和新功能。不过到目前为止,我们看到的所有效果都是静态的。其实CSS3能做的远不止于此。

    目前的情况是,如果页面上需要一些动画效果,要么你自己编写JavaScript,要么使用JavaScript框架(如jQuery)来提高效率。但是,一些熟悉CSS3的同志早就看不惯动不动就用JavaScript的做法了,他们正想方设法收复失地。虽然CSS3不可能在短期内取代jQuery或类似的框架,但它完全有能力做一些如平滑过渡(比如在鼠标悬停时)和在屏幕上移动元素之类的事情。这对我们来说是个好消息,它意味着在越来越多支持现代浏览器的设备中,我们可以使用CSS替代JavaScript实现动画效果。好吧,我的意思是:你完全可以从“待办事项”中将“学习如何使用jQuery制作动画效果”这项划掉,因为用纯CSS能完成同样有趣的效果。和之前一样,不支持这些特性的浏览器不会受到任何影响,它们会自动跳过无法识别的规则,就好像这些代码根本不存在一样。

    本章内容

    img436 什么是CSS3过渡以及如何使用它

    img437 如何编写CSS3过渡以及它的缩写语法

    img438 CSS3过渡时间函数(ease、cubic-bezier等)

    img439 响应式网站中有趣的过滤效果

    img440 什么是CSS3变换以及如何使用它

    img441 理解不同的2D变换(scale、rotate、skew,、translate等)

    img442 尝试3D变换

    img443 CSS3动画效果(使用关键帧) 7.1 什么是CSS3过渡以及如何使用它 我们在给超链接设置样式时,一般都会设置一个悬停状态(hover)的效果,这种方法能明显地提醒用户他的鼠标指向的是一个超链接。虽然对越来越多的触摸屏设备没太大用处,但不管怎么说,这种方法对网站和用户之间的交互是非常简单实用的。

    通常,使用CSS时悬停状态就是一个开关。它默认有一个状态,然后在鼠标悬停时马上切换到另一种状态。但是使用CSS3过渡,正如其名字所暗示的,可以让元素从一种状态慢慢转换到另一种状态。这种转换并不局限于悬停状态,但可以从悬停讲起。

    在上一章中,我们使用CSS3制作了一个有红色渐变背景的按钮。所使用的CSS3代码如下(为简洁起见省略了浏览器私有前缀):

    img444

    我们来给按钮增加一个悬停效果:

    img445

    两种状态下的效果如下,先看默认状态:

    img446

    再看悬停状态:

    img447

    这里只是在鼠标悬停时简单地修改了一下文字、文字阴影以及边框的颜色。所以,你可能想象出来,使用这段CSS代码,当鼠标悬停在按钮上面时,按钮会直接从第一种状态(白色文字)突变到第二种状态(黑色文字)——就是一个开关效果。我们来给第一段CSS规则添加一点CSS3魔法:

    img448

    现在再把鼠标悬停在按钮上,文字、文字阴影和边框阴影的颜色都会从第一种状态平滑过渡到第二种状态。注意,这里把过渡应用到了元素而不是悬停状态上。这样做是为了让元素的其他状态(如:active)也能设置不同的样式并拥有类似的效果。所以请记住,过渡声明要放在过渡效果开始的元素上。那过渡是怎么发生的呢? 7.1.1 过渡相关的属性 CSS3过渡效果涉及四个属性,也可以使用包含这四个属性的缩写。

    img449 transition-property:要过渡的CSS属性名称(比如background-color、text-shadow或者all,使用all则过渡会被应用到每一个可能的CSS属性上);

    img450 transition-duration:定义过渡效果持续的时间(时间单位为秒,比如.3s、2s或1.5s);

    img451 transition-timing-function:定义过渡期间速度如何变化(比如ease、linear、ease-in、ease-out、ease-in-out或cubic-bezier);

    img452 transition-delay:可选,用于定义过渡开始前的延迟时间。相反,将该值设置为一个负数,可以让过渡效果立即开始,但过渡旅程则会从半路开始。

    单独使用各种过渡属性创建转换效果的语法如下:

    img453

    1. 过渡的简写语法

    正如我们之前所见过的那样,我们可以将单个的声明组合成一个简写版:

    img454

    使用简写语法时要注意,声明中的第一个时间值总被应用给transition-duration,第二个时间值总被应用给transition-delay。

    和以前一样,别忘了浏览器私有前缀。例如,上面那句简写声明添加了浏览器私有前缀之后,代码如下:

    img455

    我们将没有前缀的标准版本放在了最后面,这样当浏览器完全实现了标准之后,这句代码就会覆盖之前带前缀的版本。

    过渡的局限性

    使用过渡时有一点需要说明,即有些属性无法实现过渡,尽管规范上说它应该可以(即使在最新的工作草案http://dev.w3.org/csswg/css3-transitions/中也这么说)。例如,background-gradient属性就无法过渡。但理论上所有CSS属性都是可以过渡的(http://www.w3.org/TR/css3-transitions/#properties-from-css-)。

    1. 在不同时间段内过渡不同属性

    当一条规则要实现多个属性过渡时,这些属性不必步调一致。看看下面这段代码:

    img456

    此处我们通过transition-property来指定只过渡border、color和text-shadow,然后在transition-duration声明中我们设定边框过渡效果应该2秒内完成,文字颜色3秒,文字阴影8秒。由逗号分隔的过渡持续时间按顺序对应上面的CSS属性。

    1. 理解过渡调速函数

    大多数过渡属性都能一看就知道是什么意思。前面其实已经介绍了过渡相关的几个CSS属性。其中,过渡持续时间和延迟时间都是以秒为单位的时间值(如2s),所以也很好理解。但过渡调速函数又有点让人摸不着头脑了。ease、linear、ease-in、ease-out、ease-in-out以及 cubic-bezier这些东西都是做什么用的?它们其实都是某种贝塞尔曲线,本质上就是缓动函数。我估计这样讲你还是不太明白。这样说吧……嗯,这其实就是那种用文字很难表达的概念(当然本人有很好的文字驾驭能力),就像你不得不给你的另一半解释清楚为什么你忘记了她的生日一样!所以我就不白费口舌了,还是请读者直接看这里吧http://cubic-bezier.com/。

    img457

    这个网站能让你对比查看各种调速函数,看到它们的区别。不过,即使你闭着眼睛都能写出贝塞尔曲线(而且作为老外还能用中国话从1000倒数到1),在实际使用中,它们的效果也确确实实没有太大区别。为什么呢?

    和任何增强效果一样,使用过渡效果也必须长个心眼儿。在现实当中,如果过渡效果持续的时间过长,会让网站感觉很慢。导航链接用整整5秒时间完成过渡,只会让你的用户骂娘而不是赞叹。因此,除非有什么特殊的理由,否则使用快速(以我的经验最多1s)的默认过渡(ease)效果往往最好。 7.1.2 响应式网站中的有趣过渡 一旦变成响应式设计的发烧友,你就会发现自己在浏览网页时总要调整一下浏览器窗口大小,以此确认该网站是不是响应式的。但这种习惯可能会激怒“普通”人,所以最好私下里做这件事。

    我经常访问的一个讨论CSS技术的好网站是Chris Coyier的http://css-tricks.com。在它重新设计之后,我浏览时碰巧调整了浏览器窗口,在看到众多元素在屏幕上飞舞时,我露出了会心的微笑。Chri给网页施了什么魔法使其具有了这种效果?其实代码如下(1)

    img458

    此处,我们使用CSS通配选择器*来选择页面所有元素,然后为所有元素都设置一个耗时1秒的过渡效果。声明中省略了过渡调速函数,浏览器默认会使用ease;声明中同样省略了延迟时间,浏览器默认使用none,所以过渡效果不会有延迟。最终效果是什么样?大多数效果(超链接、悬停状态,等等)和你所期望的一样。不过,因为所有元素都被应用了过渡,自然也就包括媒体查询中的规则,所以当浏览器窗口大小发生变化时,页面元素将从一种排列方式过渡为另外一种排列方式。必须这么做吗?当然不是!但这种效果是不是既好看又好玩?没错! 7.2 CSS3的2D变形 虽然两个英文单词发音相似,但CSS变形(transformation,包括2D变形和3D变形)和CSS过渡(transitions)完全不同。可以这样理解:过渡元素从一种状态平滑转换到另一种状态,而变形则定义了元素将会变成什么样子。我自己(极其幼稚)的理解是这样的:

    想象一下《变形金刚》里的擎天柱,他先变形(transform)为别的东西,经过一段时间的过渡(transition)又变成了卡车。

    可能刚才的这个比喻把你搞得更晕了(或者你根本不知道擎天柱是谁),还是直接说正题吧。我们来给AND THE WINNER ISN'T网站的导航链接在悬停时添加一个2D变形:

    img459

    在现代浏览器中,在导航链接上悬停鼠标就会看到如下效果:

    img460

    我们告知浏览器当鼠标悬停在链接上时,将其放大到原始大小的1.7倍。

    现在如果你尝试在Safari浏览器中添加这种规则,须注意它需要应用该规则的原始元素必须以块状显示。示例如下:

    img461

    不这样做的话,什么效果都没有,你懂的,垃圾得很。

    我们能做哪些变形

    有两种可用的CSS3变形:2D变形和3D变形。2D变形的实现更广泛,浏览器支持更好,写起来也更简单些,所以我们先来看看2D变形。CSS3的2D变形模块允许我们使用下列变形。

    img462 scale:用来缩放元素(放大或缩小)

    img463 translate:在屏幕上移动元素(上下左右四个方向)

    img464 rotate:按照一定角度旋转元素(单位为度)

    img465 skew:沿X和Y轴对元素进行斜切

    img466 matrix:允许你以像素精度来控制变形效果

    接下来我们逐个试验一下,看看会有什么效果。

    1. scale

    我们前面看到过这种变形效果。但是除了我们刚才使用的正整数值,还要知道使用小于1的值可以缩小元素;下面的代码就会将元素缩小一半:

    img467

    img468

    1. translate

    img469

    translate会告知浏览器按照一定度量值移动元素,可以使用像素或百分比。语法是第一个值表示从左向右移动的距离(本例中是40像素),然后是从上往下移动的距离(本例中是0像素,所以元素与其他导航链接保持对齐)。正值会让元素向右或向下移动,负值则会让元素向左或向上移动。所以本例中对导航链接的声明效果是:链接在鼠标悬停时水平向右移动40像素。

    img470

    1. rotate

    img471

    rotate允许你旋转一个元素。在本例中,我们将链接悬停的变形修改为旋转90度。在浏览器中的效果如下:

    img472

    括号中的值只能以度为单位(如90deg)。当然,这也挡不住你胡来——你可以让一个元素按照下面所设定的这个值来旋转:

    img473

    这会让元素旋转整整10圈。这么奇怪的值,其用处少之又少,除非你给一家风车公司设计网站,那倒可能会派上用场。

    1. skew

    如果你多少有点Photoshop经验,就会知道skew(斜切)是怎么回事,它会让元素在一个或两个轴上变形偏斜。

    img474

    在悬停状态的导航链接上应用该规则,产生的效果如下:

    img475

    第一个值是X轴上的斜切(本例中是10度),第二个值是Y轴上的斜切(本例中是2度)。省略第二个值意味着仅有的值只会应用在X轴上(水平方向)。例如:

    img476

    这样写完全有效,只是斜切仅会作用于X轴。斜切值始终以度为单位。正值沿顺时针方向斜切,负值则沿逆时针方向斜切。

    1. matrix

    好,现在该聊聊那个被严重抬高的电影(2)了。什么电影?!别忘了你要讲的是CSS3中的matrix,不是电影!是吗?好吧,看下面……

    matrix变形的语法看起来超复杂:

    img477

    它基本上能让你将若干变形效果(scale、rotate、skew等等)组合成单个声明。上面的声明在浏览器中产生的效果如下:

    img478

    总的来说,我还是蛮喜欢挑战难题的,但我相信你也会同意这语法也太有挑战性了。而且在你看了规范文档之后就会发现问题更难,要完全理解矩阵你得了解相关的数学知识:http://www.w3.org/TR/css3-2d-transforms/#cssmatrix-interface。

    傻瓜化的矩阵变形工具

    无论怎么想象我都不是一个数学家,所以当我需要创建矩阵变形时,我一般都走捷径。如果你的数学也不太好,我建议你访问这里:http://www.useragentman.com/matrix/。

    img479

    Matrix Construction Set这个网站可以让你精确地将元素拖曳成想要的样子,然后它会自动生成完美的矩阵代码(代码中包含了浏览器私有前缀)。

    1. transform-origin属性

    在使用上述变形效果的同时,你还可以使用transform-origin属性来修改变形效果的起点:

    img480

    将上面的规则应用到导航链接上,鼠标悬停之后的效果如下:

    img481

    transform-origin属性默认就在起作用,变形的起点默认是元素的中心点。这个属性提供了一种方便的方法来移动变形的中心点,这样能做出很多很赞的效果。

    transform-origin属性的详细信息请见这里:http://www.w3.org/TR/css3-2d-transforms/#transform-origin-property。

    以上讲述了2D变形的基本要素。比起3D变形,2D变形在浏览器中被广泛地支持,它为我们提供了一种轻量便捷的方法,让现代浏览器的用户体验得以锦上添花。

    CSS3的2D变形模块的完整规范文档请见:http://www.w3.org/TR/css3-2d-transforms/。 7.3 尝试CSS3的3D变形 Webkit核心浏览器(Safari和Chrome)和Firefox 10+都已支持CSS3的3D变形,但最新的IE10都还不支持该特性。尽管缺少“桌面版”浏览器的广泛支持,但多亏了移动平台浏览器基本都是Webkit血统,所以3D变形在Android(V3以后的版本)和iOS(所有版本)上均被支持。

    从这点上来讲,你最好在Webkit核心浏览器(如Chrome或Safari)中测试网页效果(当然,也可以选择其他支持3D变形的浏览器)。

    现在我们开始尝试3D变形。这是一片广阔天地,有几乎无穷的可能性。我想象着有一天3D变形被广泛支持,我们就可以用它来做图片轮播效果,而不用再依赖jQuery等JavaScript方案了。不过,在那一刻到来之前,我们先来体验一下。

    假设给AND THE WINNER ISN'T网站做一个简单测验功能。测试题目由一组电影海报组成,你必须猜猜世界上最权威的电影评论家(哈哈,说的就是我!)对这些电影的评判是好是坏。将鼠标悬停在图片上(在触摸屏上则是触击图片)就能揭晓答案。

    下面的代码是相关的页面标签,其中省略了重复的图片标签,因为它们的结构都一样:

    img482

    对应的CSS代码如下。注意,因为Webkit浏览器对3D变形的支持比较好,所以下面的声明都使用特定的浏览器前缀。和之前一样,在实际开发中,浏览器私有前缀就是你形影不离的好朋友。

    img483

    代码部署好之后,将鼠标悬停在海报图片上,会看到图片翻转到背面并显示出了该电影的评判结果。

    img484 7.3.1 分析3D变形效果 我们来研究一下代码,看看3D变形效果是如何实现的。

    img485

    第一个要点是在父级元素上设置透视。这样就开启了3D场景:

    img486

    透视的值越大,就表示你的视点与3D场景之间的景深越大。因此,如果想要一点隐约的3D效果,就增大透视值;如果想要非常明显的3D效果,则减小透视值。(3D效果的立体程度,取决于3D场景与观察者之间的距离。)

    下一个要点:

    img487

    .Qcontainer类中添加的透视声明只会应用到其第一个子元素上(即本例中的class为.film的div)。因此,为了延续父元素的透视,我们给.film元素设定了preserve-3d(这样可以设置一个3D场景)。

    接下来,当鼠标悬停在.Qcontainer模块上时,我们给.film这个div添加一个翻转效果:

    img488

    接下来的规则用来处理当海报翻转之后隐藏在其背面内容:

    img489

    .face必须使用绝对定位,这样海报才能盖在.back这个div的上面:

    img490

    最后,我们给.back这个div也加上rotateY。不加这句的话,.back这个div就会显示在正面海报之上。

    这就全部做完了。现在将鼠标移到任意一张海报上都会看到超级酷炫的3D效果。

    不过,对于非Webkit核心浏览器,页面效果肯定就残废了:

    img491

    还好,我们可以用一点传统的CSS代码为非Webkit核心浏览器提供一个合理的降级方案:

    img492

    首先,我默认给.front设置了z-index为5,以便让其显示在.back上面:

    img493

    然后,当.Qcontainer模块处于悬停状态时,我们给.front设置z-index为0以便让其隐藏在.back后面:

    img494

    这样我们就给不支持3D变形的浏览器也提供了简单问答功能,只是缺少优雅的3D效果。

    img495 7.3.2 3D变形尚未成熟 根据我的实践经验,目前大多数3D变形在使用百分比尺寸时效果都不太好(例如,修改上节例子中的视口宽度,将会使3D变形效果完全错乱)。所以现在要让3D变形在响应式布局中呈现完美效果还有一些问题。此外,由于浏览器的支持有限,在制作跨浏览器网站时,3D变形无法提供健壮的解决方案。目前,我依然使用jQuery或类似技术来制作这类变形效果。

    但是,CSS3 3D变形的前途是光明的,当浏览器开始广泛支持时,它就为我们提供了一次难得的机遇,让我们可以将现在依赖于JavaScript的优雅效果移植到样式表中。

    想了解W3C有关CSS 3D变形的最新进展,请见这里:http://dev.w3.org/csswg/css3-3d-transforms/。 7.4 CSS3动画效果 如果你制作过Flash动画,那CSS3动画你也能立即上手。CSS3沿用了在Flash和其他基于时间线的应用程序中被广泛使用的动画关键帧技术。

    相较于3D变形,CSS3动画的浏览器支持度更高。Firefox 5+、Chrome、 Safari 4+、 Android(所有版本)、 iOS (所有版本)均支持,IE 10也决定加入该行列。

    CSS3动画由两部分组成:首先是关键帧声明,然后在动画属性中使用该关键帧声明。

    上一节我们制作了一个简单的翻转效果,用于展示我对电影的评判结果。但是翻转效果的背面文字非常丑陋,所以我们来给这些文字添加一个有趣的闪烁效果。

    首先是关键帧规则:

    img496

    此处的代码没有加前缀,如果在浏览器中没有效果,你可能需要添加一组完整的浏览器私有前缀(如@-webkit-keyframes)。

    我们来分析一下上面的代码:

    img497

    首先,我们定义了一个@keyframes(关键帧)声明。然后为这个特定的关键帧声明设置了一个名称:warning。你可以将其叫成任何名字,但考虑到这些关键帧声明可以在多个元素上复用,所以建议取一个合理的名字。

    可以设置多个关键帧(比如百分比值10%、20%、30%、40%等等),或者也可以使用from和to值来定义动画的开始帧和结束帧。但注意Webkit浏览器在使用from和to值的情况下效果无法保证(它更喜欢0%和100%)。

    img498

    本例给文字阴影加一点动画,动画开始时是4像素阴影,然后用50%的时间变化至40像素阴影,之后再变化回4像素阴影。

    我们已经声明了关键帧,接下来可以在动画属性中引用它:

    img499

    在animation属性之后,我们设定了要使用的关键帧(例子中的warning),然后设定了动画的持续时间(1.5s),之后设定了animation-iteration-count(我们在此时使用了infinite让动画连续循环播放),最后设定了调速函数(ease-in)。静态截图显然无法展示出动画,但希望你能想象得出文字阴影一闪一闪的效果。访问这里查看效果:http://www.andthewinnerisnt.com。

    img500

    CSS3动画缩写语法可以接受全部7个独立动画属性的值。除了上例中使用的之外,还可以设定animation-delay(动画开始前的延时),animation-play-state(值可以是running或paused,用于控制动画的播放和暂停),最后还有animation-fill-mode,这个属性到现在我也没找到用武之地(默认值是none)。当然也可以不用缩写语法,而是像下面这样将它们一个一个单独列出来:

    img501

    前面已经提过,在其他元素上复用动画效果非常简单,如下所示:

    img502

    这样导航链接也会有同样的闪烁效果。你可以(希望能)看到下面截图中的STILLS/PHOTOS链接正处在闪烁过程中。访问这里看看真实效果:http://www.andthewinnerisnt.com。

    img503

    这只是使用CSS3动画的一个简单示例。事实上任何CSS属性都可以用在关键帧动画中,所以有无限可能性。网上有数不清的CSS3动画技巧范例,像http://webdesignerwall.com/trends/47-amazing-css3-animation-demos 这个网页就足以给你提供丰富的CSS3动画灵感。

    想了解W3C有关CSS动画的最新进展,请见这里:http://dev.w3.org/csswg/css3-animations/。

    组合使用CSS3变形和动画

    我们来尝试再做一种效果,秀一下我们的CSS3功力。我想将侧边栏的图片按照不同的角度来放置,然后让它们动起来。目标就是当页面刚加载进来的时候这些图片都“晃”几下。侧边栏的标签代码如下:

    img504

    接下来我们开始编写相关的CSS3代码。首先,创建一个名为swing的关键帧声明:

    img505

    这个动画使用了2D旋转变形,以使图片从3度旋转至10度然后再旋转回原位。接下来给图片上追加animation属性:

    img506

    我们来分析一下上面的代码。首先我们使用了CSS的id选择器,这样就可以将该规则限定应用在QUIZ页面上(该页面上的body标签是<body id="quiz">)。

    在添加动画属性之前,我想先给图片设置一个默认的旋转变形,以便让它们在动画结束之后仍然是倾斜的。但我不想它们都按同一个角度倾斜,所以我们使用从第5章中学来的nth-child选择器来分别选择出奇数与偶数图片,然后应用不同的旋转变形:

    img507

    然后给每张图片都追加animation属性,注意规则之间的差别。缩写语法会将第二个时间值(0.5秒)认定为动画延时时间。通过设定这个值,就可以分别在不同的时间启动各个动画效果。

    img508

    同样,再好的文字也展示不出来动画效果。如果你这会儿上不了网,那我只能告诉你,侧边栏的电影海报会快速地左右晃动几下,之后就会像下图所示那样倾斜地摆放着:

    img509 7.5 小结 有关CSS3过渡、变形和动画的内容,足足可以写好几本书。但是我希望通过本章蜻蜓点水般的学习,你能了解它们的基本知识并让它们运行起来。其实,我们采用CSS3新特性和技巧的最终目的,是想使用CSS3来替代JavaScript制作一些优雅精美的增强效果,从而使响应式设计的代码更加简洁、效果更加丰富。本章我们学习了CSS3过渡是什么,以及如何编写相应代码,了解了ease、linear等调速函数,并在响应式设计中应用它们制作了简单但有趣的效果。还学习了缩放、斜切等2D变形,以及如何将它们与过渡组合使用。此外,还在学习CSS3动画的强大功能与简洁语法之前,简单了解了3D变形。你要相信自己的CSS3功力正在不断增长!

    但是,如果网站设计中有一个领域是我尽可能避免谈及的(就如我拼命不想看《慕尼黑》或《金刚》一样),那肯定就是表单。我不知道为什么,只是一直觉得制作表单是件单调乏味的事儿。当我知道了HTML5和CSS3可以让表单的制作、美化甚至验证(没错,就是验证!)过程都比以往简单很多时,简直把我给乐坏了。我高兴得都手舞足蹈了,相信到时候你也会跟我一样。下一章我们就来学习HTML5表单。

    【注释】

    (1)该网站最新版的CSS代码中没有这句代码,所有元素都应用过渡效果,影响性能。——译者注

    (2)Matrix即电影《黑客帝国》,详见http://baike.baidu.com/view/180529.htm#sub5119498。——译者注