CSS入门笔记5(CSS动画,浏览器渲染)

457 阅读9分钟

CSS动画

大爱雷姆

前言

本文主要记录学习css动画的过程,主要讲浏览器渲染原理,translate平移,transition过渡,animation动画,最后还有个小实践-跳动的💗,本文源码都有的。--资料来源饥人谷


i.动画是什么呢?

定义:

动画是一种通过定时拍摄一系列多个静止的固态图像(帧)以一定频率连续变化、运动(播放)的速度(如每秒16张)而导致肉眼的视觉残象产生的错觉——而误以为图画或物体(画面)活动的作品及其影片技术。--来自维基百科


ii.怎么写出动画效果呢?

查看动画渲染重画过程可以通过F12(或者想要查看的位置鼠标右键检查)进入开发者工具,在任意地方按esc,可以弹出一个控制台,点击控制台旁边的三个竖点(more tools),选择Rendring,勾选Paint Flashing,屏幕不断出现绿色就是浏览器在不断渲染。

  • 第一种方式:用left做动画(会经过浏览器全部步骤,浏览器渲染会介绍)

具体代码可以查看js.jirengu.com/kejop/1/edi…

paint

可以看到方框内一直都是绿色,说明浏览器一直在渲染,repaint不断地重复画删画删的操作。--》加重了性能负担

  • 第二种方式:用transform做动画* (只经过最后composite,浏览器渲染会说到)

具体代码可以查看js.jirengu.com/dukek/1/edi…

again

可以看到只有开始和结束时是绿的,说明浏览器并没有repaint--》两相对比说明比用left性能更👍。


iii.和动画息息相关的是浏览器的渲染

那就来了解一下浏览器的渲染吧。

参考自google团队,详细了解可以点击下面文字(查看具体链接地址可以用开发者工具查看)

1) 浏览器渲染过程

步骤:

  1. 根据HTML构建HTML树(DOM)

  2. 根据CSS构建CSS树(CSSOM)

  3. 将两颗树合并成一颗渲染树(render tree)

  4. Layout布局(文档流、盒模型、计算大小和位置)--》"素描"

  5. Paint绘制(把边框颜色、文字颜色、阴影等画出来)--》"填色"

  6. Compose合成(根据层叠关系展示画面)--》"所有层拍平变成一层东西显示屏幕上"

三棵树有个图

tree

相同节点和起来就是渲染树(render tree)

2)怎么更新样式呢?

一般用JS来跟新样式

比如div.styel.background = 'red'

div.style.display = 'none'

div.classList.add('red') *

div.remove()直接删掉节点

3)这些方式有三种不同的渲染方式*

  1. JS / CSS > 样式 > 布局 > 绘制 > 合成

1

如果修改了元素的“layout”属性,也就是改变了元素的几何属性(例如宽度、高度、左侧或顶部位置等),那么浏览器将必须检查所有其他元素,然后“自动重排”页面。任何受影响的部分都需要重新绘制,而且最终绘制的元素需进行合成。 算style,可能还要走Layout,Paint,Conposite三步合成

  1. JS / CSS > 样式 > 绘制 > 合成

2

如果修改了“paint only”属性(例如背景图片、文字颜色或阴影等),即不会影响页面布局的属性,则浏览器会跳过布局,但仍将执行绘制。

  1. JS / CSS > 样式 > 合成

3

如果您更改一个既不要布局也不要绘制的属性,比如transform,则浏览器将跳到只执行合成。

4)三种更新方式

需要用到开发者工具上面所说renderng-paint flash

  • 第一种,全走

div.remove()会触发当前消失,其他元素relayout

具体代码js.jirengu.com/fewij/1/edi…

效果如下

remove1

可以看到三个方框删掉第一个空白框框后,三个框框原本位置都绿了--》证明浏览器经过了布局,绘制和合成

  • 第二种,跳过layout

改变背景颜色,直接repaint + composite

具体代码js.jirengu.com/sovoq/1/edi…

可以看到效果如下

跳过layout

可以看到第一个方框改变颜色为红时变绿了其他没有变色--》跳过了layout,直接paint和composite

  • 第三种,跳过layout和paint

改变transform,直接composite

具体代码js.jirengu.com/pabegi/1/ed…

效果如下

conposite

可以看到只有开始和结束被绘制,中间没有被repaint(重新绘制)--》直接composite

