likes
comments
collection
share

CSS实现背景跟随滑动的按钮菜单效果

作者站长头像
站长
· 阅读数 14

通过transition过渡属性,可以将相关css属性的变化,改为一个持续一段时间的连续过程,而不是使css样式的改变立即生效,其过程按照指定的曲线速率变化。

如下,是利用transition过渡,通过改变元素位置实现的背景跟随按钮或菜单滑动的效果,位置的改变需要经过一段时间的持续,因此产生了滑动的效果。

CSS实现背景跟随滑动的按钮菜单效果 CSS实现背景跟随滑动的按钮菜单效果 CSS实现背景跟随滑动的按钮菜单效果

背景跟随滑动的实现

html和基本css

给定用于显示菜单按钮的导航元素,各个按钮使用a元素(button元素也可以)。

<nav>
    <a href="#">主页</a>
    <a href="#">博客</a>
    <a href="#">随笔手记</a>
    <a href="#">关于此</a>
    <a href="#">联系</a>
    <div class="animation"></div>
    <div class="animation-shadow"></div>
</nav>

然后,给导航菜单设置基本的css,设置整体body的背景,nav的定位是relative,需要定位其内的背景色元素的位置改变。

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
body {
    /* background: #2c3e50; */
    background: #7bbdff;
}
nav{
    position: relative;
    margin: 270px auto 0;
    width: 580px;
    height: 50px;
    background-color: #34495e;
    border-radius: 8px;
    font-size: 0;
    box-shadow: 0 3px 10px 0 rgba(0, 0, 0, .3);
}
nav a{
    font-size: 18px;
    text-transform: uppercase;
    /* 文字阴影 */
    text-shadow: 1px 2px 3px rgba(0, 0, 0, .6);
    color: white;
    text-decoration: none;
    line-height: 50px;
    position: relative;
    z-index: 1;
    display: inline-block;
    text-align: center;
    width: 110px;
}
nav a:nth-child(3){
    width:135px;
}
nav a:nth-child(4){
    width:115px;
}

font-size: 0;用于清除一些行内元素导致的间隙问题,其内的子元素需要指定font-size,否则会不显示文字。

text-transform用于设置文字的变形,比如大小写、首字母大写、反转等效果,仅对于英文字母有效。

z-index指定一个元素层叠顺序,用于显示在默认顺序的背景元素的上方,不至于遮挡文字。

position: relative;需要指定,可以测试下,如果取消relative将会使当前元素被背景元素(absolute)遮挡,即z-index没有起效。

设置导航菜单的宽度,并根据需要不同的菜单项改变下大小。如果宽度全相同,就可以直接按比例拆分width宽度,背景元素的位置也可以按比例。

背景元素的设置

跟随的背景元素

html中的.animation.animation-shadow元素是作为背景或下/上划线元素存在的,通过鼠标的hover和点击之后的样式,改变背景或下/上划线元素的位置,实现滑动效果。

.animation作为菜单项点击后.active时的背景元素

.animation-shadow作为hover时,从.active菜单项滑动出来的浅色背景元素

nav .animation,nav .animation-shadow{
    position: absolute;
    /* 背景跟随 */
    height: 100%;
    top: 0;
    /* 顶部线条跟随 */
    /* height: 10%;
    top: 0; */
    /* 底部线条跟随 */
    /* height: 10%;
    bottom: 0;  */
    z-index: 0;
    background: #1abc9c;
    border-radius: 8px;
    transition: all .5s ease 0s;
}
nav .animation-shadow{
    background: rgba(26, 188, 156, .4);
}

上面注释已经给出,不同的高度和位置,可以实现对应的“背景跟随”、“顶部线条跟随”、“底部线条跟随”。

指定z-index小于导航菜单的

默认不给定背景元素宽度,否则会在默认的其实位置显示出来,我们需要在点击后再在相应位置显示。

transition指定过渡变化的属性:

  • all表示所有属性变化时都使用此过渡方式,
  • .5s属性变化时间为0.5秒,
  • ease是属性变化的缓动函数,表示先慢速,后逐渐变快,最后变慢直到停止。是css默认提供的几种缓动函数之一。
  • 0s最后一项表示执行属性变化动画的延迟,比如可以根据需要延迟样式的改变,默认值为0s

背景元素的样式属性改变

之后,需要设置每个 导航菜单/按钮 激活或hover时对应的“背景框”(背景元素)的位置、大小,需要每个都设置,用于动画移动到对应位置,且在该位置大小与菜单按钮相同。

第一个菜单按钮点击后(点击激活会添加有active的class)、hover时,对应的背景元素(.animation)、浅色背景元素(.animation-shadow)的样式。

第一个菜单按钮的left距离左边为0,菜单按钮的width110px

nav a:nth-child(1).active ~ .animation,
nav a:nth-child(1).active ~ .animation-shadow,
nav a:nth-child(1):hover ~ .animation-shadow{
    width: 110px;
    left: 0;
}

