:focus触发宽度过渡最简单可靠,核心是监听焦点;初始态用非零宽度(如32px)配合overflow:hidden,展开态:focus设width:240px,transition需在默认规则中声明且避免被全局样式覆盖。

用 :focus 触发宽度过渡最简单可靠
不用写 JS,点一下输入框就展开,核心就是监听焦点。浏览器对 :focus 的支持极好,且原生 <input type="search"> 点击即聚焦,行为稳定。
常见错误是直接写 width: 0 → width: 240px,结果动画一闪而过或根本不动——因为 width: 0 会让元素坍缩,offsetWidth 变成 0,浏览器失去插值依据。
- 初始态用非零宽度,比如
width: 32px(刚好放图标),加overflow: hidden和white-space: nowrap - 展开态写
&:focus { width: 240px; },别用100%,flex 容器里容易撑破 - 必须声明
transition: width 0.25s ease在默认规则里,不能只写在:focus中 - 加
box-sizing: border-box,否则padding会额外增加宽度,导致动画终点不准
父容器是 display: flex 时别硬刚 width
Flex 容器会劫持子项的尺寸计算逻辑,width 动画常被忽略或跳变。尤其在移动端键盘弹出后,resize 事件可能让布局重排错乱。
更稳的做法是换用 max-width 控制伸展上限,它不参与 flex 分配,只管视觉裁剪。
- 初始:
max-width: 40px; width: 100%; overflow: hidden; - 展开:
&:focus { max-width: min(280px, 80vw); } - 必须配
width: 100%,否则max-width不生效 - 如果父容器有
padding,记得加box-sizing: border-box
想点击按钮再展开?JS 切类比内联样式安全
需要按钮控制、或要兼容 iOS Safari 的 focus 失效问题时,就得用 JS。但别直接操作 style.width,否则动画无法回退。
典型结构是按钮 + 独立的搜索容器,靠 class 切换驱动 CSS 过渡:
<button id="search-toggle">?</button> <div id="search-wrapper"> <input type="search" placeholder="Search"> </div>
- CSS 中定义
#search-wrapper { transition: width 0.25s ease-in-out; width: 0; overflow: hidden; white-space: nowrap; } - 展开类:
#search-wrapper.open { width: 220px; } - JS 用
element.classList.toggle('open'),不要用element.style.width = '220px' - 移动端注意:触发后立刻调用
input.focus(),确保软键盘弹出
圆角和动画卡顿是连带问题
只动 width 会让短态和长态的圆角看起来割裂——短的时候用 border-radius: 16px,长的时候用 24px 更自然,但必须和 width 共享同一 transition 声明。
最容易被忽略的是全局样式覆盖。比如 Tailwind 或 Normalize.css 里写了 transition: all 0.2s,就会把你写的 transition: width 0.25s 覆盖掉,导致所有属性都动(包括 background-color),动画变糊。
- 显式写出要过渡的属性:
transition: width 0.25s ease, border-radius 0.25s ease; - 去掉默认 outline:
outline: none,否则蓝色焦点框会干扰圆角视觉 - 移动端用
transition-timing-function: ease-out展开,收起用ease-in,比统一ease更顺滑 - iOS Safari 有时不触发
:focus,得靠 JS 补位,别全押在伪类上
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











