直接设 width: 0 会导致动画跳变,因浏览器将其坍缩为 0,offsetwidth 无法插值;应使用非零宽度(如 32px)配合 overflow: hidden 和 white-space: nowrap。

为什么直接设 width: 0 会导致动画“啪”一下跳变
浏览器对 width: 0 的处理会让内部文字、padding、border 全部坍缩,offsetWidth 读出来是 0,插值计算失去依据。结果就是 transition 完全失效,视觉上直接跳到目标宽度。
真正可用的收起态宽度必须是非零且明确:比如 width: 32px(刚好容纳放大镜图标),同时配 overflow: hidden 和 white-space: nowrap 防文字换行打断动画节奏。
-
width: 0、display: none、visibility: hidden都不能参与 transition,它们不触发重排动画 - 起始值必须是可计算单位:
32px、2rem可以,auto或100%不行 - transition 声明必须写在默认状态规则里,不能只写在
:focus或展开类中
如何用 max-width 替代 width 避开 flex 干扰
在 flex 容器里给 input 设 flex-grow: 1 再加 transition: width,动画大概率失效——因为 flex-grow 分配的是动态剩余空间,不是可插值的数值类型。
更稳的路径是放弃 width,改用 max-width 控制伸展上限:
- 初始:
max-width: 40px; overflow: hidden; - 展开:
max-width: min(320px, 80vw);(兼顾小屏和留白) - 必须配合
width: 100%,否则max-width不生效 - 这个方案 IE10+ 兼容,且不会被 flex 布局逻辑干扰
移动端点击不到输入框?热区没扩够
收起态 width: 32px 只够放图标,用户点不到 input 本体,iOS Safari 尤其容易 focus 失败,键盘根本打不开。
别用 opacity: 0 + pointer-events: none 隐藏 input——这会彻底切断焦点链。
- 给
input加padding-left: 32px,再用::before绝对定位图标,左侧空白区域也能触发聚焦 - 搜索按钮必须设
flex-shrink: 0,否则小屏下被压缩消失 - 移动端建议把按钮抽成
position: absolute叠在 input 右侧,释放水平空间 - 务必加
box-sizing: border-box,否则padding和border会让视觉宽度超出预期
JS 切换类名时动画卡顿的真实原因
点击后立刻 el.classList.add('expanded'),又马上读 el.offsetWidth,会强制同步重排,动画直接中断。
这不是 CSS 写错了,而是 JS 测量时机不对。
- 正确做法:用
getComputedStyle(el).width读值前,包一层requestAnimationFrame延迟一帧 - 更推荐放弃 JS 测量,改用 CSS 原生状态驱动,比如
:focus-within或:has(input:focus)(Chrome/Firefox/Edge 已稳定支持) - 若需兼容老浏览器,可在 JS 中先读一次
el.offsetWidth强制触发布局,再改 class——但仅限一次,禁止连读连写
真正难的不是写几行 transition,而是控制好宽度变化时内容不换行、图标不位移、焦点不丢失。这些细节全靠 white-space、overflow、box-sizing 和触发时机共同约束。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