5)每个属性触发哪个流程推荐网站

要想知道哪个属性触发哪个流程除了自己试一遍别无他法,有个网站把所有属性都试过了

推荐看网站csstriggers.com/

可以告诉你每一种属性到底触发的什么流程,相同属性不同浏览器可能触发的流程不同。


iv.CSS动画优化

推荐去看google的文章里面详细讲了每个步骤的优化,太长不想看可以看TL;DR(太长不想读)。


v.transform(变形)全解

推荐看transform MDN,他会把每一个属性都给你一个列子动画,并且告诉你怎么用。

transform有四个常用的功能

  • translate-位移
  • scale-缩放
  • rotate-旋转
  • skew-倾斜

一般都需要配合transition过渡

inline元素不支持transform,需要先变成block

1. translate-移动

常用写法

translate( <length-percentage> , <length-percentage>? )
translateX( <length-percentage> )在X轴上移动,左右
translateY( <length-percentage> )在Y轴上移动,上下
translateZ( <length>)且父容器perspective(透视图原点在什么位置),在Z轴上移动,默认垂直于屏幕方向,必须要告诉视点(xyz交点)
translate3d(x,y,z)

具体代码js.jirengu.com/qiwib/1/edi…

translate(-50%,-50%)可以做绝对定位元素的居中

具体代码js.jirengu.com/huceg/1/edi…

2. scale-缩放

常用写法

scale( <number> , <number>? )
scaleX( <number> )
scaleY( <number> )

代码演示

<head>
...
  <style>
    #demo{
    width: 50px;
    height: 50px;
    border: 1px solid red;
    margin: 50px;
    transition: all 1s;
    /*添加动画,用1s动画*/
  }
  
  #demo:hover{
    transform: scale(1.5);
    /*变大为原来的1.5倍*/
  }
  </style>
</head>

<body>
  <div class="wrapper">
    <div id="demo"></div>
  </div>
</body>

这是有放大原来1.5倍

具体代码js.jirengu.com/waqot/1/edi…

效果如下

scale1.5

  #demo:hover{
    transform: scaleX(1.5);/*变胖1.5倍*/
    /* transform: scaleY(1.5);变高1.5倍*/
     /*transform: scale(1.5, 0.5); */
       /*缩写,变胖1.5,变高0.5*/
  }

同样也支持X,Y轴,变胖,变高。但是它的border也会相应的变形,容易出现模糊,所以一般不用scale

        X: X         Y: Y         XY: XY

3. rotate-旋转

语法格式

<rotate()> = rotate( [ <angle> | <zero> ] )
<rotate3d()> = rotate3d( <number> , <number> , <number> , [ <angle> | <zero> ] )/*太复杂了*/
<rotateX()> = rotateX( [ <angle> | <zero> ] )/*围绕X轴转动*/
<rotateY()> = rotateY( [ <angle> | <zero> ] )/*围绕Y轴转动*/
<rotateZ()> = rotateZ( [ <angle> | <zero> ] )/*围绕Z轴转动,默认就是垂直与屏幕的轴*/

代码

<head>
...
  <style>
    #demo {
      width: 50px;
      height: 70px;
      border: 1px solid red;
      margin: 50px;
      transition: all 1s;
    }
    #demo:hover {
      transform: rotate(45deg)
      /* 默认以垂直于屏幕轴转动45度   就相当于 transform: rotateZ(45deg);  */
      /*  transform: rotateX(45deg); 围绕X轴转动45度*/
      /*   transform: rotateY(45deg);围绕Y轴转动45度 */
      /*    transform: rotate3d(1,1,1,45deg);3d  */
    }
  </style>
</head>

<body>
  <div class="wrapper">
    <div id="demo"></div>
  </div>
</body>

具体代码js.jirengu.com/cicav/1/edi…

效果图如下

    X轴转动: X轴转动45度     Y轴转动: Y轴转动45度     Z轴转动 Z轴转动45度

一般用于做360度旋转制作loading

4. skew-倾斜

语法格式

<skew()> = skew( [ <angle> | <zero> ] , [ <angle> | <zero> ]? )
<skewX()> = skewX( [ <angle> | <zero> ] )
<skewY()> = skewY( [ <angle> | <zero> ] )

具体代码js.jirengu.com/sezom/1/edi…

