【CSS全解】CSS动画

344 阅读4分钟

动画

  • 定义:由许多静止的画面(帧),以一定的速度(如每秒30张)连续播放时,肉眼因视觉残象产生错觉,而误以为是活动的画面
  • 概念
    • 帧:每个静止的画面都叫做帧。
    • 播放速度:每秒24帧(影视)或者每秒30帧(游戏)。

一个简易动画

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            width: 100px;
            height: 100px;
            border: 1px solid red;
            position: relative;
            left: 0;
            top: 0;
        }
    </style>
</head>
<body>
    <div id="demo"></div>
    <script>
        let n = 1;
        // 间隔多少秒,执行行数
        let id = setInterval(()=>{
            // 当n小于等于200时,才会执行
            if(n <= 200) {
                // console.log(n)
                demo.style.left = `${n}px`;
                n++
            }else{
                clearInterval(id);
            }
        },10) // 每50毫秒执行一次
    </script>
</body>
</html>
  • 原理
    • 每过一段时间(用setInterval)
    • 将div移动一小段距离(元素.style.left)
    • 知道移动到目标地点(用if来判断是否移动到正确位置)

浏览器的渲染原理

浏览器的渲染

  • 步骤
    1. 根据HTML构建HTML树(DOM)
    2. 根据CSS构建CSS树(CSSOM)
    3. 将两棵树合并成一颗渲染树(render tree)
    4. Layout布局(文档流、 盒模型、计算大小和位置)
    5. Paint绘制(把边框颜色、文字颜色、阴影等画出来)
    6. Compose合成(根据层叠关系展示画面)
  • Chrome的Paint flashing功能
    • 控制台→Esc键→Rendering→Paint flashing
    • 绿色表示正在重新渲染(repaint)。
    • CSS渲染过程依次包含布局、绘制、合成, 其中布局和绘制可能被省略。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            width: 100px;
            height: 100px;
            border: 1px red solid;
            /* 中间是1s */
            transition: all 1s linear; 
        }

        #demo.end {
            transform: translateX(300px);
        }
    </style>
</head>
<body>
    <div id="demo"></div>
    <script>
        setTimeout(()=>{
            // 为demo添加一个end的类名。
            demo.classList.add('end')
        },3000)
    </script>
</body>
</html>
  • 使用transform来实现动画,要比left实现动画所渲染的要少,对资源占用更少,因此一般不用left来做动画。
  • 一般用JS来更新样式
    • div.style.background= 'red';不推荐
    • div.style.display = 'none';
    • div.classList. add('red');推荐
    • div.remove();直接删掉节点
  • 加样式不如加类。

三种样式的更新方式

  1. JS/CSS→样式→布局→绘制→合成 Pasted image 20220621110641.png
    • div.remove(),会触发当前元素,其他元素relayout。
    • 改变了布局位置。
  2. JS/CSS→样式→绘制→合成 Pasted image 20220621110708.png
  3. JS/CSS→样式→合成 Pasted image 20220621110742.png
    • 改变transform,只需要composite。
    • 必须要全屏查看效果,在iframe里查看会出问题。

如何了解某个属性触发什么动画流程

CSS动画优化

  • 作用:旋转、缩放、倾斜或平移给定元素。
  • Google写的CSS动画文章
  • JS优化:使用requestAnimationFrame替代setTimeout或setInterval。
  • CSS优化:使用will-change或translate替代left等。

transfrom属性

  • MDN transform文档
  • 常用功能
    • translate:位移
    • scale:缩放
    • rotate:旋转
    • skew:倾斜
  • 注意
    • 一般都需要配合transition过度。
    • inline元素不支持transform,需要先变成block。

