源本科技 | 码上会

CSS 动画

2026/03/06
18
0

学习目标

  • 掌握 @keyframes 规则,学会定义动画的起始、中间和结束状态

  • 理解并运用 8 大动画属性(如 duration, timing-function, direction 等)精细控制动画行为

  • 学会使用 animation 简写属性高效编写代码

  • 了解性能优化策略与无障碍设计最佳实践


正文内容

什么是动画

CSS 动画允许开发者在不依赖 JavaScript 的情况下,直接通过 CSS 控制 HTML 元素的运动和外观变化。与 CSS 过渡(Transitions)不同,动画不需要触发事件(如 :hover)即可自动运行,并且可以无限循环、往复运动或停留在特定状态。

核心优势:

  • 自主运行:页面加载后即可自动播放。

  • 关键帧控制:可以定义动画过程中的任意中间状态,而不仅仅是起点和终点。

  • 灵活循环:支持无限循环、指定次数循环或往返播放。

基础示例:颜色渐变

以下示例展示了一个方块在 3 秒内从蓝色平滑变为绿色,并无限循环。

<!DOCTYPE html>
<html>
<head>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: blue;
            /* 应用名为 changeColor 的动画,时长 3 秒,无限循环 */
            animation: changeColor 3s infinite;
        }

        /* 定义关键帧 */
        @keyframes changeColor {
            from {
                background-color: blue;
            }
            to {
                background-color: green;
            }
        }
    </style>
</head>
<body>
    <div class="box"></div>
</body>
</html>

原理解析:

  1. @keyframes changeColor 定义了动画的具体步骤:从蓝色(from)变到绿色(to)。

  2. .box 类通过 animation 属性引用了这个关键帧序列,并设定了时长和循环次数。

核心概念

@keyframes 是 CSS 动画的灵魂,它描述了动画在时间轴上的变化过程。

语法结构:

@keyframes 动画名称 {
    from {
        /* 初始状态样式 */
    }
    to {
        /* 结束状态样式 */
    }
}

进阶用法:百分比关键帧
除了 from (0%) 和 to (100%),你还可以使用百分比来定义中间状态,从而创建更复杂的动作序列(如弹跳效果)。

@keyframes bounce {
    0% {
        transform: translateY(0);
    }
    50% {
        transform: translateY(-50px); /* 跳到最高点 */
    }
    100% {
        transform: translateY(0); /* 落回地面 */
    }
}

八大动画控制属性

CSS 提供了 8 个独立属性来全方位控制动画行为。

1. 动画名称

animation-name

指定要应用到元素上的 @keyframes 名称。

  • 语法animation-name: keyframeName;

  • 作用:将元素与定义好的关键帧序列绑定。

2. 动画时长

animation-duration

定义动画完成一个周期所需的时间。

  • 语法animation-duration: 2s; (秒) 或 200ms; (毫秒)

  • 注意:默认值为 0s,如果不设置时长,动画不会发生。

3. 时序函数

animation-timing-function

控制动画在关键帧之间的速度变化曲线。

  • 常用值

    • linear:匀速。

    • ease(默认):慢 - 快 - 慢。

    • ease-in:慢速开始。

    • ease-out:快速开始,慢速结束。

    • steps(n):将动画分为 n 步执行(适合帧动画)。

4. 动画延迟

animation-delay

设置动画开始前的等待时间。

  • 语法animation-delay: 1s;

  • 场景:用于错开多个元素的动画启动时间,营造层次感。

5. 循环次数

animation-iteration-count

指定动画播放的次数。

  • 常用值

    • number:具体数字,如 3 表示播放 3 次。

    • infinite:无限循环。

6. 播放方向

animation-direction

定义动画是正向播放、反向播放还是交替播放。

  • 常用值

    • normal(默认):每次循环都从 0% 到 100%。

    • reverse:每次循环都从 100% 到 0%。

    • alternate:奇数次循环正向(0%->100%),偶数次循环反向(100%->0%)。

    • alternate-reverse:奇数次反向,偶数次正向。

