CSS面试:动画animation及性能分析

227 阅读7分钟

CSS 动画(animation)允许你通过定义关键帧(@keyframes)来创建复杂的动画效果,这些动画效果可以应用于 HTML 元素上。下面是 CSS 动画的详细讲解,包括核心概念、使用方法以及相关属性。

核心概念

  1. 关键帧(@keyframes

    • 定义了动画的关键步骤。你可以指定在动画的不同阶段元素应该如何变化。
    • 每个关键帧通过百分比(从 0%100%)或关键字(如 fromto)来定义。
  2. 动画属性(animation

    • 应用于元素上,用于控制动画的整体行为,包括动画名称、持续时间、时间函数等。

基本语法

定义关键帧

@keyframes animationName {
    0% {
        /* 初始状态 */
        transform: translateX(0);
    }
    50% {
        /* 动画的中间状态 */
        transform: translateX(100px);
    }
    100% {
        /* 结束状态 */
        transform: translateX(0);
    }
}

应用动画

.element {
    animation-name: animationName;   /* 动画名称 */
    animation-duration: 2s;          /* 动画持续时间 */
    animation-timing-function: ease-in-out; /* 动画时间函数 */
    animation-delay: 1s;             /* 动画延迟时间 */
    animation-iteration-count: infinite; /* 动画迭代次数(无限次) */
    animation-direction: alternate;  /* 动画方向(交替播放) */
}

常用动画属性

  1. animation-name: 指定动画的名称,对应 @keyframes 中定义的动画。

    animation-name: exampleAnimation;
    
  2. animation-duration: 设置动画的持续时间,单位可以是秒(s)或毫秒(ms)。

    animation-duration: 2s;
    
  3. animation-timing-function: 定义动画的时间函数(加速度曲线),控制动画的速度变化。

    • 常用值:

      • linear(匀速)
      • ease(默认,逐渐加速和减速)
      • ease-in(逐渐加速)
      • ease-out(逐渐减速)
      • ease-in-out(加速后减速)
    animation-timing-function: ease-in-out;
    
  4. animation-delay: 设置动画的延迟时间,单位可以是秒(s)或毫秒(ms)。

    animation-delay: 1s;
    
  5. animation-iteration-count: 设置动画的迭代次数,可以是具体次数或 infinite(无限次)。

    animation-iteration-count: 3; /* 动画执行3次 */
    animation-iteration-count: infinite; /* 无限次 */
    
  6. animation-direction: 设置动画的播放方向。

    • 常用值:

      • normal(正常播放)
      • reverse(反向播放)
      • alternate(每次播放后反向播放)
      • alternate-reverse(每次播放后反向播放,初始播放方向与 reverse 相反)
    animation-direction: alternate;
    
  7. animation-fill-mode: 设置动画播放结束后的状态。

    • 常用值:

      • none(默认,不改变状态)
      • forwards(保留动画结束时的样式)
      • backwards(保留动画开始时的样式)
      • both(同时保留开始和结束时的样式)
    animation-fill-mode: forwards;
    
  8. animation-play-state: 控制动画的播放状态。

    • 常用值:

      • running(播放)
      • paused(暂停)
    animation-play-state: paused;
    

示例:简单的动画效果

假设我们要创建一个简单的动画,使元素从左到右移动:

HTML:

<div class="box"></div>

CSS:

@keyframes moveRight {
    from {
        transform: translateX(0);
    }
    to {
        transform: translateX(100px);
    }
}

.box {
    width: 50px;
    height: 50px;
    background-color: #4caf50;
    animation-name: moveRight;
    animation-duration: 2s;
    animation-timing-function: ease-in-out;
    animation-iteration-count: infinite;
}

在这个示例中:

  • @keyframes moveRight 定义了一个简单的动画,从 translateX(0) 移动到 translateX(100px)
  • box 类应用了这个动画,并设置了持续时间为 2 秒,时间函数为 ease-in-out,以及无限次循环播放。

通过这些属性,你可以创建各种动画效果,包括平移、旋转、缩放等。 CSS 动画提供了丰富的功能来实现流畅和动态的用户界面。

性能较好的原因

使用 animation: move 2s forwards; 定义 CSS 动画被认为是性能较好的方法之一,主要有以下几个原因:

1. 硬件加速

  • GPU 加速:大多数现代浏览器都会对 CSS 动画启用 GPU 加速,尤其是涉及到 transformopacity 属性的动画。当使用 @keyframes 进行动画定义时,浏览器通常会将动画操作交给 GPU 处理,而 GPU 擅长处理这些图形变化,从而减少了 CPU 的计算压力,使得动画更加流畅。

2. 非阻塞渲染

  • 独立于主线程:CSS 动画通过 @keyframes 定义,动画的执行不会阻塞浏览器的主线程。这意味着即使在动画执行时,JavaScript 的其他操作(如事件监听、DOM 操作)仍然可以正常进行,不会因为动画的存在而导致卡顿或延迟响应。
  • css动画在渲染线程(合成线程) :专门处理渲染相关的任务,如绘制页面内容到屏幕上。它负责管理图层的合成,特别是当动画涉及到 GPU 加速时。

3. 动画逻辑简单明了

  • 简化代码:通过 CSS 定义动画,可以将所有与动画相关的逻辑封装在样式表中,使得代码结构清晰,样式与行为分离。相较于 JavaScript 实现的动画,这种方式更简洁,而且容易维护。

4. 浏览器优化

  • 浏览器优化:浏览器对 CSS 动画的优化非常完善。使用 CSS 动画,浏览器可以更好地进行帧优化和合成层的管理,减少了不必要的重排和重绘。这是因为浏览器能够预先计算动画的每一帧,并在渲染时直接使用,而不是像 JavaScript 动画那样需要逐帧计算和渲染。

5. 简化控制与回收

  • 自动完成与回收forwards 关键字会让动画在播放完后保持在最后一帧的状态,并且不需要额外的 JavaScript 代码来控制动画的回放状态。浏览器在动画完成后会自动回收资源,使得动画的生命周期管理更加简单和高效。

6. 避免布局抖动

  • 减少布局计算:CSS 动画通常可以避免引起布局抖动(layout thrashing),因为它们使用的是 transformopacity 这种不会触发重排的属性,而 JavaScript 动画如果涉及到改变元素的 topleft 等位置属性,则可能会触发重新布局,影响性能。

在 CSS 动画(animation)中使用 transform 不会触发重排(reflow),主要是因为 transform 属性只涉及到元素的渲染层次的变化,而不涉及元素的实际布局结构。这些是主要原因:

Transform 属性的工作原理

  • transform 属性用于对元素进行二维或三维转换,例如平移(translate)、旋转(rotate)、缩放(scale)等。这些转换是基于元素的渲染树进行的,不改变元素的实际位置和尺寸在文档流中的表现。
  • 这些转换是在 GPU 上进行的,这意味着它们不会影响页面的布局计算。

 重排和重绘的区别

  • 重排(Reflow) :当元素的尺寸、位置或文档结构发生变化时,会重新计算元素的位置和尺寸,这个过程称为重排。重排会影响到布局的计算,通常比较昂贵。
  • 重绘(Repaint) :当元素的颜色、背景等视觉效果发生变化时,浏览器会重新绘制这些元素,但不涉及元素的布局计算。变换(transform)会触发重绘,但不会触发重排。

Transform 不改变文档流

  • 当你使用 transform 对元素进行操作时,元素在视觉上的位置会变化,但它在文档流中的位置保持不变。浏览器只是在渲染层次中改变元素的视觉表现,而不需要重新计算整个布局。

什么时候 animation 是最佳选择?

  • 当你需要实现复杂的、多步骤的动画时,CSS animation 是最佳选择。比如,从左上角移动到右下角,并且保持最终位置,这种动画通过 @keyframes 定义不仅简单,而且高效。

代码示例

.box {
    width: 50px;
    height: 50px;
    background-color: red;
    position: absolute;
    top: 0;
    left: 0;
    animation: move 2s forwards;
}

@keyframes move {
    100% {
        top: 100vh; /* 页面底部 */
        left: 100vw; /* 页面右侧 */
        transform: translate(-100%, -100%); /* 确保元素完全位于右下角 */
    }
}

适用场景

  • 平滑移动:例如页面中的浮动按钮、加载动画等。
  • 渐变效果:例如背景颜色渐变、透明度渐变等。
  • 小型动画:例如按钮点击的视觉反馈、小图标的动效等。

总结来说,使用 animation@keyframes 来定义动画的方式不仅简洁,而且性能出色,适合大多数需要实现平滑、复杂动画的场景。