情景描述
假设我们希望导航栏上有一个元素(以下简称“菜单标题”),把鼠标移到标题上面时其下方会弹出一列菜单,鼠标离开时菜单又隐藏起来。
然而,当试图把鼠标从菜单标题移到菜单内容中时,菜单竟然也隐藏了。
我的菜单内容(平时隐藏的那一部分)是由一个 <ul>
充当的。
html
<html>
<head>
<title>test1</title>
<link rel="stylesheet" type="text/css" href="test1.css">
</head>
<body>
<div class="dropdown">
<span>菜单</span>
<ul class="dropdown-content">
<li>a</li>
<li>b</li>
<li>c</li>
</ul>
</div>
<div>后续内容</div>
</body>
</html>
css
.dropdown{
display:inline-block;
position:relative;
}
.dropdown-content{
display:none;
position:absolute;
}
.dropdown:hover .dropdown-content{
display:block;
}
.dropdown , .dropdown-content{
border-width:2px;
border-style:dotted;
}
原因和解决方案
首先分析这个菜单的结构:由 <div class="dropdown">
充当父元素,它有两个子元素:一个 <span>
做触发下拉菜单的起点,一个 <ul>
做平时被隐藏的菜单内容。由于 css 源码中的 :hover
是作用在父元素上的,因此按理来说即使鼠标移到了菜单内容 <ul>
上,鼠标其实也还是在父元素内的(但其实不是!)。
我通过让相关元素显示边框(如上),找到了原因:<ul>
与父元素 <div class="dropdown">
之间有空隙,鼠标经过这个空隙的瞬间就完全离开了父元素了。因此得出两种解决思路:一是为 <ul>
设置 margin-top:0;
使这个空隙消失;二是把实现这个菜单内容的 <ul>
替换成(另一个)<div>
(猜想也许不同种类的元素的默认 margin-top
不一样?进一步猜想,这个不同也许就是块元素与内联元素的区别之一?)。
进一步细究,还会发现一个问题:父元素的边框竟然没有包住子元素!我想,这是因为我们把菜单内容设置成了 position: absolute
。为什么要这样做?因为如果子元素被包在父元素内(position
保持默认值),那么当下拉菜单向下弹出时,页面中从此开始的后续内容也就跟着往下移了,我们通常不希望有这种效果。当然,这也勉强算是解决本文问题的又一种方案吧。
解决方案一:margin-top:0
在 css 中,为充当菜单内容的元素(class为 .dropdown-content
)添加 margin-top:0
。
解决方案二:菜单内容改成其它种类元素
在 html 中,将充当菜单内容的元素改成另一种,比如 <div>
。
解决方案三(通常不推荐):去除 position: absolute
在 css 中,为充当菜单内容的元素(class为 .dropdown-content
)删去 position:absolute
。这会导致当下拉菜单向下弹出时,页面中从此开始的后续内容也就跟着往下移。