7. 填充模式

animation-fill-mode

定义动画在执行前(延迟期间)和执行后(结束后)的样式状态。

  • 常用值

    • none(默认):动画不应用时,元素保持原有样式。

    • forwards:动画结束后,元素保持在最后一帧的状态(最常用)。

    • backwards:在延迟期间,元素显示第一帧的样式。

    • both:同时应用 forwardsbackwards 的效果。

8. 播放状态

animation-play-state

控制动画是正在运行还是暂停。

  • 常用值

    • running(默认):动画正常播放。

    • paused:动画暂停。

  • 交互场景:常配合 :hover 使用,实现“鼠标悬停暂停动画”的效果。

<style>
    .box {
        animation: spin 4s linear infinite;
        animation-play-state: paused; /* 默认暂停 */
    }
    .box:hover {
        animation-play-state: running; /* 悬停时播放 */
    }
    @keyframes spin {
        from { transform: rotate(0deg); }
        to { transform: rotate(360deg); }
    }
</style>

简写属性

为了代码简洁,推荐使用 animation 简写属性一次性设置所有参数。

语法顺序:

animation: [name] [duration] [timing-function] [delay] [iteration-count] [direction] [fill-mode] [play-state];

注意:只有 nameduration 是必须的,其他可选。如果有两个时间值,第一个是 duration,第二个是 delay

综合示例:

.box {
    /* 
       动画名: move
       时长: 2s
       速度曲线: ease-in
       延迟: 1s
       循环: infinite
       方向: alternate (往返)
       填充: forwards (保持结束状态)
    */
    animation: move 2s ease-in 1s infinite alternate forwards;
}

动画流程

为了清晰展示各个属性如何协同工作,以下是动画生命周期的流程图:

最佳实践

  1. 目的明确:动画应增强用户体验(如引导注意力、反馈操作),而不是造成干扰。避免滥用闪烁或快速移动的元素。

  2. 性能优先

    • 推荐:优先动画化 transform (位移、旋转、缩放) 和 opacity。这些属性由 GPU 加速,不会触发布局重排(Reflow),性能极佳。

    • 避免:尽量避免动画化 width, height, margin, top, left 等会触发布局计算的属性,这在复杂页面中会导致卡顿。

  3. 无障碍设计(Accessibility)

    • 部分用户对运动敏感(如前庭障碍),快速动画可能引起不适。

    • 建议使用媒体查询 prefers-reduced-motion 为这类用户提供简化或禁用动画的方案:

    @media (prefers-reduced-motion: reduce) {
        * {
            animation: none !important;
            transition: none !important;
        }
    }

总结

  • 关键帧驱动@keyframes 允许定义 0% 到 100% 之间的任意中间状态,实现复杂动作。

  • 八大属性

    • 基础:name, duration

    • 控制:timing-function, delay, iteration-count, direction

    • 状态:fill-mode, play-state

  • 简写高效animation 简写属性是标准写法,注意时间值的顺序(时长在前,延迟在后)。

  • 方向与填充alternate 实现往返运动,forwards 确保动画结束后不还原初始状态。

  • 性能铁律:尽量只动画化 transformopacity,以保障流畅度。


思考题

  1. 填充模式陷阱:如果一个动画设置了 animation-duration: 2sanimation-iteration-count: 1,但没有设置 animation-fill-mode。当 2 秒结束后,元素会停留在最后一帧的样子,还是瞬间变回初始状态?如果希望它停留在最后一帧,应该加什么属性?

  2. 往返逻辑:如果设置 animation-direction: alternateanimation-iteration-count: 3。请问第 1 次、第 2 次和第 3 次循环分别是正向播放还是反向播放?

  3. 性能对比:为什么在实现一个“从左移动到右”的效果时,使用 transform: translateX() 比使用 margin-left 性能更好?请从浏览器渲染流水线(Render Pipeline)的角度简要解释。