源本科技 | 码上会

CSS 过渡

2026/03/06
17
0

学习目标

  • 理解 CSS 过渡的核心概念,掌握如何通过状态变化触发动画

  • 精通四大过渡子属性:transition-propertydurationtiming-functiondelay

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

  • 了解最佳实践,避免性能陷阱,提升用户交互体验


正文内容

什么是过渡

CSS 过渡(Transitions)是一种在元素的两个状态之间创建平滑动画效果的技术。与瞬间完成的样式切换不同,过渡允许属性值在一段时间内逐渐变化,从而极大地增强了网页的交互性和用户体验。

核心特点:

  • 状态驱动:过渡通常由状态变化触发,例如鼠标悬停(:hover)、焦点获取(:focus)或通过 JavaScript 添加 / 移除类名。

  • 属性支持:并非所有 CSS 属性都能过渡。通常支持数值型属性(如 width, height, opacity, color, transform 等)。

  • 无需关键帧:与 @keyframes 动画不同,过渡只需要定义“起始状态”和“结束状态”,浏览器会自动计算中间过程。

基础示例:颜色平滑切换

以下示例展示了当用户将鼠标悬停在方块上时,背景色如何在 0.5 秒内从蓝色平滑变为绿色。

<!DOCTYPE html>
<html>
<head>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: blue;
            /* 定义过渡:背景色变化耗时 0.5 秒 */
            transition: background-color 0.5s;
        }

        .box:hover {
            /* 悬停时改变背景色,触发过渡 */
            background-color: green;
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <p>将鼠标悬停在方块上查看过渡效果。</p>
</body>
</html>

原理解析:

  1. 初始状态下,.box 的背景是蓝色。

  2. 当触发 :hover 伪类时,背景色目标值变为绿色。

  3. 由于定义了 transition,浏览器不会立即切换颜色,而是在 0.5 秒内插值计算每一个中间颜色,形成渐变效果。

四大核心过渡属性

CSS 提供了四个独立的属性来精细控制过渡行为。

1. 过渡属性

该属性指定哪些 CSS 属性需要应用过渡效果。你可以选择特定属性、所有属性或不应用任何过渡。

语法:

transition-property: none | all | property-name [, property-name...];

常用值:

  • none:没有任何属性发生过渡。

  • all:所有发生变化的属性都进行过渡(默认值)。

  • property-name:指定具体的属性名,如 width, opacity, transform 等。多个属性用逗号分隔。

示例:仅宽度变化

<style>
    .box {
        width: 100px;
        height: 100px;
        background-color: blue;
        /* 仅对 width 属性应用过渡 */
        transition-property: width;
        transition-duration: 0.5s;
    }
    .box:hover {
        width: 200px; /* 触发宽度过渡 */
        background-color: green; /* 颜色会瞬间变化,因为未包含在 transition-property 中 */
    }
</style>

在此例中,悬停时宽度会平滑展开,但背景色会瞬间从蓝变绿,因为 background-color 未被列入过渡列表。

2. 过渡持续时间

该属性定义过渡效果完成所需的时间。这是过渡生效的必要条件,默认值为 0s(即无过渡效果)。

语法:

transition-duration: time;
  • time:时间值,单位为秒(s)或毫秒(ms)。例如 0.5s500ms

示例:

.box {
    transition-duration: 0.5s; /* 变化过程持续半秒 */
}

3. 过渡时序函数

该属性控制过渡过程中的速度曲线,即变化是匀速进行,还是先快后慢、先慢后快等。

语法:

transition-timing-function: ease | ease-in | ease-out | ease-in-out | linear | step-start | step-end | cubic-bezier(...);

常用值解析:

  • linear:匀速运动,从头到尾速度一致。

  • ease(默认):慢 - 快 - 慢,自然的启动和停止。

  • ease-in:慢速开始,加速结束。

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

  • ease-in-out:慢速开始,中间加速,最后慢速结束。

示例:

.box {
    transition-timing-function: ease-in-out; /* 起止缓慢,中间快速 */
}

4. 过渡延迟

该属性定义在状态改变后,等待多久才开始执行过渡效果。

语法:

transition-delay: time;
  • time:延迟时间,单位 sms

示例:

.box {
    transition-delay: 1s; /* 悬停后等待 1 秒才开始变色 */
}

简写属性

为了简化代码并提高可读性,我们可以将上述四个属性合并为一个 transition 简写属性。

语法顺序:

transition: [property] [duration] [timing-function] [delay];

注意:delay 必须放在 duration 之后。如果只写两个时间值,第一个是 duration,第二个是 delay

综合示例:

<!DOCTYPE html>
<html>
<head>
    <style>
        .box {
            width: 100px;
            height: 100px;
            background-color: blue;
            
            /* 简写:宽度变化,耗时 0.5s,缓动模式 ease-in-out,延迟 1s 开始 */
            transition: width 0.5s ease-in-out 1s;
        }

        .box:hover {
            width: 200px;
        }
    </style>
</head>
<body>
    <div class="box"></div>
    <p>悬停后等待 1 秒,方块宽度将在 0.5 秒内平滑展开。</p>
</body>
</html>

过渡过程可视化

为了帮助理解 timing-functiondelay 的作用,我们可以通过以下流程图展示整个过渡的时间轴:

最佳实践

  1. 优先使用简写:使用 transition 简写属性可以减少代码行数,使逻辑更集中。

  2. 只动画化可渲染属性:尽量对 transformopacity 进行过渡,因为它们可以由 GPU 加速,性能最好。避免对 width, height, margin 等触发布局重排(Reflow)的属性进行复杂动画,这可能导致页面卡顿。

  3. 多属性过渡:如果需要过渡多个属性,可以使用 all 或者逗号分隔列表。

    /* 推荐方式 */
    transition: transform 0.3s ease, opacity 0.3s ease;
  4. 跨设备测试:在不同性能的设备和浏览器上测试过渡效果,确保在低端设备上也能保持流畅,必要时降低动画复杂度。


总结

  • 触发机制:过渡是由样式状态的改变(如 :hover、类名切换)自动触发的,不需要 JavaScript 控制每一帧。

  • 四要素

    • property:决定什么在变。

    • duration:决定变化多快完成。

    • timing-function:决定变化的节奏(速度曲线)。

    • delay:决定何时开始变。

  • 简写优势transition: prop dur func delay; 是标准写法,简洁高效。

  • 性能提示:虽然 widthheight 可以过渡,但在高性能要求的场景下,优先使用 transform: scale() 代替尺寸变化,使用 opacity 代替显示 / 隐藏。


思考题

  1. 多属性差异:如果编写 transition: width 0.5s, color 1s;,当同时触发宽度和颜色变化时,这两个属性的动画会同时结束吗?请描述它们的播放过程。

  2. 延迟的往返:当一个元素设置了 transition-delay: 1s,鼠标悬停时会延迟 1 秒开始动画。那么当鼠标移开(状态恢复)时,是否也会有 1 秒的延迟?为什么?

  3. 性能优化:为什么在制作复杂的位移动画时,专家通常建议使用 transform: translateX() 而不是 margin-leftleft?这与浏览器的渲染机制有什么关系?