simplify the life

transition、@keyframes animation 和 Hover.css

transition

Transitions enable you to define the transition between two states of an element. Different states may be defined using pseudo-classes like :hover or :active or dynamically set using JavaScript.

综上,transition 动效切换最常用的方式是用伪类(常用 :hover)或者用 JS 动态添加

简单使用可参考 CSS3 过渡

transition 属性设置元素的过渡效果,四个简写属性为:(默认值 all 0 ease 0)(其中前两个比较常用)

  • transition-property(指定 transition 所作用的 CSS 属性,默认 all 全部)
  • transition-duration(指定效果完成时间,默认 0 表示无效果)
  • transition-timing-function(指定效果转速曲线,默认 ease
  • transition-delay(定义效果开始的时候,需要延迟多久开始,默认 0 不延迟)
最简 demo
<!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>
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
      transition: 1s;
    }

    .box:hover {
      width: 200px;
      height: 200px;
      background-color: yellow;
    }
  </style>
</head>
<body>
  <div class="box"></div>
</body>
</html>

上面的 demo 所有的属性 transition-duration 都是 1s,如何同时指定多个 transition-property?

同时指定多个属性
<!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>
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
      /* 同时指定不同属性 */
      transition: width 2s, height 2s, background-color 1s;
    }

    .box:hover {
      width: 200px;
      height: 200px;
      background-color: yellow;
    }
  </style>
</head>
<body>
  <div class="box"></div>
</body>
</html>
用 JS 实现动效切换
<!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>
    .box {
      width: 100px;
      height: 100px;
      background-color: red;
      transition: 2s;
    }

    .larger {
      width: 200px;
      height: 200px;
    }
  </style>
</head>
<body>
  <div class="box"></div>
  <script>
    document.querySelector('.box').addEventListener('click', () => {
      document.querySelector('.box').classList.add('larger')
    })
  </script>
</body>
</html>

keyframes animation

简单使用可参考 CSS3 动画

@keyframes 规则是创建动画

@keyframes bg-color-change {
  from {background: red;}
  to {background: yellow;}
}

可以用百分比来规定变化发生的时间,或者用关键字 fromto,等同于 0%100%

@keyframes bg-color-change {
  0% {background: red;}
  50% {background: green;}
  100% {background: yellow;}
}

用 @keyframes 创建完一个动画,需要把它绑定到一个选择器

最简 demo
<!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>
    div {
      width: 100px;
      height: 100px;
      background-color: red;
    }

    @keyframes bg-color-change {
      from {background: red;}
      to {background: yellow;}
    }
 
    .box:hover {
      /* 绑定 @keyframes 到一个选择器 */
      animation: bg-color-change 2s;
    }
  </style>
</head>
<body>
  <div class="box"></div>
</body>
</html>

