3、动画属性全家桶:从入门到精通

说实话,CSS动画的属性看起来挺多的。八个属性,乍一看有点吓人。但别担心,我带你一个一个捋清楚。这八个属性就像是动画的八块积木,拼在一起就能搭出各种效果。

我在项目中见过不少同学,写动画就只会用个简写属性。一旦要控制动画暂停、保持结束状态,就傻眼了。嗯,今天咱们就把这八个属性彻底搞明白。

3.1 animation-name:给动画起个名字

这个最简单。就是告诉浏览器,你要用哪个@keyframes定义的动画。

/* 定义一个动画 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* 引用它 */
.element {
  animation-name: fadeIn;
}

你可以同时引用多个动画,用逗号隔开:

.element {
  animation-name: fadeIn, slideUp, rotate;
}
我的习惯:动画命名用驼峰式,比如fadeIn、slideUp。别用中文,也别用太随意的名字。你想想看,项目大了以后,看到个"myAnimation"这种名字,谁还记得是干嘛的?

3.2 animation-duration:动画跑多久

这个属性控制动画从开始到结束的总时长。单位是秒(s)或毫秒(ms)。

.element {
  animation-name: fadeIn;
  animation-duration: 2s;    /* 2秒 */
  /* 或者 */
  animation-duration: 2000ms; /* 2000毫秒 */
}

多个动画可以设置不同的时长:

.element {
  animation-name: fadeIn, slideUp;
  animation-duration: 1s, 2s; /* fadeIn用1秒,slideUp用2秒 */
}
注意:我曾经遇到过一个bug,动画看起来没效果。查了半天,发现是duration设成了0s。0秒的动画,浏览器直接就跳过了。所以记得检查你的时长设置。

3.3 animation-timing-function:动画的节奏感

这个属性控制动画的速度变化。说白了就是让动画看起来更自然。

.element {
  animation-name: move;
  animation-duration: 2s;
  animation-timing-function: ease; /* 默认值 */
}

常用的几个值:

效果 适用场景
ease 慢-快-慢 大多数场景,默认值
linear 匀速 进度条、旋转加载
ease-in 慢到快 元素离开屏幕
ease-out 快到慢 元素进入屏幕
ease-in-out 慢-快-慢 弹窗出现和消失
cubic-bezier() 自定义曲线 需要精确控制节奏

重点来了:cubic-bezier()可以自定义任何节奏。比如弹跳效果:

.element {
  animation-timing-function: cubic-bezier(0.68, -0.55, 0.27, 1.55);
}

这个曲线会让元素产生"弹一下"的效果。我经常用它做按钮点击反馈。

3.4 animation-delay:让动画等一下

这个属性控制动画延迟多久才开始。可以是正数,也可以是负数。

.element {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-delay: 1s;  /* 等1秒再开始 */
}

负数延迟很有意思:

.element {
  animation-delay: -1s;  /* 从动画的第1秒开始播放 */
}
实用技巧:我做列表动画时,经常用负延迟让多个元素同时开始但处于不同进度。比如三个卡片同时出现,但位置不同,看起来就像波浪一样。

3.5 animation-iteration-count:动画播几次

控制动画重复播放的次数。默认是1次。

.element {
  animation-name: spin;
  animation-duration: 1s;
  animation-iteration-count: 3;     /* 播3次 */
  /* 或者 */
  animation-iteration-count: infinite; /* 无限循环 */
}
避坑指南:我曾经在做一个loading动画时,用了infinite。结果用户反馈说页面卡死了。后来发现是动画里有个属性一直在触发重排。无限循环的动画一定要检查性能,特别是移动端。

3.6 animation-direction:动画的方向

这个属性控制动画是正向播放、反向播放,还是来回播放。

