基于纯HTML&CSS实现子菜单根据空间自动上下动态定位
子菜单底部空间不足时自动向上显示的解决方案
问题
纯CSS实现的菜单-子菜单功能,鼠标悬停主菜单项时子菜单可正常展开,但当菜单位于页面底部时,子菜单会超出页面底部。需要实现:当底部可用空间不足时,子菜单自动切换为向上展开,根据空间自动调整位置。
现有代码
CSS
.main-item { list-style-type: none; } .main-item li:hover > ul.dropdown-menu { display: block; } .dropdown-submenu { position: relative; } .dropdown-submenu > .dropdown-menu { top: 0; left: 100%; margin-top: -6px; } .dropdown-item { padding: 0.5rem; cursor: pointer; background-color: #fff; color: #6c757d; border-color: #6c757d; } .dropdown-item:hover { background-color: #6c757d; border-color: #6c757d; color: #fff; }
HTML
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"/> <ul class="main-item p-0"> <li> <button type="button" class="btn-xs btn-outline-primary">Options</button> <ul class="dropdown-menu"> <li class="dropdown-submenu dropdown-item dropdown-toggle"> Menu 2 <ul class="dropdown-menu"> <li class="dropdown-item">1. sub-menu1</li> <li class="dropdown-item">2. sub-menu2</li> <li class="dropdown-item">3. sub-menu3</li> <li class="dropdown-item">4. sub-menu4</li> <li class="dropdown-item">5. sub-menu5</li> <li class="dropdown-item">6. sub-menu6</li> <li class="dropdown-item">7. sub-menu7</li> <li class="dropdown-item">8. sub-menu8</li> <li class="dropdown-item">9. sub-menu9</li> </ul> </li> </ul> </li> </ul>
解决方案
这里提供两种可行的纯CSS方案,分别适配不同的浏览器兼容性需求:
方案1:利用CSS新特性实现自动空间检测(推荐现代浏览器)
通过:has和:in-view伪类检测子菜单是否超出视口,自动切换展开方向,无需固定子菜单高度:
.main-item { list-style-type: none; } .main-item li:hover > ul.dropdown-menu { display: block; } .dropdown-submenu { position: relative; } /* 默认向下展开,基于父元素底部定位 */ .dropdown-submenu > .dropdown-menu { position: absolute; left: 100%; bottom: 0; max-height: 80vh; /* 限制子菜单最大高度为视口80%,避免过度占用空间 */ overflow-y: auto; /* 空间不足时显示滚动条 */ transform: translateY(100%); margin: 0; } /* 当子菜单无法完全显示在视口内时,改为向上展开 */ .dropdown-submenu:has(.dropdown-menu:not(:in-view)) > .dropdown-menu { bottom: 100%; transform: translateY(-100%); } .dropdown-item { padding: 0.5rem; cursor: pointer; background-color: #fff; color: #6c757d; border-color: #6c757d; } .dropdown-item:hover { background-color: #6c757d; border-color: #6c757d; color: #fff; }
方案2:兼容旧浏览器的固定高度方案
如果需要支持不支持:has伪类的旧浏览器,可以通过提前计算子菜单高度,结合媒体查询来切换展开方向:
.main-item { list-style-type: none; } .main-item li:hover > ul.dropdown-menu { display: block; } .dropdown-submenu { position: relative; } /* 默认向下展开 */ .dropdown-submenu > .dropdown-menu { position: absolute; left: 100%; top: 0; margin-top: -6px; /* 根据子项数量计算固定高度(每个子项高度约2rem,9个为18rem) */ height: calc(9 * 2rem); overflow-y: auto; } /* 当视口高度不足以容纳子菜单向下展开时,切换为向上展开 */ @media screen and (max-height: calc(100vh - 18rem)) { .dropdown-submenu > .dropdown-menu { top: auto; bottom: 100%; margin-top: 0; margin-bottom: -6px; } } .dropdown-item { padding: 0.5rem; cursor: pointer; background-color: #fff; color: #6c757d; border-color: #6c757d; } .dropdown-item:hover { background-color: #6c757d; border-color: #6c757d; color: #fff; }
方案说明
- 方案1无需固定子菜单高度,适配更灵活,但需要浏览器支持
:has(Chrome 105+、Firefox 121+、Safari 15.4+)和:in-view伪类。 - 方案2通过固定高度和媒体查询实现兼容,适合旧浏览器环境,但需要根据实际子项数量调整高度值。
内容的提问来源于stack exchange,提问作者Akhil RJ
相关产品推荐
相关产品推荐

