通过transition
过渡属性,可以将相关css属性的变化,改为一个持续一段时间的连续过程,而不是使css样式的改变立即生效,其过程按照指定的曲线速率变化。
如下,是利用transition
过渡,通过改变元素位置实现的背景跟随按钮或菜单滑动的效果,位置的改变需要经过一段时间的持续,因此产生了滑动的效果。
背景跟随滑动的实现
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,菜单按钮的width
为110px
。
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前面的菜单按钮没有滑动效果,如下:
因此,需要通过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;
});
})
mouseover
、mouseleave
事件中修改和还原“浅色背景元素”元素的width
、left
,使滑动表现正常。
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);
}