4

CSS 实现按钮点击动效的套路

 2 years ago
source link: https://segmentfault.com/a/1190000041400360
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

在 Web 中,大部分按钮可能都是平平无奇的,有时候为了强调品牌特殊或者满足特殊功能,可能需要给按钮添加一点点击动效。比如,用过 Ant Design 的小伙伴应该都能发现,在点击按钮的时候会有一个很微妙的水波动画

Kapture 2022-02-10 at 18.55.48

这就非常有特色了,看到这样的按钮自然会联系上 Ant Design 。

动画过程其实不复杂,看了一下官方的实现,是通过 js 动态更改属性实现的,在点击的时候,改变属性,触发动画,当动画结束之后,再将该属性还原(还原是为了保证下次点击仍然有动画),如下

image-20220211184419600

看着好像有点麻烦?其实,这种效果也是可以纯 CSS 实现的,而且还能实现其他更多有趣的效果

Kapture 2022-02-11 at 20.02.15

一起看看吧~

一、CSS 过渡动画

通常 CSS 中实现动画有两种思路,transitionanimation。一般而言,简单的、需要主动触发(:hover:active或者动态切换类名等)的可以用transition实现,其他的都可以用animation

回到这个例子,动画足够简单了,就两个变化,而且需要主动触发(这里是点击,可以想到:active),所以优先考虑用transition来实现。

观察整个动画,其实就是两个效果叠加而成

  1. 阴影不断扩大
  2. 透明度不断降低

那么,这个动画(过渡)的两种状态可以这样来表示

/* 初始状态 */
button{
  opacity: .4;
  transition: .3s;
}
/* 扩散状态 */
button{
  box-shadow: 0 0 0 6px var(--primary-color);
  opacity: 0;
}

嗯,两种状态的样式都写好了,怎么触发点击呢?

二、CSS 点击动画

先完善一下基本样式,假设 HTML 结构如下

<button class="button">Default</button>

简单美化一下

:root{
  --primary-color: royalblue;
}
.button{
  padding: 5px 16px;
  color: #000000d9;
  border: 1px solid #d9d9d9;
  background-color: transparent;
  border-radius: 2px;
  line-height: 1.4;
  box-shadow: 0 2px #00000004;
  cursor: pointer;
  transition: .3s;
}
.button:hover{
  color: var(--primary-color);
  border-color: currentColor;
}

然后添加阴影扩散动画,为了方便透明度的控制,这里用::after伪类单独渲染

.button::after{
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  opacity: 0.4;
  transition: .3s;
}

如果按照正常的思路通过:active来触发过渡动画,可能会这样来实现

.button:active::after{
  box-shadow: 0 0 0 6px var(--primary-color);
  opacity: 0;
}

效果如下:

Kapture 2022-02-10 at 20.35.12

嗯,好像不大对劲?接着往下看

三、CSS 过渡重置

为什么会有上面这种现象呢?这里提一下:active:active只有在鼠标按下时才会起作用,通常在点击一个按钮时,都是轻轻地点击,而不是长按,如果在:active上添加动画,那么在鼠标抬起的时候,动画一般都没有结束,所以会导致在鼠标抬起的时候,动画马上就停止了,如果是transition,还会有一个“回退”的过渡效果。

那么,有没有什么方法可以只在鼠标抬起的时候产生动画呢?

我的实现是这样的,假设默认就是有阴影(透明度为0)的状态,在:active的时候迅速去除阴影(这里的“迅速”,是指取消按下去的过渡动画),然后由于默认是有过渡的,所以鼠标抬起的时候阴影就回退到有阴影的状态了,这样可以保证按下去是没有动画的,抬起来触发过渡动画

整个流程其实是这样:

image-20220214104311207

取消过渡动画也很简单,设置时长为 0 就行了,代码实现就是这样

.button::after{
  /*其他样式*/
  opacity: 0;
  box-shadow: 0 0 0 6px var(--primary-color);
  transition: .3s;
}
/*点击*/
.button:active::after{
  box-shadow: none;
  opacity: 0.4;
  transition: 0s; /*取消过渡*/
}

