纯CSS实现下拉菜单展开时保持按钮下划线动画常驻
问题描述
纯CSS实现简易下拉菜单,全程不使用JavaScript,目前存在交互问题:
- 下拉菜单打开时,要求菜单按钮的下划线动画保持
width: 100%的激活状态 - 实际表现:鼠标移动到展开的下拉菜单位置时,下划线动画会回到初始
width: 0状态 - 约束要求:下划线动画元素必须保留在
<a>标签(即TESTIMONIALS导航选项卡)上,不能把.line-anim类移动到<li>元素和.dropdown-menu-hook同级(虽然该写法能实现预期效果,但不符合结构要求) - 已尝试无效方案:直接给
.line-anim:after设置width: 100%!important;,该写法会丢失平滑过渡动画效果 - 目标效果:下划线平滑过渡到100%宽度后保持激活状态,直到鼠标完全移出下拉菜单区域才收回。
现有实现代码
问题版本(.line-anim挂载在a标签,存在动画复位问题)
/* Main Structure Styling */ .header { width: 100%; } .header ul { display: flex; gap: 20px; justify-items:center; } .header ul li { padding: 10px; } a { text-decoration: none; color: #000; font-size: 20px; } li { list-style: none; } /* Dropdown Menu Styling*/ .dropdown-menu-hook { position: relative; } .dropdown-menu { width: 120px; height: auto; background-color: #fff; border-radius: 10px; padding: 1rem; position: absolute; top: 45.5px; left: 0; visibility: hidden; pointer-events: all; opacity: 0; color: #000; box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.4); display: flex; align-items: center; } .items { display: flex; flex-direction: column; align-items: flex-start; } .item1, .item2, .item3, .item4 { line-height: 1.2; color:#000; font-weight: 500; padding: 10px; transition: .3s; } .dropdown-menu-hook:hover > .dropdown-menu { visibility: visible; pointer-events: all; opacity: .9; } .dropdown-menu { transition: opacity .5s; } /* Line Animation */ .line-anim { position: relative; width: fit-content; } .line-anim:after { content: ""; background-color: #000; height: 1px; width: 0; left: 0px; top: -5px; transition: 0.4s ease-out; position: absolute; } .line-anim:hover:after { width: 100%; } a:hover > .line-anim { display: block; }
<nav class="header"> <ul> <li><a href="#" class="line-anim">ABOUT</a></li> <li class="dropdown-menu-hook"> <a href="#" class="line-anim">TESTIMONIALS</a> <div class="dropdown-menu"> <div class="items"> <a class="item1" href="#">Item 1</a> <a class="item2" href="#">Item 2</a> <a class="item3" href="#">Item 3</a> <a class="item4" href="#">Item 4</a> </div> </div> </li> <li ><a href="#" class="line-anim">CONTACT</a></li> </ul> </nav>
已尝试无效写法
.line-anim:after { width: 100%!important; transition: all .9s; }
参考效果版本(.line-anim挂载在li标签,效果符合预期但不符合结构要求)
/* Main Structure Styling */ .header { width: 100%; } .header ul { display: flex; gap: 20px; justify-items:center; } .header ul li { padding: 10px; } a { text-decoration: none; color: #000; font-size: 20px; } li { list-style: none; } /* Dropdown Menu Styling*/ .dropdown-menu-hook { position: relative; } .dropdown-menu { width: 120px; height: auto; background-color: #fff; border-radius: 10px; padding: 1rem; position: absolute; top: 45.5px; left: 0; visibility: hidden; pointer-events: all; opacity: 0; color: #000; box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.4); display: flex; align-items: center; } .items { display: flex; flex-direction: column; align-items: flex-start; } .item1, .item2, .item3, .item4 { line-height: 1.2; color:#000; font-weight: 500; padding: 10px; transition: .3s; } .dropdown-menu-hook:hover > .dropdown-menu { visibility: visible; pointer-events: all; opacity: .9; } .dropdown-menu { transition: opacity .5s; } /* Line Animation */ .line-anim { position: relative; width: fit-content; } .line-anim:after { content: ""; background-color: #000; height: 1px; width: 0; left: 0px; top: -5px; transition: 0.4s ease-out; position: absolute; } .line-anim:hover:after { width: 100%; } a:hover > .line-anim { display: block; }
<nav class="header"> <ul> <li><a href="#" class="line-anim">ABOUT</a></li> <li class="dropdown-menu-hook line-anim"> <a href="#" class="">TESTIMONIALS</a> <div class="dropdown-menu"> <div class="items"> <a class="item1" href="#">Item 1</a> <a class="item2" href="#">Item 2</a> <a class="item3" href="#">Item 3</a> <a class="item4" href="#">Item 4</a> </div> </div> </li> <li ><a href="#" class="line-anim">CONTACT</a></li> </ul> </nav>
解决方案
不需要移动.line-anim类的挂载位置,也不需要JavaScript,利用CSS后代选择器,在父级.dropdown-menu-hook处于hover状态时,选中内部的.line-anim::after伪元素设置宽度100%即可,原有过渡动画会完全保留。
只需要在原有CSS代码中新增一行规则:
/* 下拉父容器hover时,保持内部链接下划线激活状态 */ .dropdown-menu-hook:hover > .line-anim:after { width: 100%; }
实现原理
- 鼠标移到下拉菜单上时,hover状态是绑定在父级
.dropdown-menu-hook(li元素)上的,不会因为鼠标离开内部a标签就丢失hover状态 - 原代码只给
.line-anim:hover:after设置了宽度100%,鼠标移到下拉菜单时离开了a标签,该选择器就不生效,导致下划线收回 - 新增的选择器会在父li处于hover状态时,持续让内部a标签的下划线保持100%宽度,同时原有的transition属性正常生效,下划线展开、收回都会保持平滑动画,不会出现硬切效果
- 普通导航项(ABOUT、CONTACT)没有
.dropdown-menu-hook父级,不受该规则影响,原有交互逻辑保持不变
内容的提问来源于stack exchange,提问作者Maryando
相关产品推荐
相关产品推荐

