纯 CSS 无法实现真正下划线跟随鼠标滑动,因 :hover 不能跨元素联动、CSS 无运行时坐标读取能力,所谓“跟随”实为各链接独立触发 ::after 动画,存在消失再出现的断层,且无法动态适配不同宽度导航项位置。

纯 CSS 实现“下划线跟随鼠标滑动”是伪命题——:hover 无法跨元素联动,浏览器不支持用 CSS 动态读取兄弟元素的 getBoundingClientRect()。所谓“0行 JS”的方案,实际只是每个链接独立展开自己的下划线,不是真正跟随。
为什么纯 CSS 的 ::after + transition 不算“跟随”?
这类写法(如给每个 a 加 ::after 并 transition: width)本质是“单点触发”,下划线只在当前链接下方出现、展开,不会从上一个链接平滑移动到下一个。鼠标从“首页”移到“关于”时,下划线会先消失再在新位置出现,中间有断层。
- 它依赖
a:hover::after,作用域仅限于自身,无法让父容器里一个共享的下划线元素响应变化 -
left或transform: translateX()若写死在 CSS 里,就无法适配不同宽度的导航项 - 即使借助
:has()(如nav:has(a:hover)::after),目前也无法获取 hover 元素的运行时坐标,CSS 没有变量反射机制
transform: translateX() 为什么比 left 更可靠?
下划线 DOM 节点一旦确定,它的位移必须只触发合成(composite),避免重排。直接改 left 在 flex 或有 transform 的父容器中极易计算失准,且强制同步布局。
-
transform属于合成属性,由 GPU 加速,动画更顺滑 - 计算位移时必须用
target.getBoundingClientRect().left - container.getBoundingClientRect().left,不能用offsetLeft - 初始
transform: translateX(-100%) scaleX(0)可隐藏元素,避免页面加载时闪一下 - 务必在
requestAnimationFrame中更新样式,否则可能触发 forced reflow
移动端必须绕开 :hover 的三个事实
iOS Safari 对非可点击元素的 :hover 响应极不可靠,尤其在无 touchstart 触发的前提下。纯 CSS 方案在真机上基本失效。
立即学习“前端免费学习笔记(深入)”;
- 导航项需加
role="button"和tabindex="0",让 Safari 认为它是可聚焦/可交互元素 - 必须监听
touchstart+click双事件,并用preventDefault()防止双击缩放 - 不要依赖
mouseenter/mouseleave,移动端没有 mouse 事件流;改用focus/blur+touchstart组合
真正平滑跟随的关键不在过渡写法,而在坐标计算是否在正确时机、用正确 API 拿到了正确值——getBoundingClientRect() 返回的是视口坐标,减去容器坐标才是相对位移,这个差值一旦错 1px,下划线就会偏移。别省略 Math.round(),亚像素渲染会让线条模糊或抖动。


