效果 X轴倾斜15度: X轴倾斜15度                Y轴倾斜15度: Y轴倾斜15度

transform多重效果

可以组合使用,空格隔开 例如:

#demo:hover{
   transform: scale(1.5) rotate(45deg); 
}

具体代码js.jirengu.com/yevux/1/edi…

效果是这样的:

放大1.5倍,并旋转45度: 组合


vi.transition过渡

依然推荐去看transition MDN

作用

transition作用是添加中间帧(告诉开头和结尾怎么样,中间自动补齐)

可以用代码和效果图来说明它的作用

<head>
  ...
  <style>
   #demo{
    width: 50px;
    height: 50px;
    border: 1px solid red;
    transition: width 1s;
    /*如果宽度变化,就添加1s的中间动画*/
  }
  
  #demo:hover{
    width: 100px;
  }
  </style>
</head>
<body>
  <div id="demo"></div>
</body>

具体代码:js.jirengu.com/zunal/1/edi…

宽高开始,当hover时宽变为100px,transition补中间过程 作用

语法

  • transition: 属性名 时长 过渡方式 延迟(过多久开始运动)

transition: left 200ms linear 1s

  • 可以用逗号分隔开两个不同属性

transition: left 200ms, top 400ms

  • 可以用all代表所有的属性,上面写transform就用的all

transition: all 200ms

  • 过渡方式有: linear(匀速线性) | ease | ease-in(淡入) | ease-out(淡出) | ease-in-out(缓入) | cubic-bezier | steep-start | step-end | steeps

过渡方式具体含义看MDN要靠数学知识

注意

不是所有的属性都能过渡

display: none;=>block没法过度(从看不见到看的间没法过渡)可以用opacity: 1;=>0(透明度从1到0看不见,但位置还占着的)

如果想要从看不见到看得见一搬用visibility: hidden;=>visible

background颜色可以过渡,是16进制的

过渡必须要有起始

一般只有一次动画或者两次,比如hover状态和非hover状态的过渡。

如果除了起始还想要在中间有变化呢,中间该怎么过渡?

有两种方法:

  • 一种是使用两次transform

具体代码js.jirengu.com/lejut/2/edi…

效果图

两次transition

  • 还有一种就是animation动画

vii.animation动画

推荐阅读animation MDN

使用animation:

  • 声明关键帧
  • 添加动画
#demo.start{
  animation: xxx 1.5s;
  /*js的点击事件后开始xxx,总时间1.5s,要想停在最后一帧,可以加上forwards*/
}

@keyframes xxx {
  0% {
    transform: none;
  }
  60%{
    transform: translateX(200px);
  }
  100%{
    transform: translateX(200px) translateY(100px);
  }
}
/*给了三个关键帧,分别是0%*,60%和100%,0-60%向由移动200px,60-100%向下移动100px/   

具体的代码js.jirengu.com/yojah/1/edi…

效果

animation

可以添加任意数量想添加的中间帧,它会按照你给的线路进行移动

@keyframes完整语法

标准写法

建议搜索keyframes MDN很详细

  • 一种写法是from to
  • 另一种写法是百分数

from to就智能from和to

@keyframes slidein {
  from {
    transform: translateX(0%);
  }

  to {
    transform: translateX(100%);
  }
}

百分数更广泛

@keyframes identifier {
  0% { top: 0; left: 0; }
  30% { top: 50px; }
  68%, 72% { left: 50px; }
  100% { top: 100px; left: 100%; }
}

缩写语法

animation: 时长 | 过渡方式 | 延迟 | 次数 | 方向 | 填充模式 | 是否暂停 | 动画名 ;

时长: 写运动的时间。
过渡方式: 和transition取值一样,如ease。
次数: 执行的次数,也可以infinite(无限次)
方向: reverse(反方向运动),alternate(交替的,适合加载动画,过去又回来),alternate-reverse(反方向交替)。
填充模式: none | forwards(定格) | backwards(一开始就把动画第一帧复制到原始的位置) | both
是否暂停: paused | running

viii.跳动的💗

用animation做

具体代码js.jirengu.com/lesam/1/edi…

效果

herat 你懂得

--continue



心动不如行动,学习前端从入门到入土,我正在路上。您的每一次观看,就是对我学习路上最大的鼓励,一起努力吧!

欢迎留下您宝贵的意见。