transform: translate()

  • 常用属性值
    • translateX(<length-percentage>):X轴方向(水平)上移动。
    • translateY(<length-percentage>):Y轴方向(垂直)上移动。
    • translateZ(<length-percentage>):Z轴方向上移动,需要配合父元素的perspective属性,改变视点。
    • translate(<length-percentage>, <length-percentage>):(X轴方向, Y轴方向)。
    • translate3d(<length-percentage>, <length-percentage>, <length-percentage>):(X轴方向, Y轴方向, Z轴方向)。
  • 注意
    • 学会看懂MDN的语法实例。
    • translate(-50%, -50%)可以做到绝对定位元素的居中(不支持IE)。
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      
    • 百分数取值,为自身长宽的百分之多少。如50%为自身长宽的50%。

transform: scale()

  • 常用属性值
    • scaleX(<number>):X轴方向上放大(缩小)多少倍。
    • scaleY(<number>):Y轴方向上放大(缩小)多少倍。
    • scale(<number>):整体放大(缩小)多少倍。
    • scale(<number>, <number>):(X轴方向,Y轴方向)放大(缩小)多少倍。
  • 注意
    • 一般不用scale,因为会拉伸元素,导致变形、出现模糊。

transform: rotate()

  • 常用属性值
    • rotate(<angle>):沿着Z轴旋转。
    • rotateZ(<angle>):沿着Z轴旋转。
    • rotateX(<angle>):沿着X轴旋转。
    • rotateY(<angle>):沿着Y轴旋转。
    • [rotate3d()]developer.mozilla.org/zh-CN/docs/…
  • 注意
    • <angle>的单位是deg,degree的缩写。
    • 默认为顺时针旋转。
    • 一般用360度旋转制作loading。

transform: skew()

  • 常用属性值
    • skewX(<angle>):沿着X轴方向旋转拉伸。
    • skewY(<angle>):沿着Y轴方向旋转拉伸。

transform多重效果

  • 组合使用:transform: scale(0.5) translate(100%, 100%);
  • 取消所有:transform: none;

transition属性

  • 作用:补充中间帧。
  • 语法:transition: 属性名 时长 过度方式 延迟;
    • 例:transition: left 200ms linear 400ms;
  • 可用逗号分隔两个不同属性。
    • 例:transition: let 200ms, top 400ms;
  • 可以用all代表所有属性。
    • 例:transition: all 200ms;
  • 过度方式:linear(线性变化)、ease(非线性变化)、ease-in、ease-out、ease-in-out、cubic-bezier、step-start、step-end、steps
  • 注意
    • 并不是所有属性都能使用transition属性。
    • display: nonedisplay: block没法过渡,一般改成visibility: hidden;visibility: visible;
    • color、background-color、opacity也可以transition。
    • 基本上只要变化过程有规律的都可以transition。
    • 可以用事件监听和两个transform来实现连续的两次transition。

animation

obj.start {
	/* 1.5s为动画执行的总时间 */
	animation: slidein 1.5s;
}

@keyframes slidein {
  0% {
	transform: translateX(0%); 
  }
  100% {
	transform: translateX(100%);
  }
}
  • animation语法:animation: 时长 过度方式 延迟 次数 方向 填充模式 是否暂停 动画名;
    • 时长:1s或者1000ms
    • 过渡方式:跟transition取值一样,如linear、ease
    • 次数:3或者2.4或者infinite
    • 方向:reverse | alternate| alternate-reverse
    • 填充模式:none | forwards | backwards | both
    • 是否暂停:paused | running
    • 以上所有属性都有对应的单独属性
  • @keyframes:关键帧,另一种写法是from to格式。
  • keyframes MDN
  • 如何使动画停在最后一帧?
    • 为animation添加一个forwards,如animation: slidein 1.5s forwards;

拓展

opacity、display、visibility的区别

  • opacity: 0;只是改变元素的透明度,但还会占用布局空间。会一边改变透明度,一边执行过渡动画。
  • visibility: hidden;只是改变元素的透明度,但还会占用布局空间。会先执行动画,再改变透明度。
  • display: none;会改变元素的透明度,但不会占用空间。