一个纯 CSS 实现的导航条小动画

最近由于见习和各种各样乱七八糟的事情,已经许久没有大段地写代码,也没有更新文章了。这次更新的这篇文章,是我在帮别人修改博客模板的时候,对面提出这样一个动画的需求,并且已经用 jQuery 实现了出来,但 jQuery 动画毕竟很坑,放出来的结果肯定想都不用想,必然是一卡一卡的。秉承我一贯能用大招杀的绝对不用 Q 杀能用 CSS 实现的效果绝不用 JavaScript 的理念,我尝试着用 CSS3 动画实现了这个效果,最终效果(和我觉得最优的解决方案)如下(鼠标放到字上面可以看到效果):

See the Pen A simple navbar animation by peterwang (@peterwang1996) on CodePen.

下面来说说我想到没试的,想到试了不成的和想到最终试成了的办法。

动画拆解

首先这种动画拿到之后我们肯定可以做一个分析,实现这种动画大致的思路无非就有两种,一种是变换,一种是遮挡。所谓变换也就是直接更改物体(在这里是底下的小条)的属性,遮挡也就是用另一个和背景物相同的物体来对下面一层显示的东西进行遮挡,原理都十分简单,并且下面的方法中都有使用到。

JavaScript 实现

这种动画,如果用 JavaScript 来实现的话,思路想必是十分简单的。最简单的办法是在下方初始化一个宽度为0的 div ,然后在 mouseovermouseout 的时候对应着改 positionwidth 就行。还有就是弄两个 div ,一个用来呈现,一个用来遮挡,看起来也十分简单,此外,还有各种各样玲琅满目的动画库貌似也能实现这种效果,这里就不一一叙述了。

纯 CSS 实现

那么刚才也提到过,我的一贯思路是能用 CSS 实现的效果绝不用 JavaScript,而且在这里也确实出现了 JavaScript 动画的性能问题,那么现在我就来说一说我是如何用CSS解决的。

最基本的问题

对于这个效果,首先有个最简单的问题要解决,那就是鼠标进入和离开的时候,效果是不同的,也不是直接简单粗暴地还原操作(这里说的还原操作是指的鼠标移出之后,动画刚好将移入时候的动画倒放一边),然而对于鼠标的进入和移出, CSS 貌似只提供了一个伪类,也就是 :hover 来对应这个事件,那鼠标移出的效果怎么做?于是我求助了万能的 stackoverflow 还真找到一个问题是问这个的,回答者给出了这样的解决方案:

1
element:not(:hover) { ... }

看了这个回答之后简直觉得大开眼界,原来 :not 选择器不仅可以用来选择元素,还可以用来选择伪元素,这样我们就可以用这种效果来模拟类似 mouseout 的效果了。

失败的尝试

做 CSS 动画首先想到的肯定是 transation 属性,而且显然我们知道, background 是可以适用 transition 的,并且MDN
的动画属性支持列表
也可以佐证我们的观点。于是刚开始我自然而然想到了这样的方案:

HTML:

1
2
3
4
5
6
<nav>
<a href="#">
矢泽日香
<div class="underline"><div>
</a>
</nav>

CSS:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
nav a {
...
position: relative;
}

nav a .underline {
position: absolute;
bottom: 10px;
left: 0;
background: linear-gradient(90deg, #000 0%, #000 0%, #6cf 0%, #6cf 0%, #000 0%, #000, 100%);
}

nav a:hover .underline {
background: linear-gradient(90deg, #000 0%, #000 0%, #6cf 0%, #6cf 100%, #000 100%, #000 100%);
transition: background .5s ease-in-out;
}

nav a:not(:hover) .underline {
background: linear-gradient(90deg, #000 0%, #000 100%, #6cf 100%, #6cf 100%, #000 100%, #000 100%);
transition: background .5s ease-in-out;
}

很显然,这里我的意图是将下面 div.underline 这个小条通过渐变来分成三个部分,然后在动作触发时通过改变这三个部分的长度来实现对这个动画的模拟。一切看起来似乎都很美好。但是,当我信心满满地写完之后,试着鼠标放到链接上时,悲剧发生了,底下的条儿一点反应都没有。到处都检查不出问题,但是底下的条儿就是不动。后来经过更深入的了解后发现,原来 transition 对于 background 的支持是不完全的,它并不支持带有渐变的背景,算是长见识了。于是对这种方法的尝试,只能在欢笑声中打出 GG 。

方法一的实现

那么直接改变元素的方法看起来并不可行,那我们只能用另外的方法来实现了。

(待续)

赏我点钱让我去看 7777777 吧!