精通 CSS 第 10 章 变换过渡与动画 学习笔记

Posted GoldenaArcher

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了精通 CSS 第 10 章 变换过渡与动画 学习笔记相关的知识,希望对你有一定的参考价值。

精通 CSS 第 10 章 变换、过渡与动画 学习笔记

这一章主要讲的还是让元素“动”起来的特性,主要内容在以下几章学习笔记中有讲到,这里可以算是一个系统性整合了:

都学过了,所以这一章的内容会很快的过一遍,顺便拾遗补漏。

概述

翻了一下书中讲的狗家的案例,是真的挺好看的:

google-story-book

点进去之后还能够看到狗家的各个产品,都是用这种三维的效果制作的,体感挺好。

二维变换

从技术角度来说,变换(transform) 改变的是元素所在的 坐标系统

一种看待变换的角度是把他们看成“畸变场”——任何落在元素渲染空间内的像素都会被畸变场必火,然后再将他们传输到页面上的新位置,或改变大小。元素本身还在页面上原来的位置,但它们畸变之后的“影像”已经变换了。

为元素应用变化后,会为元素最初所在的位置创建所谓的 局部坐标系统。页面上任会保留原本的像素空间位置,但是畸变后的局部坐标系不会影响原本的像素空间。

这种说法也能够解释为什么二维转换不会影响到其他元素,毕竟元素本身的位置没有产生任何的改变,受到影响的是元素的“投影”。

例如说下面这个例子:

distorted-coordinators

畸变后元素的局部过标系统如上图所示,并不会影响到原本的的位置坐标系:

orig-coordinators

这部分源码为:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Document</title>
    <style>
      body {
        padding: 100px;
      }
      .box {
        width: 100px;
        height: 100px;
        margin-top: 20px;
        top: 200px;
        left: 200px;
        background-color: #eee;
        outline: 1px solid;
        transform: rotate(45deg);
      }
    </style>
  </head>
  <body>
    abcdefg
    <div class="box"></div>
    hijklmn
  </body>
</html>

变换原点

transform-origin属性,默认情况下,变换是以元素边框盒子的中心作为原点。

变换原点会对元素的旋转产生不同的效果,如将原点从中心修改成左上角,再进行 45° 旋转所产生的效果:

origin-center

left-top

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Simple transform</title>
    <style>
      body {
        padding: 50px 200px;
      }
      .box {
        width: 100px;
        height: 100px;
        background-color: #eee;
        outline: 1px solid;
        /* 注视下面这行代码查看不同效果 */
        transform-origin: 0 0;
        transform: rotate(45deg); /* 1 */
      }
    </style>
  </head>
  <body>
    origin left-top:
    <div class="box"></div>
  </body>
</html>

平移

translate属性,使得元素沿着 x 轴 和/或 y 轴进行移动。

多重变换

案例中是结合了 transform 和 translate,效果图如下:

transform+translate

其实现方法是利用伪元素 before 添加 § 3,再用绝对定位将伪元素中的内容放到 list-style 占用的空间上。before 中的数字是使用了另一种 CSS 的特性 counter 去实现的计数效果。

最初的效果如下:

initial-stage

设置了绝对定位之后,作为 自定义的列表样式属性 的定位如下:

position-absolute

为了能够更清楚地看到样式,我暂时将 li元素 中的内容注释掉了。

实现平移后的效果如下:

after-translate

这里已经设置了 transform-origin: 100% 100%;,即等同于 transform-origin: right bottom;,将右下角作为旋转中心后,实现旋转 -90° 就完成了最终的效果。

完整实现代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Using transform-origin to rotate text</title>

    <style>
      body {
        font-family: Baskerville, Times, Times New Roman, serif;
        font-size: 1.25em;
        padding: 3em;
      }
      h1 {
        font-weight: 400;
      }
      .rules {
        counter-reset: rulecount 2;
        list-style: none;
        padding: 0;
        margin: 0;
      }
      .rules li {
        line-height: 1.5;
        min-height: 1.75em;
        counter-increment: rulecount;
        max-width: 35em;
        border-left: 1.5em solid #777;
        padding-left: 0.5em;
        position: relative;
        margin-bottom: 0.5em;
      }
      .rules li:before {
        position: absolute;
        top: 0;
        left: 0;
        padding-right: 0.25em;
        display: block;
        color: #777;
        color: #fff;
        line-height: 1.5em;
        padding-left: 0.25em;
        content: "§ " counter(rulecount);
        transform: translate(-100%, -100%) rotate(-90deg);
        transform-origin: 100% 100%;
      }
    </style>
  </head>
  <body>
    <h1>Fight Club rules</h1>
    <ol class="rules" start="3">
      <li>If someone says ”stop”, goes limp or taps out, the fight is over.</li>

      <li>Only two guys to a fight.</li>

      <li>One fight at a time.</li>

      <li>No shirts, no shoes.</li>

      <li>Fights will go on as long as they have to.</li>

      <li>If this is your first night at FIGHT CLUB, you HAVE to fight.</li>
    </ol>
  </body>