之后时其余的四个元素位置和大小:

nav a:nth-child(2).active ~ .animation,
nav a:nth-child(2).active ~ .animation-shadow,
nav a:nth-child(2):hover ~ .animation-shadow
{
    width: 110px;
    left: 110px;
}

nav a:nth-child(3).active ~ .animation,
nav a:nth-child(3).active ~ .animation-shadow,
nav a:nth-child(3):hover ~ .animation-shadow{
    width: 135px;
    left: 220px;
}

nav a:nth-child(4).active ~ .animation,
nav a:nth-child(4).active ~ .animation-shadow,
nav a:nth-child(4):hover ~ .animation-shadow
{
    width: 115px;
    left: 355px;
}

nav a:nth-child(5).active ~ .animation,
nav a:nth-child(5).active ~ .animation-shadow,
nav a:nth-child(5):hover ~ .animation-shadow{
    width: 110px;
    left: 470px;
}        

原生js处理点击操作

为菜单按钮元素a添加点击事件,事件处理中,其他菜单按钮清除active的class,为当前元素添加.active,实现背景元素的样式设置生效。

但是,对于hover来说,菜单按钮元素被点击.active,浅色背景元素的设置也在生效,如果其菜单按钮前面的按钮被hover,由于浅色背景元素位置和大小已经指定,并且样式设置位于后面,将会覆盖前面hover的样式,即不会生效。

具体表现就是hover前面的菜单按钮没有滑动效果,如下:

CSS实现背景跟随滑动的按钮菜单效果

因此,需要通过js处理,通过修改位置和大小的样式,使权重大于css样式表中的位置和大小,使“往回”滑动生效。

const navas=document.querySelectorAll('nav a');
const nava_shadow=document.querySelector('nav .animation-shadow');
navas.forEach(nava=>{
    nava.addEventListener('click',function(){
        // 测试,极个别情况下,点击无效,需要多点一次
        navas.forEach(a=>a.classList.remove('active'));
        this.classList.add('active');
    });
    // 处理hover时的样式问题
    nava.addEventListener('mouseover',function(){
        let shadowLeft=0;
        let preva=this.previousElementSibling;
        while(preva){
            shadowLeft+=preva.offsetWidth;
            preva=preva.previousElementSibling;
        }
        nava_shadow.style.width=this.offsetWidth+'px';
        nava_shadow.style.left=shadowLeft+'px';
    });
    nava.addEventListener('mouseleave',function(){
        nava_shadow.style.width=null;
        nava_shadow.style.left=null;
    });
})

mouseovermouseleave事件中修改和还原“浅色背景元素”元素的widthleft,使滑动表现正常。

  • previousElementSibling用于获取当前元素的前一个dom元素。

  • offsetWidth获取元素的宽度。

  • .style设置元素的行内样式。

  • 小技巧

如果只有mouseover,在.style样式设置中,直接如下设置offsetWidth,不带单位。

nava_shadow.style.width=this.offsetWidth;
nava_shadow.style.left=shadowLeft;

可以实现,鼠标离开后取消的效果,即css:hover效果。

扩展调整

还可以根据需要,不同的菜单项位置,背景元素使用不同的颜色。

如果跟随不同颜色,.animation.animation-shadow都要指定不同颜色变化。

nav a:nth-child(1).active ~ .animation{
    background-color: rgb(250, 190, 250);
}
nav a:nth-child(1).active ~ .animation-shadow,
nav a:nth-child(1):hover ~ .animation-shadow{
    background-color: rgba(250, 190, 250,.4);
}

nav a:nth-child(2).active ~ .animation{
    background-color: rgb(2, 165, 133);
}
nav a:nth-child(2).active ~ .animation-shadow,
nav a:nth-child(2):hover ~ .animation-shadow{
    background-color: rgba(2, 165, 133,.4);
}

nav a:nth-child(3).active ~ .animation{
    background-color: rgb(141, 161, 248);
}
nav a:nth-child(3).active ~ .animation-shadow,
nav a:nth-child(3):hover ~ .animation-shadow{
    background-color: rgba(141, 161, 248,.4);
}

nav a:nth-child(4).active ~ .animation{
    background-color: rgb(255, 177, 177);
}
nav a:nth-child(4).active ~ .animation-shadow,
nav a:nth-child(4):hover ~ .animation-shadow{
    background-color: rgba(255, 177, 177,.4);
}
      
nav a:nth-child(5).active ~ .animation{
    background-color: rgb(201, 123, 246);
}
nav a:nth-child(5).active ~ .animation-shadow,
nav a:nth-child(5):hover ~ .animation-shadow{
    background-color: rgba(201, 123, 246,.4);
}

CSS实现背景跟随滑动的按钮菜单效果

参考

滑动按钮