I am Oliver

菜单下面的小精灵

有些网站的导航下面会有一到杠,鼠标在各个导航之间移动的时候,这一道杠也会跟着动,很好看,就像这个

See the Pen ooo-nav by Oliver (@ochukai) on CodePen.

我把她叫做小精灵。


原理

实现这个其实不难,当鼠标移动到某一个菜单上面时,小精灵滑入(至于方向,如果鼠标从右边进入菜单,那就从右向左滑),然后当鼠标移出时,小精灵跟着也移出菜单, 同时如果鼠标恰好移进了另一个菜单,下一个菜单的进入动画也开始播放,连续起来的话就像是小精灵跟着过来了。

实现

菜单

菜单的话当然是用 ul 来实现了

1
2
3
4
5
6
<ul class="nav">
  <li>我的</li>
  <li>导航栏</li>
  <li>非常</li>
  <li>牛逼</li>
</ul>

小精灵

这个小精灵该怎么实现呢, 开始时我打算用 border 来实现,试了一下之后才发现,并不理想,因为当鼠标 hover 时,border 变化,内容也会随着动,很丑。

于是我就想用 after 这个伪元素来实现,因为之前并没用过,感觉蛮新鲜的。

使用 after 最重要的地方也是前提,就是 content: '',如果没有这一句,不管怎么修饰 after 的样式,都是徒劳。

写完之后的样子大概是这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> li {
  float:left;
  display: inline-block;
  padding: 10px 20px;
  cursor: pointer;
  position: relative;
  overflow: hidden;

  &:after {
    content: '';
    height: 3px;
    position: absolute;
    bottom: 0;
  }
}

动画

根据上面的原理,如果想实现的话,大概只需要写四个动画

  • 小精灵从右向左进入菜单
  • 小精灵从右向左移出菜单
  • 小精灵从左向右进入菜单
  • 小精灵从左向右移出菜单

我打算使用 width 的变化来模拟小精灵的滑动效果,假如是从左向右, css 就像下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@keyframes slide-in {
  from { width: 0; }
  to { width: 100%; }
}

.slide-in-from-left:after,
.slide-out-from-left:after {
  left: 0; // 初始位置在左边,宽度为 0,宽度逐渐变大
}

.slide-in-from-left:after,
.slide-in-from-right:after {
  animation-name: slide-in;
  animation-timing-function: cubic-bezier(0.65, 0.05, 0.36, 1);
}

JS

css 写完了,不过我要识别鼠标进入或离开的方向,也就是要判断鼠标是从左边进入还是从右边进入,是从左边移出还是从右边移出。

于是, 要写一些 js 来判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$(function() {

  var classList = [
        'slide-in-from-left',
        'slide-in-from-right',
        'slide-out-from-right',
        'slide-out-from-left'
      ].join(' ');

  $('ul.nav')
    .on('mouseenter', 'li', function(e) {
      var $this = $(this);
      var width = $this.outerWidth();
      var xx = e.offsetX;
      var className = (xx < (width / 2))
                    ? 'slide-in-from-left'
                    : 'slide-in-from-right';

      $this.removeClass(classList).addClass(className);      
    })
    .on('mouseleave', 'li', function(e) {
      var $this = $(this);
      var width = $this.outerWidth();
      var xx = e.offsetX;
      var className = (xx < (width / 2))
                    ? 'slide-out-from-left'
                    : 'slide-out-from-right';
      $this.removeClass(classList).addClass(className);
    });

});

这样就写完了,再把开头的例子放上吧。

See the Pen ooo-nav by Oliver (@ochukai) on CodePen.

谢谢。

打赏