做网页动效时,图片的缩放和颜色变化是最常见的两种效果。有人用JavaScript写定时器去改宽高,代码一大堆还容易掉帧,其实CSS3提供的@keyframes规则配合animation属性,几行代码就能让图片平滑地变大变小,颜色也能随之渐变,浏览器还会自动做性能优化,比脚本动画流畅得多。本文把这套动画的写法完整拆开讲一遍,看完直接就能用到自己的项目里。

@keyframes规则与animation属性基础
先说清楚@keyframes到底是什么。它是一个用来定义动画关键帧的规则,你可以把它理解成动画的“剧本”:在0%的时候元素是什么状态,在50%的时候变成什么状态,到100%的时候又是什么状态,都由你来编写。浏览器拿到这个剧本后,会自动把中间的过渡过程补齐,形成连续的动画。
剧本写好后,还需要让某个元素去“演出”,这就轮到animation属性出场了。它有以下几个常用子属性:animation-name指定要使用的关键帧名称,animation-duration设置一次动画的时长,animation-iteration-count控制播放次数(写infinite就是无限循环),animation-timing-function决定动画的速度曲线,animation-direction可以设置是否来回交替播放。一个最简的写法如下:
.box {
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.3); }
100% { transform: scale(1); }
}这段代码的意思是:类名为box的元素会循环播放名为pulse的动画,一个周期2秒。动画从原始大小开始,中间放大到1.3倍,最后又缩回原样。ease-in-out让变化先慢后快再慢,看起来更自然。如果希望图片放大后再“倒放”回去,可以加一句animation-direction: alternate,不过上面的写法已经在100%处回到了初始状态,两种方式效果接近,按需选择即可。
用transform的scale实现图片变大变小
控制元素大小有两条路:一是直接改width和height,二是用transform: scale()。强烈推荐第二种。原因在于width和height的变化会触发浏览器的回流重排,每一帧都要重新计算布局,性能开销大;而transform属于合成层操作,浏览器只需在GPU上对元素做缩放变换,不触发布局计算,动画非常流畅。
scale接收的参数是缩放倍数,1表示原始大小,1.5表示放大到1.5倍,0.5则是缩小一半。还可以传两个参数分别控制水平和垂直方向,比如scale(1.2, 0.8)表示横向拉伸、纵向压缩。下面给一个图片呼吸效果的实际例子,这是电商网站商品图上很常用的动效:
<div class="img-wrap">
<img src="product.jpg" class="breath-img" alt="商品图">
</div>
<style>
.breath-img {
width: 300px;
animation: breathe 3s ease-in-out infinite;
}
@keyframes breathe {
0% { transform: scale(1); }
50% { transform: scale(1.15); }
100% { transform: scale(1); }
}
</style>有个细节需要注意:scale缩放不会改变元素占用的布局空间,也就是说图片放大时可能覆盖到周围的内容。如果不想遮挡邻居元素,可以给外层容器设置overflow: hidden,或者预留足够的边距。另外,为了让缩放以中心点为准,可以配合transform-origin: center,这个属性默认就是center,一般不用额外设置,但一旦你发现缩放的原点不对,第一个要检查的就是它。
颜色变化的两种实现方式
颜色变化在CSS3动画里有两条主流路线,各自适合不同的场景。第一种是直接对颜色属性做过渡,比如背景色从红色渐变到蓝色,浏览器会在关键帧之间自动做颜色插值,写法非常直观:
.color-box {
width: 200px;
height: 200px;
animation: colorShift 4s linear infinite;
}
@keyframes colorShift {
0% { background-color: #ff6b6b; }
33% { background-color: #feca57; }
66% { background-color: #48dbfb; }
100% { background-color: #ff6b6b; }
}这里的关键帧用了33%和66%做中间节点,让红、黄、蓝三种颜色依次过渡,最后回到红色形成无缝循环。注意animation-duration设为4秒,那么每个颜色阶段大约各占1.3秒,节奏比较舒缓。如果你希望颜色跳变而不是平滑过渡,可以在相邻两个关键帧写相同的百分比,比如33%和34%分别写两种颜色,过渡时间几乎为零,看起来就是瞬间切换。
第二种方式是针对图片本身。图片的像素内容没法直接用background-color改,这时候要用filter滤镜。其中hue-rotate可以旋转色相,让图片整体呈现不同色调;grayscale能做黑白过渡;sepia则是复古泛黄效果。例如让一张图片在正常色调和暖色调之间来回变化:
.tone-img {
width: 300px;
animation: toneShift 5s ease-in-out infinite;
}
@keyframes toneShift {
0%, 100% { filter: hue-rotate(0deg) saturate(1); }
50% { filter: hue-rotate(45deg) saturate(1.4); }
}hue-rotate的取值范围是0到360度,50度左右偏黄绿,180度左右接近反色。saturate控制饱和度,1是原图,大于1会更鲜艳。需要注意的是,filter动画虽然不触发重排,但每一帧都要对像素做计算,大面积图片上可能有一定开销,建议对尺寸适中的图片使用,或者用will-change: filter提前告知浏览器做优化。
缩放与变色组合的完整案例
把前面的两个效果合到一个@keyframes里,就能得到一个既有大小变化又有颜色变化的完整动画。假设要做一个活动的推广图,图片循环呼吸式放大,同时叠加一层不断变换颜色的光晕,整体代码如下:
<div class="promo">
<img src="banner.jpg" class="promo-img" alt="活动图">
</div>
<style>
.promo {
position: relative;
width: 400px;
margin: 50px auto;
}
.promo-img {
width: 100%;
display: block;
border-radius: 12px;
animation: zoomTone 4s ease-in-out infinite;
}
@keyframes zoomTone {
0% {
transform: scale(1);
filter: hue-rotate(0deg) brightness(1);
}
50% {
transform: scale(1.2);
filter: hue-rotate(30deg) brightness(1.15);
}
100% {
transform: scale(1);
filter: hue-rotate(0deg) brightness(1);
}
}
</style>这个例子把transform和filter写在同一个关键帧里,浏览器会同时对两个属性做插值,缩放和变色严格同步,视觉上非常协调。brightness让图片在放大时稍微提亮,产生一种被“点亮”的感觉。如果还想加文字变色,可以在容器里再放一层文字,给它单独写一个只改color的关键帧,两个动画同时播放互不干扰。
动画体验优化与兼容性建议
动画写完不等于万事大吉,实际部署前还有几点值得注意。首先是性能方面,尽量把动画限制在transform和opacity这两个属性上,它们能完全交给GPU处理;filter虽好用但开销略高,移动端上要控制使用面积。其次,如果动画元素会被频繁操作,可以加上will-change: transform, filter,让浏览器提前创建独立合成层,减少运行时的卡顿,但这个属性不要滥用,设置太多层反而浪费内存。
其次是用户偏好问题。部分用户会在系统里开启“减少动态效果”的选项,出于无障碍考虑,可以用媒体查询尊重他们的选择:
@media (prefers-reduced-motion: reduce) {
.promo-img {
animation: none;
}
}最后是兼容性。@keyframes、animation和transform在目前主流浏览器中都已经支持得很好,包括移动端浏览器,基本不需要加-webkit-前缀。只有一些老旧的iOS版本和Android WebView需要前缀,如果你的项目还要兼容它们,可以在animation前面加一行-webkit-animation,在@keyframes前加@-webkit-keyframes做兜底。一般现代项目直接写标准语法即可。掌握这些要点后,图片的缩放、变色动画就都能信手拈来了。
CSS3动画@keyframestransform修改时间:2026-09-06 11:22:41