CSS 知识总结

469 阅读9分钟

CSS 动画

引入

1.动画的原理

  • 静止画面称作帧
  • 将这些这帧以一定的速度进行播放,我们的视觉会产生残影形成动画效果。一般影视播放需要:1s/24帧,游戏需要1s/60帧。

2.浏览器的渲染过程

  1. 根据HTML创建HTML树(DOM)
  2. 根据CSS创建CSS树(CSSOM)
  3. 合并两棵树创建RENDER TRee(渲染树)
  4. LAYOUT 布局<文档流、盒模型、计算大小和位置以及文字的颜色>
  5. PAINT 绘制<把边框的颜色、文字颜色、以及阴影画出来>
  6. COMPOSE 合成根据层叠关系,进行展示画面

以下是三棵树

3. 如何更新样式

一般我们用JS更新样式

  • div.remove() 对应下图的第一种方式,全走的方式,会触发当前消失,其他元素relayout。
  • div.style.background='red' 改变背景颜色,直接跳过repaint+composite环节
  • div.style.dispaly='none'
  • div.classList.add('add')

不同的属性选择的渲染方式也不同,可以查看相关文档进行判断:点击查看更多

更新样式的三种方式

4.css动画优化方式

  • JS优化: 使用repuestAnimationFrame代替setTimeout或者setlnterval
  • css 优化: 使用will-change 或者translate

点击查看更多

5.实现css 动画的属性

5.1 transform

transform属性允许你旋转,缩放,倾斜或平移给定元素。

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

使用此属性的情况下,必须要配合 transition 过渡 行内元素(inline)不支持变形,需要先把它变成块元素(block)。

属性的演示 1.translate

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            width: 100px;
            height: 200px;
            border: 1px solid red;
            margin: 50px;
        }
        
        #demo:hover {
            transform: translateX(50px);
            /* 向X轴移动50像素 */
            transform: translateY(-50px);
            /* 向Y轴移动-50像素 */
            transform: translateZ(-200px);
            /* 向Z轴移动-200像素 */
        }
        
        .wrapper {
            perspective: 1000px;
            /* 视觉大小为1000像素 */
            /* perspective指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。 z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定 */
            border: 1px solid black;
        }
    </style>
</head>

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

</body>

</html>

演示

2.scale 缩放

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            height: 300px;
            width: 300px;
            border: 1px solid palevioletred;
            margin: 50px;
        }
        
        #demo:hover {
            transform: scaleX(1.5);
            /* X轴缩放1.5倍 */
            transform: scaleY(0.5);
            /* Y轴缩放0.5倍 */
            /* transform: scale(1.5, 0.5); */
            /* 另一种写法 */
        }
        
        .wrapper {
            perspective: 1000px;
            border: 5px solid blueviolet;
        }
    </style>
</head>

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

</html>

演示

3.rotate 旋转 一般用于360度旋转制作,loading。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            height: 300px;
            width: 300px;
            border: 1px solid palevioletred;
            margin: 150px;
        }
        
        #demo:hover {
            transform: rotateX(45deg);
            /* X轴旋转45度 */
            transform: rotateY(90deg);
            /* Y轴旋转90度 */
            transform: rotateZ(30deg);
            /* Z轴旋转30度 */
        }
        
        .wrapper {
            perspective: 1000px;
            border: 5px solid blueviolet;
        }
    </style>
</head>

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

</html>

4.skew 倾斜

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #demo {
            height: 300px;
            width: 300px;
            border: 1px solid palevioletred;
            margin: 150px;
        }
        
        #demo:hover {
            /* transform: skewX(45deg); */
            /* X轴倾斜45度 */
            transform: skewY(45deg);
            /* Y轴倾斜90度 */
        }
        
        .wrapper {
            perspective: 1000px;
            border: 5px solid blueviolet;
        }
    </style>
</head>

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

</html>

第一个小红心

预览地址

代码显示

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            box-sizing: border-box;
        }
        
        #heart {
            display: inline-block;
            margin: 100px;
            position: relative;
            transition: all 1s;
            /* 过渡时间为1s */
        }
        
        #heart:hover {
            transform: scale(1.2);
            /* 缩放的比例1.2倍 */
        }
        
        #heart>.left {
            background: red;
            width: 50px;
            height: 50px;
            position: absolute;
            transform: rotate(45deg) translateX(31px);
            /* 旋转45度 X轴方向移动31像素 */
            bottom: 50px;
            left: -50px;
            border-radius: 50% 0 0 50%;
            /* 将正方形变成圆形 */
        }
        
        #heart>.right {
            background: red;
            width: 50px;
            height: 50px;
            border-radius: 50%;
            position: absolute;
            transform: rotate(45deg) translateY(31px);
            bottom: 50px;
            right: -50px;
            border-radius: 50% 50% 0 0;
        }
        
        #heart>.bottom {
            background: red;
            width: 50px;
            height: 50px;
            transform: rotate(45deg);
        }
    </style>
</head>

<body>
    <div id="heart">
        <div class="left"></div>
        <div class="right"></div>
        <div class="bottom"></div>
    </div>

</body>

</html>

5.2 transition

transition属性可以被指定为一个或多个 CSS 属性的过渡效果,多个属性之间用逗号进行分隔。 它的作用是补充中间帧。

5.2.1用法

  • transition:属性名 时长 过渡的方式 延迟的时间 例如:
transition :left  200ms linear;
向左过渡 200ms时间
  • 可以用逗号分隔两个不同属性
transition: left 200ms,top 200ms;
向左和向上做过渡动画 时间200ms

  • all 可以代表所有属性
  • 过渡的方式:linear ease ease-in 具体请查阅相关资料

注意

不是所有的属性都可以过渡

  • display:none 装换成 block 无法进行过渡

      一般用visibility:hidden 转换成:visible

5.2.2 过渡必须有始有终

一般只有一次动画,或者是两次。

例如:hover 和非 hover状态的一个过渡 如果出现中间点怎么办呢?

解决的方式:

  • 使用两次 transform 从a --- b 再从b --- c 用setTimeout 或者监听transitionend 事件的方式
#demo{
  width: 100px;
  height: 100px;
  border: 1px solid red;
  margin: 50px;
  transition: transform 1s linear;
}

#demo.b{
  transform: translateX(200px);
}
#demo.c{
  transform: translateX(200px) translateY(100px);
}

button.onclick = ()=>{
  
  demo.classList.add('b')
  setTimeout(()=>{
    demo.classList.remove('b')
    demo.classList.add('c')
  },1000)
}

预览

  • 用animation 的方式 声明关键帧, 添加动画。
#demo{
  width: 100px;
  height: 100px;
  border: 1px solid red;
  margin: 50px;
  transition: transform 1s linear;
}

#demo.start{
  animation: xxx 1.5s;
}


@keyframes xxx {
  0% {
    transform: none;
  }
  66.66%{
    transform: translateX(200px);
  }
  100%{
    transform: translateX(200px) translateY(100px);
  }
}
button.onclick = ()=>{
  
  demo.classList.add('start')
}

预览

但是如果想得到动画停到最后一帧的情况呢? 在原有的基础上使用代码所示的方式即可实现。

#demo{
  width: 100px;
  height: 100px;
  border: 1px solid red;
  margin: 50px;
}

#demo.start{
  animation: xxx 1.5s forwards;
}


@keyframes xxx {
  0% {
    transform: none;
  }
  66.66%{
    transform: translateX(200px);
  }
  100%{
    transform: translateX(200px) translateY(100px);
  }
}

预览

6.animation的具体用法

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

  • 时长:1s or 1000ms
  • 过渡方式: 与transition相似 有:linear等
  • 次数:3或者2.4 或者infinite(无穷的)
  • 方向:reverse alternate alternate-reverse(交替反向)
  • 填充方式:none forwards backwards both
  • 是否暂停:paused running

第二个红心