然后,神奇的效果就出来了!

Kapture 2022-02-10 at 20.56.07

这样就实现了和 Ant Design 几乎相同的点击效果

四、其他动效案例

上面其实提供了一种思路,只要是这种点击动画,都可以采用这种方式来实现。比如这样一个刷新按钮,需要点击的时候转一下

Kapture 2022-02-10 at 21.14.32

用这种思路就很容易了,这个例子比上面那个要简单一些,毕竟只有旋转变化,没有透明度变化,核心代码如下

.icon{
    transform: rotate(360deg);
    transition: .5s;
}
.button:active .icon{
    transform: rotate(0);
    transition: 0s;
}

完整代码可以访问 ant design button (codepen.io),整合了更多的 demo

Kapture 2022-02-10 at 21.18.41

再比如这样的点击粒子动效,原理也是相同的

Kapture 2022-02-11 at 14.08.54

在之前文章CSS实现一个粒子动效的按钮中已经有讲到,这里就不多说了,完整代码可以访问 button-active (codepen.io)

五、更复杂的动画

前面提到过,简单的动画可以用过渡transition来实现,那么稍微复杂点的,比如下面这种 “Q弹Q弹” 的按钮

Kapture 2022-02-11 at 14.13.25

这类动画,单纯的transition就无能为力了,必须借助animation来实现,原理还是类似

先定义一个动画关键帧

@keyframes tada {
    from {
        transform: scale3d(1, 1, 1)
    }
    10%, 20% {
        transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg)
    }
    30%, 50%, 70%, 90% {
        transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg)
    }
    40%, 60%, 80% {
        transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg)
    }
    to {
        transform: scale3d(1, 1, 1)
    }
}

这个动画来自于 Animate.css 中的 tada,直接 copy 过来就行

然后让按钮动起来

.button{
  animation: tada 1s;
}

在点击的时候重置动画,直接重置动画,animation可能会更好理解一些,这样在抬起的时候会重新运行动画

.button:active{
  animation: none;
}

这样就实现了,是不是出乎意料的容易?

不过有一点小瑕疵,每次页面刷新,按钮会主动进行一次动画(因为动画是自动执行的),如下

Kapture 2022-02-11 at 14.20.28

那么,如何避免首次进来时动画不执行呢?

这里有一个小技巧,可以在默认情况下设置动画时长为 0 ,这样在首次动画执行后,马上就结束了,然后在 hover时恢复默认的动画时长,由于动画已经结束,改变动画时长也不会触发动画再次运行,所以实现就是

.button{
  animation: jump 0s;
}
.button:hover{
  animation-duration: 1s;
}
.button:active{
  animation: none;
}

这样刷新页面就不会再有动画了

Kapture 2022-02-11 at 14.28.44

接下来,借助 animate.css 你可以更换任意的动画,比如

Kapture 2022-02-11 at 19.59.00

完整代码可以访问button-jump (codepen.io),整合了更多的 demo

Kapture 2022-02-11 at 20.02.15

六、总结和说明

以上就是关于 CSS 点击动画的几个套路和一些案例,其实就是默认执行动画,点击时重置一下就行了。整体来说代码很简单,只是理解起来可能不是特别顺畅,下面总结一下实现要点:

  1. 简单动画用transition,其他用 animation
  2. transition 可以通过设置时长为 0 来重置
  3. animation 可以通过设置 none 来重置
  4. 在 :active 时重置动画,点击后会再次运行动画
  5. 复杂的动画可以借助现有的动画库,例如 anmate.css
  6. 设置动画时长为 0 可以避免首次渲染出现动画

相比 js 实现,CSS 实现代码更少,加载更快,无需等待 js 加载完成,体验更优(比如天然支持敲空格键触发),同时也更容易维护和使用,直接复制一个类名就行了。最后,如果觉得还不错,对你有帮助的话,欢迎点赞、收藏、转发❤❤❤


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK