CSS 动画

234 阅读4分钟

本文主要整理了一下 CSS 相关动画的笔记,基础概念,性能优化,以及个人认为使用频率较高的插入/移除内容过渡效果的实现。

CSS 动画实现可以分为两种: transition 以及 animation。两者的区别是:transition 是通过改变属性值触发的,animation 是直接通过添加相关值进行执行的。

The principal difference is that while transitions trigger implicitly when property values change, animations are explicitly executed when the animation properties are applied. — CSS Animations Level 1

Transition

CSS transitions provide a way to control animation speed when changing CSS properties. Instead of having property changes take effect immediately, you can cause the changes in a property to take place over a period of time. For example, if you change the color of an element from white to black, usually the change is instantaneous. With CSS transitions enabled, changes occur at time intervals that follow an acceleration curve, all of which can be customized.

触发机制: CSS 属性变化;控制属性变化的过程。

图片来源:developer.mozilla.org/en-US/docs/…

使用场景

设置过渡动画

  • transition-property 需要进行过渡处理的属性
  • transition-duration 过渡时间长度
  • transition-timing-function 过渡动画的时间曲线
  • transition-delay 过渡动画延迟开始的时间
  • transition: ; 缩写形式

对多个属性进行动画

/* 简写 */
.box {
  transtion: width 2s, height 2s, background-color 2s;
}

/* 自动重复 */
div {
  transition-property: opacity, left, top, height;
  transition-duration: 3s, 5s; 
  /* transition-duration: 3s, 5s, 3s, 5s; */
}

可以添加过渡动画的属性

  • 可以添加过渡动画的属性为有限集,会随着标准的变化而变化。
  • 尽量不要使用 auto 作为动画的始末状态
  • Animatable CSS properties

JS 事件 — 检测过渡动画的开始与结束

  • transitionrun — 在 transition-delay 前触发( Chrome 上偶尔会出现 transitionrun 与 transitionstart 几乎同时触发的情况)

  • transitionstart — 在 transition-delay后触发

  • transitionend — transition 结束时触发。在过渡完成前,如果过渡属性发生变化,或者元素的样式被设置为 display:none 时,不会触发

    Note: The transitionend event doesn't fire if the transition is aborted before the transition is completed because either the element is made display: none or the animating property's value is changed.

  • transitioncancel — transition 在 transitionruntransitionend 之间取消时触发

codepen.io/kongkx-the-…

Animation

CSS animations make it possible to animate transitions from one CSS style configuration to another. Animations consist of two components, a style describing the CSS animation and a set of keyframes that indicate the start and end states of the animation’s style, as well as possible intermediate waypoints.

css animation, 从一组样式到另一组样式。需要设置两个部分,一是动画的基本描述(与 transition 类似),二是“关键帧”的定义。 animation 属性设置时便触发。标准文档:

使用场景

相关参数列表

  • animation-name 通过 @keyframes 定义的关键帧样式描述
  • animation-duration
  • animation-timing-function
  • animation-delay 动画延迟开始的时间,不会影响到动画 iteration
  • animation-iteration-count 动画重复次数,可以设置为 infinite
  • animation-direction: normal, reverse(反向), alternate(往返), alternate-reverse(反向往返)
  • animation-fill-mode: 定义元素的开始与结束状态 none, forwards, backwards, both
    • forwards — 动画结束时,保留最后关键帧的样式
    • backwards — 与 animation-delay 相关,等待过程中应用动画的“初始帧”样式
  • animation-play-state: paused, running, inherit, initial, unset

JS 事件

  • animationstart
  • animationend
  • animationiteration
  • animationcancel

interface AnimationEvent {
  animationName,
  elapsedTime,
  pseudoElement
}

codepen.io/kongkx-the-…

备注

  • animation 产生的计算属性在 cascading 的过程中优先于元素的静态属性,次于 !important 设置的属性。可能造成的现象:动画结束后,:hover 的样式不生效
  • display 属性。当元素的 display 设置为 none 时,所有动画都会终止。当 display 属性从 none 设置为其他时,元素上的所有动画都会开始。
  • Working Draft : CSS Animations Level 1

性能优化

想要对 css 动画进行优化,先要了解页面像素渲染的流程。

网页像素渲染流程:

延伸阅读:

优先策略

  • 尽可能避免重排reflow,减少重绘repaint,尽可能使用 reComposite (transform) 来实现动画效果

注意

  • composite 可能会耗费更多的内存资源,以及电力资源

传闻

使用 translateZ 建立 compositing layer,触发 gpu 硬件加速。

.accelerated {
  -webkit-transform: translateZ(0);
  -moz-transform: translateZ(0);
  -ms-transform: translateZ(0);
  -o-transform: translateZ(0);
  transform: translateZ(0);

  -moz-transition: all 1s;
  -webkit-transition: all 1s;
  -o-transition: all 1s;
  transition: all 1s ;
}

延伸阅读:CSS GPU Animation: Doing It Right

内容过渡效果的实现

通过阅读整理 React Transition Group 以及 vue 的 进入/离开 & 列表过渡 的文档,我总结了一下页面元素进入/离开 以及 列表项目的插入与删除 的实现方式:

  • 元素的动画可以分两个阶段:进入阶段, 离开阶段

  • 在移除页面元素时,可能会存在过渡 state( 的源码),等待过渡动画结束后再更新 state ,真正删除dom

  • CSS 类名

    • React CSSTransition: v:classNames

      • 首次: v-appear, v-appear-active, v-appear-done
      • 进入: v-enter, v-enter-active, v-enter-done
      • 离开:v-exit, v-exit-active, v-exit-done
    • Vue transition: v:name

  • JS Hook

    • React : onEnter, onEntering, onEntered, onExit, onExiting, onExited
      • 通过 timeout 计时器来触发过渡终点
    • Vue : before-enter, enter, after-enter, enter-cancelled, before-leave, leave, after-leave, leave-cancelled
      • 监听 transitionend, animationend 来判断过渡终点,也可以显式地设置 duration

React Transition Group 的实现要点

  • state 设计

    this.state = {
      contextValue: { isMounting: true },
      handleExited,
      firstRender: true,  // 标记首次渲染
      children: Object, // key-value mapping
    }
    
  • static getDerivedStateFromProps使用 props.children 生成 state.children,并使用 state.children 进行渲染

  • 添加列表时,直接使用 <Transition> entering 的过渡效果

  • 删除列表项时,使用 <Transition>onExited 更新 state.children