text-decoration不支持transition,需用border-bottom+scalex()模拟滑动下划线;tab激活态须js控制is-active类,配合transition-transform实现精准跟随与顺滑回弹。

为什么直接用 text-underline 无法滑动
加了 hover:underline 或 text-underline,下划线只会“啪”一下出现或消失,没有滑动过程。因为 text-decoration(包括 text-underline)在所有主流浏览器中都不支持 transition,CSS 规范里它就不是可动画属性。你看到的所谓“动画”,其实是浏览器强制重绘,毫无过渡可言。
正确做法:用 border-bottom + scaleX() 模拟滑动线
核心是把下划线变成一个独立、可控的视觉元素,再用 transform: scaleX() 控制它的伸展。Tailwind 本身不提供原生的“滑动下划线”类,但你可以组合出稳定、高性能的效果:
-
relative加在 tab 容器(如<div class="relative">)上,为绝对定位的下划线提供定位上下文 <li>下划线用伪元素 <code>::after或<span></span>实现;推荐伪元素,更轻量 - 初始状态设
scaleX(0)、origin-left,悬停时变为scaleX(1) - 必须配
transition-transform duration-300 ease-out—— 注意duration-和ease-类要写在常态元素上,不能只放在hover:后面,否则鼠标移出时会直接跳回
示例结构:
<div class="relative inline-flex space-x-6">
<a href="#" class="relative py-2 px-1 font-medium text-gray-500 hover:text-gray-900">
首页
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-blue-500 origin-left scale-x-0 transition-transform duration-300 ease-out group-hover:scale-x-100"></span>
</a>
<a href="#" class="relative py-2 px-1 font-medium text-gray-500 hover:text-gray-900">
关于
<span class="absolute bottom-0 left-0 w-full h-0.5 bg-blue-500 origin-left scale-x-0 transition-transform duration-300 ease-out group-hover:scale-x-100"></span>
</a>
</div>
Tab 切换场景下,如何让下划线「精准跟随当前激活项」
纯 hover: 只能响应鼠标,而 Tab 切换通常需要 JS 控制的「当前选中态」。这时不能依赖 group-hover,得改用 JS 切换 class:
- 给每个 tab 项加一个统一基础类,比如
tab-item - 用 JS 在点击后给当前项添加
is-active类(而不是靠hover:) - 下划线元素的显示逻辑改为
is-active:<span-class></span-class>,例如:is-active:scale-x-100 - 确保
transition-transform和duration-依然写在常态类里,否则切换 class 后离开时不会回弹动画
关键点:不要用 hidden/block 控制下划线显隐——hidden 是 display: none,不可过渡。始终用 scaleX(0) → scaleX(1) 这种 transform 方式。
容易被忽略的细节和兼容性坑
实际部署时最容易栽在这几个地方:
- 父容器没设
relative:伪元素或<span></span>的absolute定位会错位到 body 顶部,下划线飘走 - 用了
border-bottom直接做动画:别写border-b-0 hover:border-b-2,这会触发 layout 重排,卡顿明显;必须用transform或height + opacity替代 - 移动端 iOS Safari 对
hover支持极差:Tab 切换交互优先用active:或 JSis-active,别指望纯 hover - 多个 tab 共享同一根下划线?可以,但要用 JS 动态更新
left和width,此时scaleX不适用,得切回transition-all+width/left,但注意性能——务必加will-change: transform或改用transform: translateX()模拟位移
真正顺滑的滑动效果,从来不是靠堆属性,而是选对可动画属性、控制好定位上下文、并把 transition 参数稳稳落在常态类上。一旦漏掉其中一环,看起来就像卡顿或突然跳变。











