8. CSS揭秘——过渡与动画

1. 缓动效果

给过渡和动画加上缓动效果(比如具有回弹效果的过渡过程)

image.png

回弹效果是指当一个过渡达到最终值时,往回倒一点,然后再次回到最终值,如此往复一次或多次,并逐渐收敛,最终稳定在最终值。

假设要用一个元素来模拟一个下落的小球,我们会把 transform 属性从 none 过渡到 translateY(350px) 来模拟这个下落过程。

1.1 弹跳动画

CSS 提供了一个 cubic-bezier()函数,允许我们指定自定义的调速函数。

  • 它接受四个参数,分别代表两个控制锚点的坐标值,我们通过这两个控制锚点来指定想要的贝塞尔曲线
  • 语法形式是这样的:cubic-bezier(x1, y1, x2, y2),其中 (x1, y1) 表示第一个控制锚点的坐标,而 (x2, y2) 是第二个。
  • 曲线片断的两个端点分别固定在(0,0) 和 (1,1),前者是整个过渡的起点(时间进度为零,动画进度为零),后者是终点(时间进度为 100%,动画进度为 100%)

image.png

<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes bounce {
        60%, 80%, to {
          transform: translateY(400px);
          animation-timing-function: ease;
        }
        70% {
          transform: translateY(300px);
        }
        90% {
          transform: translateY(360px);
        }
      }

      .ball {
        width: 0;
        height: 0;
        padding: 1.5em;
        border-radius: 50%;
        margin: auto;
        background: red radial-gradient(at 30% 30%, #fdd, red);
        animation: bounce 2s cubic-bezier(0.1, 0.25, 1, 0.25) forwards;
      }

      body {
        background: linear-gradient(skyblue, white 450px, yellowgreen 0);
        min-height: 100vh;
      }
    </style>
  </head>
  <body>
    <div class="ball"></div>
  </body>
</html>

1.gif

1.2 弹性过渡

假设有一个文本输入框,每当它被聚焦时,都需要展示一个提示框。这个提示框用来向用户提供帮助信息,比如字段值的正确格式等

CSS 属性 transform-origin 更改一个元素变形的原点。

image.png

<!DOCTYPE html>
<html>
  <head>
    <style>
      input:not(:focus) + .callout:not(:hover) {
        /*隐藏.callout*/
        transform: scale(0);
        transition: 0.25s transform;
      }

      .callout {
        transition: 0.5s cubic-bezier(0.25, 0.1, 0.3, 1.5) transform;
        transform-origin: 1.4em -0.4em;
      }

      /* Styling */
      body {
        padding: 1.5em;
        font: 200%/1.6 Baskerville;
      }

      input {
        display: block;
        padding: 0 0.4em;
        font: inherit;
      }
      /*提示框样式*/
      .callout {
        position: absolute;
        max-width: 14em;
        padding: 0.6em 0.8em;
        border-radius: 0.3em;
        margin: 0.3em 0 0 -0.2em;
        background: #fed;
        border: 1px solid rgba(0, 0, 0, 0.3);
        box-shadow: 0.05em 0.2em 0.6em rgba(0, 0, 0, 0.2);
        font-size: 75%;
      }
      /*三角形的箭头*/
      .callout:before {
        content: "";
        position: absolute;
        top: -0.4em;
        left: 1em;
        padding: 0.35em;
        background: inherit;
        border: inherit;
        border-right: 0;
        border-bottom: 0;
        transform: rotate(45deg);
      }
    </style>
  </head>
  <body>
    <label>
      Your username:
      <input value="leaverou"></input>
      <span class="callout">
      Only letters, numbers, underscores (_) and hyphens (-) allowed!
      </span>
    </label>
  </body>
</html>

1.gif

2. 逐帧动画

以最常见的 “加载中” 的效果为例:

使用step()函数,它可以传入一个参数,表示此次动画是分几步完成的,例如,step(8) 表示此次动画是分8部完成,也就是总共8帧,且逐帧匀速去执行的。

<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes loader {
        to {
          background-position: -800px 0;
        }
      }

      .loader {
        width: 100px;
        height: 100px;
        text-indent: 999px;
        overflow: hidden; /* Hide text */
        background: url(http://dabblet.com/img/loader.png) 0 0;
        animation: loader 1s infinite steps(8);
      }
    </style>
  </head>
  <body>
    <div class="loader">Loading…</div>
  </body>
</html>

1.gif

3. 闪烁效果

通过数次闪烁(不超过三次)来提示用户界面中有某处发生了变化。

  • 比如对整个元素进行闪烁(通过 opacity 属性),
  • 对文字的颜色进行闪烁(通过 color 属性),
  • 对边框进行闪烁(通过 border-color 属性),等等

animation-direction 的 唯 一 作 用 就 是 反 转 每 一 个 循 环 周 期(reverse),或第偶数个循环周期(alternate),或第奇数个循环周期(alternate-reverse)。它的伟大之处在于,它会同时反转调整函数,从而产生更加逼真的动画效果

<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes blink-1 {
        /*让状态切换发生在每个循环周期的中间*/
        50% {
          color: transparent;
        }
      }
      @keyframes blink-2 {
        to {
          color: transparent;
        }
      }

      p {
        padding: 1em;
        background: gold;
      }

      .blink-smooth-1 {
        animation: 1s blink-1 3;
      }

      .blink-smooth-2 {
        animation: 0.5s blink-2 6;
        animation-direction: alternate;
      }

      .blink {
        animation: 1s blink-1 3 steps(1);
      }
    </style>
  </head>
  <body>
    <p class="blink-smooth-1">Peek-a-boo!</p>
    <p class="blink-smooth-2">Peek-a-boo!</p>
    <p class="blink">Peek-a-boo!</p>
  </body>
</html>

1.gif

4. 打字动画

一段文本中的字符逐个显现,模拟出一种打字的效果。

核心思路就是让容器的宽度成为动画的主体:把所有文本包裹在这个容器中,然后让它的宽度从 0 开始以步进动画的方式、一个字一个字地扩张到它应有的宽度。并不适用于多行文本

  • 用 white-space:nowrap; 来阻止文本折行
  • overflflow: hidden;,超出宽度的文本裁切掉
  • 逐帧动画steps()所需要的步进数量是由字符的数量来决定的
  • ch 单位,表示“0”字形的宽度。在等宽字体中,“0”字形的宽度和其他所有字形的宽度是一样的。
  • 用右边框来模拟光标效果,infinite 关键字循环闪烁光标
<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes typing {
        from {
          width: 0;
        }
      }

      @keyframes caret {
        50% {
          border-right-color: transparent;
        }
      }

      h1 {
        font: bold 200% Consolas, Monaco, monospace;
        /*width: 8.25em;*/
        width: 15ch;
        white-space: nowrap;
        overflow: hidden;
        border-right: 0.05em solid;
        animation: typing 8s steps(15), caret 1s steps(1) infinite;
      }
    </style>
  </head>
  <body>
    <h1>CSS is awesome!</h1>
  </body>
</html>

1.gif

5. 状态平滑的动画——暂停动画

不是所有动画都是在页面一加载好就立即播放的。

通过动画来响应用户的动作。用户的动作会随时中断动画,而此时在默认情况下,动画只会立即停止播放,并生硬地跳回开始状态

有一个属性正好是为暂停动画的需求专门设计的:animation-play-state

<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes panoramic {
        to {
          background-position: 100% 0;
        }
      }

      .panoramic {
        width: 150px;
        height: 150px;
        background: url("http://c3.staticflickr.com/3/2671/3904743709_74bc76d5ac_b.jpg");
        background-size: auto 100%;
        animation: panoramic 10s linear infinite alternate;
        animation-play-state: paused;
      }

      .panoramic:hover,
      .panoramic:focus {
        animation-play-state: running;
      }
    </style>
  </head>
  <body>
    <div class="panoramic"></div>
  </body>
</html>

把动画加在 .panoramic 这条样式中,但是让它一开始就处于暂停状态,直到 :hover 时再启动动画。这再也不是添加和取消动画的问题了,而只是暂停和继续一个一直存在的动画,因此再也不会有生硬的
跳回现象了

1.gif

6. 沿环形路径平移的动画

用CSS 动画来让一个元素沿着环形路径动起来

我们希望它只是沿着环形进行移动,同时保持自己本来的朝向

6.1 需要两个元素的解决方案

用内层的变形来抵消外层的变形效果

  • 对头像元素设置另一个旋转动画,让它以相反的方向自转一周,这两层旋转的作用会在头像上相互抵消,我们只会看到父元素旋转所产生的环绕动作
  • 让内层动画从父元素那里继承所有的动画属性,然后把动画名覆盖掉
<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes spin {
        to {
          transform: rotate(1turn);
        }
      }

      .avatar {
        animation: spin 3s infinite linear;
        transform-origin: 50% 150px;
      }

      .avatar > img {
        animation: inherit;
        animation-direction: reverse;
        /*reverse 值,可以得到原始动画的反向版本*/
      }

      /* Anything below this is just styling */

      .avatar {
        width: 50px;
        margin: 0 auto;
        border-radius: 50%;
        overflow: hidden;
      }

      .avatar > img {
        display: block;
        width: inherit;
      }

      .path {
        width: 300px;
        height: 300px;
        padding: 20px;
        border-radius: 50%;
        background: #fb3;
      }
    </style>
  </head>
  <body>
    <div class="path">
      <div class="avatar">
        <img src="http://lea.verou.me/book/adamcatlace.jpg" />
      </div>
    </div>
  </body>
</html>

1.gif

6.2 单个元素的解决方案

用两次位移变形(translate)来代替变形原点(transform-origin)的作用

每个transform-origin 都是可以被两个translate() 模拟出来的

transform: rotate(30deg);
transform-origin: 200px 300px;
/*等价*/
transform: translate(200px, 300px) rotate(30deg) translate(-200px, -300px);
transform-origin: 0 0;

每个变形函数并不是只对这个元素进行变形,而且会把整个元素的坐标系统进行变形,从而影响所有后续的变形操作。

可以把两套动画合并为一套,并只用在 .avatar这一个元素上

image.png

把头像放在圆心并以此作为起点,我们就可以消除最开始的那两个位移操作了

<!DOCTYPE html>
<html>
  <head>
    <style>
      @keyframes spin {
        from {
          transform: rotate(0turn) translateY(-150px) translateY(50%)
            rotate(1turn);
        }
        to {
          transform: rotate(1turn) translateY(-150px) translateY(50%)
            rotate(0turn);
        }
      }

      .avatar {
        animation: spin 3s infinite linear;
      }

      /* Anything below this is just styling */

      .avatar {
        display: block;
        width: 50px;
        margin: calc(50% - 25px) auto 0;
        border-radius: 50%;
        overflow: hidden;
      }

      .path {
        width: 300px;
        height: 300px;
        padding: 20px;
        margin: 100px auto;
        border-radius: 50%;
        background: #fb3;
      }
    </style>
  </head>
  <body>
    <div class="path">
      <img src="http://lea.verou.me/book/adamcatlace.jpg" class="avatar" />
    </div>
  </body>
</html>

1.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容