纯css实现可交互的动画

1,959 阅读4分钟

如题,不借助JavaScript,只利用CSS,如何实现可交互式的动画呢?或许该需求仅此一种解决方案,绝无仅有。不知该方案是否是第一次找到。

什么是可交互动画?

就是可以响应用户的动画,直接上图吧,更直观更清晰。 当用户点击按钮或者心的时候,就会跳动一下。

该示例中用到的有趣知识点

1. 重写checkbox样式

我们经常遇到一个问题,需要重写checkbox,这个示例正好用到,值得收藏。这里直接是重写了input的样式,思路如此,代码如下:

input {
  display: inline-block;
  width: 36px;
  text-align: center;
}

input::after {
  content: attr(label);
  display: inline-block;
  width: 100%;
  height: 100%;
  background-color: white;
  white-space: normal;
  cursor: pointer;
}

input:active::after {
  cursor: wait;
}

2. 两种兄弟选择器

1. +号选择器。

选择DOM结构在自己下方且紧邻自己的单个兄弟元素。

2. ~号选择器。

选择DOM结构在自己下方的所有兄弟元素。

有时候我们很想选择自己的兄弟元素,不关心他们DOM结构的关系,目前CSS是做不到。而有时候我们也很想选择父元素,目前CSS也是没有的,如果有,该示例就灵活多了。如果有,我们也可以选择所有的兄弟元素了。

目前父元素选择器还在草案阶段,而且计划是CSS5才会出,这是多年以后的事情了。

3. :checked选择器。

当checkbox的状态选中时,可以应用一组样式。

上面三点是「纯CSS实现可交互动画」的基础。不过,还有一些基础需要知道。

4. 样式优先级。

定义在文件下方的样式会覆盖文件上方的样式 -- 其他优先级这里不多说。

5. 动画通常是立即执行。

放在这里说明的原因是,我们通过:checked选择及兄弟选择器找到目标元素,给它设置动画属性。当然动画也有paly属性。

有了上面的知识点,基本就可以开始搞了。那为什么不写一些动画相关的呢?因为动画可以有千万种,但是仅仅通过CSS就让你的动画可交互,目前我所知,只有这一种,欢迎来探索。这里不包含「transition」。

如何实现?

结合上面的知识点,下面给出思路。

1. 先贴出HTML代码结构。

外层包了一层div,示例简单,可有可无。定义了一个类,示例中没有用到,权当注释就好。

<div class="animation-box">
  <input class="init" label="心跳"" type="checkbox">
  <input class="alternating" label="跳心" type="checkbox">
  <div class="heart"></div>
</div>

2. 覆盖原生checkbox样式。

上面代码已经贴出来。这里是简单覆盖其样式,真实需求中,可以再做变换。

为什么会有两个checkbox?一个类名是init,一个类名是alternating。一个是为了初始化目标(需要执行动画的元素)元素,一个是来回切换目标元素的动画。div.heart是目标动画元素。且看以下思路。

3. 首先隐藏alternating checkbox。

.alternating {
  display: none;
}

4. 当init被选中时:

1. 隐藏自己

.init:checked {
  display: none;
}

2. 显示alternating

.init:checked + .alternating {
  display: inline-block;
}

3. 给heart设置动画

.init:checked ~ .heart {
  animation-name: init;
}

heart被初始化之后,立马执行一个动画,且该动画属性一直保留在heart上。因为init已经隐藏,且始终是选中状态。那么上面的第三段CSS会一直存在。

5. 当alternating被选中时,给heart设置新的动画。

.alternating:checked ~ .heart {
  animation-name: alternating;
}

由于该代码位于init之后,所以,heart会执行新的动画。

6. 当alternating取消选中。

第五条的动画失效,init的动画再次生效。

至此,整个思路已经清晰。init负责初始化动画,alternating在选中与取消变化的过程中,隐式的给heart交替设置了动画。

全部代码

上面已经提到,动画不是本篇的重点。重点是可交互的思路。隐藏,heart这里不再的实现这里不再给出。但是,为了能拿到代码就能看效果,这里简单给一个不是动画的动画代码。

以下代码是全部。

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

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>纯css实现可交互的动画</title>
  <style>
    /* .animation-box */
    input {
      display: inline-block;
      width: 36px;
      text-align: center;
    }

    input::after {
      content: attr(label);
      display: inline-block;
      width: 100%;
      height: 100%;
      background-color: white;
      white-space: normal;
      cursor: pointer;
    }

    input:active::after {
      cursor: wait;
    }

    .alternating {
      display: none;
    }

    .init:checked {
      display: none;
    }

    .init:checked~.heart {
      animation-name: init;
    }

    .init:checked+.alternating {
      display: inline-block;
    }


    .alternating:checked~.heart {
      animation-name: alternating;
    }

    .heart {
      animation-duration: 1s;
      animation-fill-mode: forwards;
    }

    /* 动画 */
    @keyframes init {
      0% { transform: scale(0.8, 0.8); opacity: 1; }
      25% { transform: scale(1, 1); opacity: 0.8; }
      100% { transform: scale(0.8, 0.8); opacity: 1; }
    }

    @keyframes alternating {
      0% { transform: scale(0.8, 0.8); opacity: 1; }
      25% { transform: scale(1, 1); opacity: 0.8; }
      100% { transform: scale(0.8, 0.8); opacity: 1; }
    }

    .heart {
      margin: 100px;
      width: 100px;
      height: 100px;
      background: red;
      filter: drop-shadow(0px 0px 20px red);
    }
  </style>
</head>

<body>
  <div class="animation-box">
    <input class="init" label="心跳" type="checkbox">
    <input class="alternating" label="跳心" type="checkbox">
    <div class="heart"></div>
  </div>
</body>
</html>