.element {
  animation-name: slide;
  animation-duration: 2s;
  animation-iteration-count: 2;
  animation-direction: normal;    /* 正向(默认) */
  /* 其他选项 */
  animation-direction: reverse;   /* 反向 */
  animation-direction: alternate; /* 来回 */
  animation-direction: alternate-reverse; /* 先反再正 */
}

alternate这个值特别实用。比如做呼吸灯效果:

@keyframes breathe {
  from { opacity: 0.3; }
  to { opacity: 1; }
}

.element {
  animation: breathe 2s infinite alternate;
}

这样元素就会从暗到亮,再从亮到暗,循环往复。比用两个keyframes简单多了。

3.7 animation-fill-mode:动画结束后的状态

这个属性很多人会忽略。但它真的很重要。它控制动画开始前和结束后,元素应该处于什么状态。

.element {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-fill-mode: none;     /* 默认,不保留任何状态 */
  animation-fill-mode: forwards; /* 保留最后一帧的状态 */
  animation-fill-mode: backwards;/* 应用第一帧的状态 */
  animation-fill-mode: both;     /* 同时应用前后状态 */
}

举个例子你就明白了:

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* 不加fill-mode,动画结束后元素变回原来的透明度 */
/* 加了forwards,动画结束后元素保持opacity: 1 */

我的经验:做弹窗动画时,我习惯用both。这样弹窗在动画开始前就隐藏(backwards),结束后保持显示(forwards)。一个属性解决两个问题。

3.8 animation-play-state:控制动画的播放和暂停

这个属性特别适合做交互控制。比如鼠标悬停时暂停动画。

.element {
  animation-name: spin;
  animation-duration: 2s;
  animation-iteration-count: infinite;
  animation-play-state: running; /* 播放(默认) */
}

.element:hover {
  animation-play-state: paused;  /* 暂停 */
}
实用场景:我做轮播图时,就用这个属性。默认自动播放,鼠标移上去暂停。用户操作完再继续播放。比用JavaScript控制方便多了。

3.9 简写属性:一行搞定

八个属性写起来确实有点多。CSS提供了简写方式:

/* 完整写法 */
.element {
  animation-name: fadeIn;
  animation-duration: 2s;
  animation-timing-function: ease;
  animation-delay: 1s;
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-fill-mode: both;
  animation-play-state: running;
}

/* 简写 */
.element {
  animation: fadeIn 2s ease 1s infinite alternate both running;
}

顺序是:name duration timing-function delay iteration-count direction fill-mode play-state

注意:简写虽然方便,但可读性差。我个人的习惯是:在demo或简单项目里用简写,在正式项目里还是分开写。你想想看,三个月后回来看代码,简写那行你能一眼看出每个值是什么意思吗?

3.10 实战:组合使用

来看一个完整的例子。我做了一个加载动画:

@keyframes pulse {
  0% { transform: scale(1); opacity: 0.5; }
  50% { transform: scale(1.2); opacity: 1; }
  100% { transform: scale(1); opacity: 0.5; }
}

.loading-dot {
  width: 20px;
  height: 20px;
  background: #3498db;
  border-radius: 50%;
  animation-name: pulse;
  animation-duration: 1.5s;
  animation-timing-function: ease-in-out;
  animation-delay: 0s;
  animation-iteration-count: infinite;
  animation-direction: normal;
  animation-fill-mode: none;
  animation-play-state: running;
}

/* 三个点依次延迟 */
.loading-dot:nth-child(2) {
  animation-delay: 0.3s;
}

.loading-dot:nth-child(3) {
  animation-delay: 0.6s;
}

这个例子用到了延迟、无限循环、自定义timing function。三个点依次跳动,效果很流畅。

好了,八个属性都讲完了。说白了就是:name告诉浏览器用哪个动画,duration控制时长,timing-function控制节奏,delay控制何时开始,iteration-count控制次数,direction控制方向,fill-mode控制状态,play-state控制启停。

记住这些,你就能随心所欲地控制CSS动画了。下一章我们聊聊动画的性能优化,这可是实战中的硬功夫。