</html>

平移与旋转的顺序是非常重要的,因为平移的是相对于元素的局部坐标系进行的操作。如果先旋转再进行位移,那么就需要重新计算位移的角度,否则会产生下面的结果:

coordinator-off

transform属性修改为 transform: rotate(-90deg) translate(80%, -120%); 还是能够产生一样的效果。

缩放和变形

scaleskew 两个属性。

scale,缩放理解起来比较简单,就是对元素产生放大和缩小的变化。

skew 我觉得比较好理解的代入方法是斜体,斜体是对字体倾斜,skew 是对元素倾斜。以上面多重变换的例子,简单的修改一下后会有这样的效果:

skew

修改过的 CSS 部分如下

.rules li {
  line-height: 2.5;
  min-height: 1.75em;
  counter-increment: rulecount;
  max-width: 35em;
  padding-left: 0.5em;
  position: relative;
  background-color: #e5212e;
  border-left: 1.5em solid #aa031c;
  transform: skewX(15deg);
}
.rules li:nth-child(even) {
  background-color: #aa031c;
  border-color: #6b0011;
  transform: skewX(-15deg);
}

只是对颜色的搭配进行了一点儿的修改,就有了深浅折叠的感觉,模拟出了 3D 的效果。

二维矩阵变换

本质上来说,旋转也好,位移也好,都是在一个平面上对元素进行操作,CSS 也提供了一个更加直观明了的属性去进行计算平面直角坐标系:矩阵matrix()

以数学的角度来说,它能够更加直观明了的表明想要操作的结果,如:

.some-content {
  transform: matrix(1.41, 1.41, -1.16, 1.66, 70.7, 70.7);
  /* 与下面的效果一样 */
  transform: rotate(45deg) translate(100px, 0) scale(2) skewX(10deg);
}

但是很明显,对于人来说,第二条 CSS 更加方便理解,能够直观的理解这条 CSS 想要实现的目的是什么。

变换与性能

使用 变换(transform) 只会影响到相关元素的直角坐标系,不需要浏览器去重新计算对整个页面造成的影响,因此相应的性能会高一些。

过渡

过渡是一种动画,可以从一个状态过渡到另一个状态,常见的有按钮的点击、菜单栏的展开、元素的切入等。

只需要指定想要的效果以及延续的时间,浏览器能够相对快速地对页面的变化进行重绘,并且会自动双向运行。如当元素处于 hover 状态时触发时会产生的过渡,不再 hover 状态时即会反向运行。

press-me

