用CSS transitions实现动画式下拉菜单
2012 3 22 02:02 PM 5834次查看
昨天在V2EX看到有人用CSS3特效做页面菜单,其实主要就是用transition这个属性。于是想着本站右上角那个“热门文章”的菜单是否也能弄成动画效果呢,便也尝试了一番,做出了目前这种效果。
不过拿它来讲解也蛮复杂的,于是还是从入门的开始,先做个不依赖JavaScript的没有动画效果的下拉菜单。
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
ul, li {
list-style: none;
margin: 0;
padding: 0;
}
#nav a {
display: inline-block;
background: #eee;
padding: 3px;
margin: 3px;
width: 100px;
text-decoration: none;
}
#nav a:hover {
background: #aaa;
}
#nav li {
position: relative;
}
#nav>li {
display: inline-block;
}
#nav ul {
display: none;
position: absolute;
}
#nav li:hover>ul {
display: block;
}
#nav ul ul {
left: 110px;
top: 0;
}
</style>
</head>
<body>
<ul id="nav">
<li><a href="#">1</a></li>
<li>
<a href="#">2</a>
<ul>
<li>
<a href="#">2.1</a>
<ul>
<li><a href="#">2.1.1</a></li>
<li><a href="#">2.1.2</a></li>
</ul>
</li>
<li>
<a href="#">2.2</a>
<ul>
<li><a href="#">2.2.1</a></li>
<li>
<a href="#">2.2.2</a>
<ul>
<li><a href="#">2.2.1</a></li>
<li><a href="#">2.2.2</a></li>
<li><a href="#">2.2.3</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#">2.3</a></li>
</ul>
</li>
<li>
<a href="#">3</a>
<ul>
<li><a href="#">3.1</a></li>
<li><a href="#">3.2</a></li>
</ul>
</li>
<li><a href="#">4</a></li>
</ul>
</body>
</html>
效果怎样我就不做个页面来演示了,借口也不找了,反正我就是懒。也不想管其他浏览器怎样,我主要用Chrome开发。
简单说下原理:
- 首先是将第一级菜单的菜单项(#nav>li)设为横排排列(display: inline-block或float: left都可)。
- 接着将第二级菜单及其子菜单(#nav ul)隐藏(display: none),而在鼠标悬停在菜单项上时(#nav li:hover>ul),显示下级子菜单(display: block)。
- 最后调整一下ul和li的position(分别为absolute和relative),让三级或更低级菜单(#nav ul ul)可以向右延伸(left: 110px;top: 0)。
接下来就该让它动起来了,先来试试对display属性进行渐变:
#nav ul {
-webkit-transition: display 0.3s 0.1s ease-out;
}
这里我求方便只写了-webkit-transition,要支持其他浏览器的话,还得补上-moz、-o和-ms等。这种写法其实是4个属性的缩写,分别是:
- transition-property:设定哪些属性的变化需要渐变,上面是针对display属性。
- transition-duration:渐变持续的时间。
- transition-delay:等待多久以后再开始变化,省略则为0。
- transition-timing-function:设置渐变过程中,每个阶段快慢的函数。它是一个贝塞尔曲线函数,有ease、linear、ease-in、ease-out和ease-in-out这5个预定义的值,详细解释可以参考MDN。
现在再刷新试试我们的例子,你会发现什么动画效果都没有⋯至于原因嘛,估计是display从none到block不是一个可视的渐变过程,真正可渐变的应该是opacity。
于是再次改动代码:
#nav ul {
/* display: none; */
opacity: 0;
position: absolute;
-webkit-transition: opacity 0.3s 0.1s ease-out;
}
#nav li:hover>ul {
/* display: block; */
opacity: 1;
}
这次刷新后,终于能看到效果了。可是当鼠标移动到一些空白的地方也会显示菜单,这就有bug了。解决办法就是用visibility属性,它同样也得应用transition,且时间和opacity的相同,否则在opacity渐变时,可能因visibility为hidden而看不到动画效果。
#nav ul {
visibility: hidden;
opacity: 0;
position: absolute;
-webkit-transition: opacity 0.3s 0.1s ease-out, visibility 0.3s 0.1s linear;
}
#nav li:hover>ul {
visibility: visible;
opacity: 1;
}
这里用了不同的函数,在不透明度变化时,我希望用户能很快看到菜单的出现,然后慢慢完全清晰地显示出来,所以可以用ease-out(感觉更好的方式是在:hover时也定义ease-in);而visibility其实也是没有可视的渐变过程的,所以用什么都无所谓。单纯渐显的菜单也没什么意思,所以再来改变一下高度吧:
#nav li li {
height: 0;
-webkit-transition: height 0.3s 0.1s ease-out;
}
#nav li:hover>ul>li {
height: 28px;
}
现在看上去效果不错,可是三级菜单不适合向下展开,最好是向右展开,于是再改下:
#nav li li li {
height: 28px;
}
#nav ul ul {
left: 0;
top: 0;
-webkit-transition: left 0.3s 0.1s ease-out;
}
#nav ul li:hover>ul {
left: 110px;
top: 0;
z-index: -1;
}
这里唯一需要提的是z-index: -1,如果不设置的话,子菜单会覆盖在父菜单上面,获得鼠标焦点,再往右移动,这样鼠标焦点就跑到子菜单上去了。我不清楚有没有更好的解决办法,反正这样是可以搞定的。我想看到这里,大家应该懂得怎么用transition了。它很简单好用,能高效地完成以前只能用JavaScript做到的动画效果;不过兼容性还是个问题,至少我在iOS设备上就不能用tap来触发:hover和:active的transition效果,别说动画效果了,连最终效果都没了⋯⋯
0条评论 你不来一发么↓