您的位置:首页 > Web前端 > CSS

CSS3简单实现动画下拉菜单(display:none和CSS3动画之踩坑)

2017-05-26 15:11 411 查看
文本介绍了采用CSS3的 transform 和  transition 属性来实现下拉菜单的动画效果。

由于css3的动画化和display:block以及display:none这两个属性有所冲突,这里提出了一种解决方法。

这里要实现的动画效果是这样的,首先子菜单用display:none来隐藏,它的初始opacity:0,位置向上有一个偏移

当鼠标滑过目标1的时候,子菜单的属性变为为display:block,之后子菜单边出现在下图中虚线处的位置上。接下来,子菜单的opcacity=1,同时下滑。



html代码如下:

这里subBox初始状态处于隐藏状态,因此设置了一个类hide,让其display:none;

<ul class="menuBox fr">
<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>博客文章</a>
<ul class="subBox hide">
<li><i class="iconfont subNav"></i><a href="#">web前端</a></li>
<li><i class="iconfont subNav"></i><a href="#">nodejs</a></li>
<li><i class="iconfont subNav"></i><a href="#">工具用法</a></li>
</ul>
</li>
<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>兴趣分享</a>
<ul class="subBox hide">
<li><i class="iconfont subNav"></i><a href="#">书籍</a></li>
<li><i class="iconfont subNav"></i><a href="#">影视剧</a></li>
<li><i class="iconfont subNav"></i><a href="#">动漫</a></li>
</ul>
</li>
<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>作品展示</a>
<ul class="subBox hide">
<li><i class="iconfont subNav"></i><a href="#">静态仿站</a></li>
<li><i class="iconfont subNav"></i><a href="#">站点作品</a></li>
<li><i class="iconfont subNav"></i><a href="#">插件</a></li>
</ul>
</li>
<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>关于本站</a></li>
<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>关于我</a></li>
</ul>


liInMenu的css代码如下:

为li设置了relative的定位,以便让subBox基于它定位

.menuBox{
>li{
float: left;
margin-left: 2px;
position: relative;
}


subBox的css代码如下:
这是subBox的初始状态。

transform:translate3d(0,-50px,0);让其顺着Y轴方向上移。

opacity: 0;让它完全处于透明状态下。

transition:all 0.3s;当subBox要通过css3来实现运动的时候,它所有属性的变化过程都会在持续0.3秒

.subBox{
border: 1px solid #ddd;
border-top: none;
position: absolute;
z-index: 10;
left: 0;
top: 70px;
width: 100%;
background-color: #fff;
opacity: 0;
-webkit-transform:translate3d(0,-50px,0);
-moz-transform:translate3d(0,-50px,0);
-ms-transform:translate3d(0,-50px,0);
-o-transform:translate3d(0,-50px,0);
transform:translate3d(0,-50px,0);
-webkit-transition:all 0.3s;
-moz-transition:all 0.3s;
-ms-transition:all 0.3s;
-o-transition:all 0.3s;
transition:all 0.3s;
}


鼠标滑过liInMenu时,添加类showBox,代码如下:

.showBox{
z-index: 10 !important;
opacity: 1 !important;
-webkit-transform:translate3d(0,0,0) !important;
-moz-transform:translate3d(0,0,0) !important;
-ms-transform:translate3d(0,0,0) !important;
-o-transform:translate3d(0,0,0) !important;
transform:translate3d(0,0,0) !important;
}


关于JS代码,这里用jquery

最初我打算用事件代理的方式来写,很遗憾,jquery的事件代理不能触发冒泡,而在下拉菜单中必须要用冒泡。

这是原先失败的代码;

//下拉菜单一定要用到冒泡,由事件代理来实现实在是太麻烦了不可取
//由于a和li都要触发下拉菜单,不能这样用
headerMenuBox.on('mouseover',[liInMenuBox,aInLi],function(event){
console.log('enter')
var subMenu = 'undefined';
if ($(event.target).hasClass('liInMenu')) {
subMenu = $(event.target).children('.subBox')
console.log(subMenu)
}
if ($(event.target).hasClass('aInLi')) {
var parent = $(event.target).parent('.liInMenu')
subMenu = parent.children('.subBox')
console.log(subMenu)
}
if (subMenu!=='undefined') {
subMenu.show().addClass('showMenu')
}
})


之后采用了hover来实现,下面我最初的代码

由于需要确定顺序,当移除hide之后再调用函数添加showBox类,确保动画执行。因此用requestAnimationFrame()方法将传入的函数推到下个轮询中调用。

但这里又出现问题了,当我在liInMenu中迅速来回切换的时候,下拉菜单不再显示。

仔细想了想,应该是requestAnimationFrame()的问题,当我从一个liInMenu迅速移动到另一个liInMenu上时,触发了hover的第二个函数,但这时subBox第二个liInMenu的子菜单了,因而没有正确移除目标类。

var subBox = 'undefined'
for (var j = 0; j < liInMenuBox.length; j++) {
liInMenuBox.eq(j).hover(function(event) {
/* Stuff to do when the mouse enters the element */
subBox = $(this).children('.subBox')
subBox.removeClass('hide')
requestAnimationFrame(function(){
subBox.addClass('showBox')
})
}, function() {
/* Stuff to do when the mouse leaves the element */
subBox.removeClass('showBox')//有0.3秒,没有起到作用
requestAnimationFrame(function(){
subBox.addClass('hide')
})

})
}
查明原因后,将获取的每个subBox分别单独赋予liInBox的一个属性上,消除了bug,修改的代码如下。

for (var j = 0; j < liInMenuBox.length; j++) {
liInMenuBox.eq(j).hover(function(event) {
/* Stuff to do when the mouse enters the element */
this.subBox = $(this).children('.subBox')
this.subBox.removeClass('hide')
var self = this
requestAnimationFrame(function(){
self.subBox.addClass('showBox')
})
}, function() {
/* Stuff to do when the mouse leaves the element */
this.subBox.removeClass('showBox')//有0.3秒,没有起到作用
var self = this
requestAnimationFrame(function(){
self.subBox.addClass('hide')
})
//如果用下面的代码还是会出现问题
// setTimeout(function(){
// 	self.subBox.addClass('hide')
// },350)
})
}
但在从liInBox上移除时,上移的效果没有了,这是因为上移的动作持续了30ms,而requestAnimationFrame()推到下个轮询的间隔估计在30ms以内。

不过这个效果也不错,就没有再修改了。

4000
后续如果解决这个bug我再来更新这片文章。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  jquery 前端 动画 css3