实现代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Button transition</title>

    <style>
      button {
        cursor: pointer;
        border: 0;
        padding: 0.5em 1em;
        color: #fff;
        border-radius: 0.25em;
        outline: none;
        font-size: 1em;
        background-color: #173b6d;
        background-image: linear-gradient(to bottom, #1a4a8e, #173b6d);
        box-shadow: 0 0.25em 0 rgba(23, 59, 109, 0.3), inset 0 1px 0 rgba(0, 0, 0, 0.3);
        transition: all 150ms ease-in;
      }
      button:active {
        box-shadow: 0 0 0 rgba(23, 59, 109, 0.3), inset 0 1px 0 rgba(0, 0, 0, 0.3);
        transform: translateY(0.25em);
      }
    </style>
  </head>
  <body>
    <button>Press me!</button>
  </body>
</html>

过渡计时函数

transition-timing-function属性,目前有 9 个值,比较值得注意的有以下几个:

  • ease,即默认值

    开始的时候稍慢些,迅速加快,最后快接近终值的时候再慢下来

  • ease-in

    开始慢,后来快

  • ease-out

    与 ease-in 相反

  • ease-in-out

    ease-in 和 ease-in-out 的结合,两头慢中间快

  • linear

    线性匀速

  • 三次贝塞尔函数

    cubic-bezier(p1, p2, p3, p4),需要提供 4 个点去定义三次贝塞尔函数

    上面的实现,包括 ease 的系列和 linear 底层都是依赖于三次贝塞尔函数实现的。如 ease 可以被重写为 cubic-bezier(0.25, 0.1, 0.25, 1.0),linear 的三次贝塞尔函数为 cubic-bezier(0.0, 0.0, 1.0, 1.0) 等。

    matrix 一样,都不是给普通人看和用的,如果有特殊需求应该是可以网上找到公式去套用的。

  • 步进函数(steps)

    steps 的原理和 翻书画 相似,以前看到过就是通过图像快速的闪现,使其在视网膜中停留的时间过短,人的大脑就会自动的产生联想,看起来就和动画效果相似。

    之前做的一个特效是奔跑的北极熊,使用的就是 steps 实现的:

    polar-bear

使用不同的正向和反向过渡

就是一个有持续的过度效果,但是通过覆写其他的属性,即刻取消过渡效果,依旧以 hover 为例:

.sample {
  transition: background-position 0s stpes(6);
}
.sample:hover {
  transition-duration: 0.6s;
}

上面的代码中,当鼠标悬浮时会有一个时间长为 0.6s 的过渡阶段,但是一旦鼠标不悬浮于元素上了,因为过度的时间只有 0s,所以反向过度看起来即刻就消失了。

“黏着”过渡

即无限延长过渡时间段,使得反向过渡看起来失效,从而达成实现的过渡效果悬停的感觉。

.sample {
  transition: background-position 9999999999s stpes(6);
}
.sample:hover {
  transition-duration: 0.6s;
}

延迟过渡

即控制在多久之后才会令过渡效果触发。

过渡的能与不能

过渡只能应用于二者之间有明确的过渡阶段的效果,例如说颜色的变化——本质上来说,网页上的颜色还是通过 rgb 或是 16 进制 转换的值,从纯黑色的 #000 到纯白色的#fff 自然是可以通过计算中间值来达到过度的效果的。

但是对于没有过渡阶段的属性,过渡就无法应用了,例如说 display属性,display: none;display: block; 中间不存在过渡属性,自然也无法产生过渡动画。

另外一种就是过渡属性有可计算的变化量,但是所赋的值无法进行计算,例如说高度宽度盒子大小等都需要提供参数,但是当参数值为 auto 的时候,过渡就无法正确的计算可变化的数值,因此也就无法产生动画效果。

CSS 关键帧动画

过渡给予了一段动画开始和结束的定义,但是如果中间有其他的动画定义就无法被实现了,而使用关键帧动画可以从仅有两个阶段的尴尬境地脱离出来。

书中的案例就很厉害了,将「生命的幻象」部分的动画展示出来了,下面是关键帧的分割:

key-frames

结合起来的效果如下:

box-model

关键帧部分的实现为:

@keyframes roll {
  from {
    transform: translateX(-100%);
    animation-timing-function: ease-in-out;
  }
  20% {
    transform: translateX(-100%) skewX(15deg);
  }
  28% {
    transform: translateX(-100%) skewX(0deg);
    animation-timing-function: ease-out;
  }
  45% {
    transform: translateX(-100%) skewX(-5deg) rotate(20deg) scaleY(1.1);
    animation-timing-function: ease-in-out;
  }
  50% {
    transform: translateX(-100%) rotate(45deg) scaleY(1.1);
    animation-timing-function: ease-in;
  }
  60% {
    transform: translateX(-100%) rotate(90deg);
  }
  65% {
    transform: translateX(-100%) rotate(90deg) skewY(10deg);
  }
  70% {
    transform: translateX(-100%) rotate(90deg) skewY(0deg);
  }
  to {
    transform: translateX(-100%) rotate(90deg);
  }
}

三维变换

关于三维变换,书中实现的一个案例是菜单案例,其效果与下图相似:

flip

这部分内容大多都在 学完一起做个走马灯吧 - CSS 3D 转换学习笔记&学习案例 中讲过了,这里也就不再赘述了。

以上是关于精通 CSS 第 10 章 变换过渡与动画 学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

精通 CSS 第 9 章 表单与数据表 学习笔记

精通 CSS 第 7 章学习笔记(上)

如何使用 css 变换创建循环过渡动画

《精通 CSS3 动画(学完这个课写炫酷页面)》

自己总结的CSS3中transform变换transition过渡animation动画的基本用法

精通 CSS 第 8 章 响应式布局 学习案例