@keyframes 所有动画属性:

  • animation-name(规定 @keyframes 动画的名称)
  • animation-duration(规定动画完成一个周期所需要的时间)
  • animation-timing-function(规定动画的速度曲线,默认 ease
  • animation-delay(规定动画开始的延迟时间)
  • animation-play-state(可设置 paused 暂停动画,默认 running
  • animation-iteration-count(设置动画播放次数,默认 1,常用设置 infinite 表示无限循环)
  • animation-direction(定义是否循环交替反向播放动画)(常用设置 alternate,即 1、3、5 等正向播放,2、4、6 等反向播放,多用于循环动画中)
  • animation-fill-mode(设置当动画开始前,或者结束后的样式)

其他的都比较好理解,这里重点说下 animation-fill-mode(更多可以参考 如何理解animation-fill-mode及其使用?

看下这个例子
<!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>
    div {
      width: 100px;
      height: 100px;
      background-color: blue;
    }

    @keyframes bg-color-change {
      from {background: red;}
      to {background: yellow;}
    }
 
    .box.on {
      /* 绑定 @keyframes 到一个选择器 */
      animation: bg-color-change 2s;
      animation-delay: 1s;
    }
  </style>
</head>
<body>
  <div class="box on"></div>
</body>
</html>

我们发现动画开始时有一个 blue->red 的跳转,结束的时候有一个 yellow->blue 的跳转,我们可以设置动画开始前的颜色为 @keyframes 中 from 的样式(animation-fill-mode: backwards),结束的颜色为 to 的样式(animation-fill-mode: forwards),也可以同时设置两者(animation-fill-mode: both

注意如果样式是通过 hover 或者 JS 动态设置的,animation-fill-mode: backwards 的设置其实没啥用(因为不是直接的动画,所以初始的样式不可能用 @keyframes 中 from 的)

hover + animation-fill-mode
<!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>
    div {
      width: 100px;
      height: 100px;
      background-color: blue;
    }

    @keyframes bg-color-change {
      from {background: red;}
      to {background: yellow;}
    }
 
    .box:hover {
      /* 绑定 @keyframes 到一个选择器 */
      animation: bg-color-change 2s;
      animation-delay: 1s;
      animation-fill-mode: both;
    }
  </style>
</head>
<body>
  <div class="box"></div>
</body>
</html>
JS + animation-fill-mode
<!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>
    div {
      width: 100px;
      height: 100px;
      background-color: blue;
    }

    @keyframes bg-color-change {
      from {background: red;}
      to {background: yellow;}
    }
 
    .box.on {
      /* 绑定 @keyframes 到一个选择器 */
      animation: bg-color-change 2s;
      animation-delay: 1s;
      animation-fill-mode: both;
    }
  </style>
</head>
<body>
  <div class="box"></div>
  <script>
    document.querySelector('.box').addEventListener('click', () => {
      document.querySelector('.box').classList.add('on')
    })
  </script>
</body>
</html>

transition VS keyframes animation

参考 CSS animation 与 CSS transition 有何区别?

  1. transition 只有两个状态:开始状态和结束状态;但 animation 可以有多个状态,有帧的概念,并且可以指定动画次数
  2. transition 需要借助别的方式来触发,比如 CSS 的状态选择器(如 :hover)或借助 JS 触发;animation 可以自动触发

所以 keyframes animation > transition,所有 transition 的动画其实都能用 @keyframes 实现

实战

如果需要面试,可以考察下 Hover.css

先考察几个比较简单的动效:

  • Fade(最基本的动效,背景色和字体颜色渐变)(考察基础的 transition)
  • Grow(基础。考察 transform: scale(1.1)
  • Wobble Horizontal(左右快速移动,考察 @keyframes + transform: translateX(8px))(因为从开始到结束并不是只有两个状态,所以需要用 @keyframes)
  • Buzz(和 Wobble Horizontal 类似,也是需要用到 @keyframes,并且是 translateX 和 rotate 属性一起作用,且设置 animation-iteration-count 为 infinite)

Sweep to Right

首先可以考察下这个蓝色背景色是如何加进去的?(用 ::before 或者 ::after

然后考查蓝色背景色位置是如何介于原来 box 和文字中间的?(需要设置 box 为一个新的堆叠上下文,详见 由 Sweep To Right 动效引发的对 z-index 的再度学习

最后才是考察 transition 相关

一个简单实现
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background: #e1e1e1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container:hover {
      color: white;
    }
    
    .container::after {
      content: '';
      position: absolute;
      width: 0;
      height: 100%;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      background-color: #2098D1;
      z-index: -1;
      
      transition: 1s;
    }

    .container:hover::after {
      width: 100%;
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

以上实现是用 width 渐变来做的,也可以用 scale 做大小的渐变(注意需要设置 transform-origin: 0 50%,默认是 (0, 0),在元素的左上角)

scale 实现
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background: #e1e1e1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container:hover {
      color: white;
    }
    
    .container::after {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      background-color: #2098D1;
      transform-origin: 0 50%;
      transform: scaleX(0);
      z-index: -1;

      transition: 1s;
    }

    .container:hover::after {
      transform: scaleX(1);
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

其实修改 transform-origin 以及 transform 可以完成很多不同的渐变效果

Shutter In Horizontal / Shutter Out Horizontal

Shutter Out Horizontal 比较简单,其实就是 Sweep to Right 的变种(transform-origin: 50%,毕竟是从中心开始变大)

Shutter Out Horizontal
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background: #e1e1e1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container:hover {
      color: white;
    }
    
    .container::after {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      background-color: #2098D1;
      transform-origin: 50%;
      transform: scaleX(0);
      z-index: -1;

      transition: 1s;
    }

    .container:hover::after {
      transform: scaleX(1);
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

但是 Shutter In Horizontal 如何实现呢?如果还是将蓝色背景当作 ::after 的元素,可能就需要两个 box,我们可以反过来思考,将灰色背景当作 ::after 的元素,这个思路很巧妙

实现
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background-color: #2098D1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container:hover {
      color: white;
    }
    
    .container::after {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      background: #e1e1e1;
      transform-origin: 50%;
      transform: scaleX(1);
      transition: 1s;
      z-index: -1;
    }

    .container:hover::after {
      transform: scaleX(0);
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

Rectangle In / Rectangle Out

先看 Rectangle Out,参考 Shutter Out Horizontal

Rectangle Out
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background: #e1e1e1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container:hover {
      color: white;
    }
    
    .container::after {
      content: '';
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      background-color: #2098D1;
      transform-origin: 50%;
      transform: scale(0, 0);
      z-index: -1;

      transition: 1s;
    }

    .container:hover::after {
      transform: scale(1, 1);
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

Rectangle In 参考 Shutter In Horizontal,将两个颜色颠倒,反向思考即可

Underline From Left / Underline From Center

其实和前面的没啥本质区别

Underline From Left
<!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>
    .container {
      display: inline-block;
      margin: 0.4em;
      padding: 1em;
      cursor: pointer;
      background: #e1e1e1;
      color: #666;
      position: relative;

      /* 这里主要为了产生一个层叠上下文 */
      z-index: 0;

      transition: 1s;
    }

    .container::after {
      content: '';
      position: absolute;
      height: 5px;
      right: 0;
      left: 0;
      bottom: 0;
      background-color: #2098D1;
      transform-origin: 0 50%;
      transform: scaleX(0);
      z-index: -1;

      transition: 1s;
    }

    .container:hover::after {
      transform: scaleX(1);
    }
  </style>
</head>
<body style="padding: 200px">
  <a class="container">
    Hover me
  </a>
</body>
</html>

Underline From Center 无非是修改下 transform-origin: 50%

posted on 2023-02-27 21:50  lessfish  阅读(201)  评论(0)    收藏  举报

导航