做导航栏二级菜单,导航最怕的栏级就是鼠标一抖菜单就没了。你肯定遇到过这种情况:想点“产品分类”下面的菜单“工业配件”,结果鼠标稍微偏了一点,导航整个下拉菜单瞬间消失,栏级气得想砸键盘。菜单问题出在哪儿?导航多半是HTML结构没把父子关系绑死,或者CSS里少了那几像素的栏级缓冲地带。
先看一个能用的菜单结构。别搞什么
<div>套<div>再套<ul>,导航导航栏就该用<nav>包一个<ul>,栏级一级菜单项是菜单<li>,二级菜单直接塞进这个<li>里面再开一个<ul>。导航像这样:<nav class="main-nav"> <ul> <li><a href="#">首页</a></li> <li class="has-sub"> <a href="#">产品</a> <ul class="sub-menu"> <li><a href="#">工业配件</a></li> <li><a href="#">家用系列</a></li> <li><a href="#">定制服务</a></li> </ul> </li> <li><a href="#">关于</a></li> </ul> </nav>注意那个
has-sub类,栏级它是菜单整个交互的命门。二级菜单.sub-menu必须是li.has-sub的直接子元素,不能隔一层。很多人喜欢在a标签和ul之间加个div做定位,结果鼠标从a移到div再移到ul,中间只要有一像素空隙,菜单就关了。浏览器可不会猜你的意图。CSS部分,先让一级菜单横过来。
.main-nav > ul用display: flex,li之间给点gap。二级菜单默认要藏起来,但别用display: none,那玩意儿没法做过渡动画,而且鼠标移上去的瞬间菜单是突然蹦出来的。用visibility: hidden配合opacity: 0,再加个transition,顺滑得多。.sub-menu { position: absolute; top: 100%; left: 0; visibility: hidden; opacity: 0; transition: opacity 0.2s, visibility 0.2s; background: #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.1); min-width: 160px; padding: 8px 0; list-style: none; } .has-sub:hover .sub-menu { visibility: visible; opacity: 1; }top: 100%是关键。它让二级菜单紧贴着一级菜单项的底部,中间没有缝隙。但有些设计师觉得贴太紧不好看,想留个4px间距。那你不能直接top: calc(100% + 4px),因为那4px的空隙会让鼠标移过去时触发:hover丢失。正确做法是用padding-top: 4px给.sub-menu自己加内边距,背景色设在li上,这样鼠标滑过空白区域时仍然算在.has-sub里面。我见过一个电商网站,二级菜单有十几项,他们用
column-count: 2分成两列。结果鼠标从第一列移到第二列时,中间隔着列间距,菜单直接消失。后来改成用display: grid加gap,并且把gap算进.sub-menu的padding里,问题才解决。所以记住:任何视觉上的间距,都要用内边距或透明边框来撑,不能用margin或gap把父子元素在盒模型上分开。移动端怎么办?别指望
:hover。触屏设备上要么用:focus-within,要么直接加个click事件切换.open类。我自己的习惯是给.has-sub > a加一个aria-haspopup="true",然后用一小段JS监听点击,切换aria-expanded。CSS里写.has-sub.open .sub-menu { visibility: visible; opacity: 1; }。这样键盘用户按Tab也能展开,无障碍这块顺手就做了。最后提一个坑:如果导航栏用了
顶: 32踩: 25914position: fixed,二级菜单的position: absolute会相对于最近的定位祖先。要是.main-nav没设position: relative,菜单可能飞到页面左上角去。检查一下,给.main-nav加上position: relative,一劳永逸。别问我是怎么知道的。






评论专区