预览

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>red heart</title>
    <style>
        * {
            box-sizing: border-box;
        }
        
        #box {
            display: inline-block;
            margin: 100px;
            position: relative;
            /* background-color: red; */
            /* border: 1px solid palegreen; */
            animation: .3s heart infinite alternate-reverse;
        }
        
        #box:hover {
            transform: scale(1.2);
        }
        
        #box>.left {
            width: 100px;
            height: 100px;
            /* border: palegreen 1px solid; */
            background: purple;
            transform: rotate(45deg) translateX(62px);
            /* 旋转45度,向X轴移动31像素 */
            position: absolute;
            bottom: 100px;
            left: -100px;
            border-radius: 50% 0 0 50%;
        }
        
        #box>.right {
            width: 100px;
            height: 100px;
            /* border: palegreen 1px solid; */
            background: purple;
            transform: rotate(45deg) translateY(62px);
            /* 旋转45度,向Y轴移动31像素 */
            position: absolute;
            bottom: 100px;
            right: -100px;
            border-radius: 50% 50% 0 0;
        }
        
        #box .bottom {
            background: purple;
            width: 100px;
            height: 100px;
            transform: rotate(45deg);
        }
        
        #name {
            position: absolute;
            /* top: 50px; */
            right: 230px;
            bottom: 60px;
            color: royalblue;
        }
        
        #box1 {
            display: inline-block;
            margin: 100px;
            position: relative;
            /* background-color: red; */
            /* border: 1px solid palegreen; */
            /* transition: all 1s; */
            animation: 1s heart infinite alternate-reverse;
        }
        
        @keyframes heart {
            0% {
                transform: scale(1);
            }
            100% {
                transform: scale(2);
            }
        }
        /* #box1:hover {
            transform: scale(1.2);
        }
         */
        
        #box1>.left1 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateX(31px);
            /* 旋转45度,向X轴移动31像素 */
            position: absolute;
            bottom: 50px;
            left: -50px;
            border-radius: 50% 0 0 50%;
        }
        
        #box1>.right1 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateY(31px);
            /* 旋转45度,向Y轴移动31像素 */
            position: absolute;
            bottom: 50px;
            right: -50px;
            border-radius: 50% 50% 0 0;
        }
        
        #box1 .bottom1 {
            background: red;
            width: 50px;
            height: 50px;
            transform: rotate(45deg);
        }
        
        #name1 {
            position: absolute;
            /* top: 50px; */
            right: 230px;
            bottom: 60px;
            color: royalblue;
        }
        
        #box2 {
            display: inline-block;
            margin: 100px;
            position: relative;
            /* background-color: red; */
            /* border: 1px solid palegreen; */
            transition: all 1s;
        }
        
        #box2:hover {
            transform: scale(1.2);
        }
        
        #box2>.left2 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateX(31px);
            /* 旋转45度,向X轴移动31像素 */
            position: absolute;
            bottom: 50px;
            left: -50px;
            border-radius: 50% 0 0 50%;
        }
        
        #box2>.right2 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateY(31px);
            /* 旋转45度,向Y轴移动31像素 */
            position: absolute;
            bottom: 50px;
            right: -50px;
            border-radius: 50% 50% 0 0;
        }
        
        #box2 .bottom2 {
            background: red;
            width: 50px;
            height: 50px;
            transform: rotate(45deg);
        }
        
        #box3 {
            display: inline-block;
            margin: 100px;
            position: relative;
            /* background-color: red; */
            /* border: 1px solid palegreen; */
            transition: all 1s;
        }
        
        #box3:hover {
            transform: scale(1.2);
        }
        
        #box3>.left3 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateX(31px);
            /* 旋转45度,向X轴移动31像素 */
            position: absolute;
            bottom: 50px;
            left: -50px;
            border-radius: 50% 0 0 50%;
        }
        
        #box3>.right3 {
            width: 50px;
            height: 50px;
            /* border: palegreen 1px solid; */
            background: red;
            transform: rotate(45deg) translateY(31px);
            /* 旋转45度,向Y轴移动31像素 */
            position: absolute;
            bottom: 50px;
            right: -50px;
            border-radius: 50% 50% 0 0;
        }
        
        #box3 .bottom3 {
            background: red;
            width: 50px;
            height: 50px;
            transform: rotate(45deg);
        }
    </style>
</head>

<body>
    <div id="box">
        <div class="left"></div>
        <div class="right"></div>
        <div class="bottom">
            欧力给!
        </div>



    </div>
    <!-- <span id="name">曹坤</span> -->
    <div id="box1">
        <div class="left1"></div>
        <div class="right1"></div>
        <div class="bottom1">

        </div>



    </div>
    <!-- <span id="name1">曹坤</span> -->
    <div id="box2">
        <div class="left2"></div>
        <div class="right2"></div>
        <div class="bottom2">

        </div>



    </div>

</body>

</html>