结论:用 width 配合 :focus 做过渡基本不可靠,因 width: auto 无法参与插值计算,导致跳变;推荐改用 max-width 过渡,并确保父容器有明确宽度约束。

直接说结论:用 width 配合 :focus 做过渡基本不可靠,90% 的“没动画”“一闪就变”问题都出在这里——width: auto 无法参与 CSS 插值计算。
为什么 transition: width 0.3s 经常失效
浏览器对 width 的过渡要求很严格:起始值和结束值都必须是可插值的数值(如 120px → 280px),但绝大多数搜索框初始写的是 width: auto 或没设宽度,导致:
-
auto → 240px被当成“不可动画”,直接跳变,无过渡 - 即使写了
width: 100%,父容器宽度不确定时,100% 也等效于auto,照样跳 -
transition: all 0.3s更危险:它会尝试过渡display、visibility等不可动画属性,拖慢渲染甚至触发重排
推荐方案:用 max-width 替代 width
max-width 是可动画的,且天然兼容“默认窄、聚焦后撑开”的交互逻辑,无需 JS,IE10+ 全支持。
- 初始状态设小
max-width(如140px),同时保持width: 100%占满父容器 -
:focus时放大max-width(如320px),元素自动伸展但不溢出 - 务必加
overflow-x: hidden,防止长输入内容撑破边界或出现横向滚动条 - 过渡函数建议用
cubic-bezier(0.4, 0, 0.2, 1),比ease更顺滑,尤其适合轻量输入交互
.search-input {
width: 100%;
max-width: 140px;
transition: max-width 0.25s cubic-bezier(0.4, 0, 0.2, 1);
overflow-x: hidden;
}
.search-input:focus {
max-width: 320px;
outline: none;
border-color: #007bff;
}
移动端点击无反应?检查这几个硬性条件
iOS Safari 和部分安卓 WebView 对 :focus 触发很挑剔,不是加了 transition 就万事大吉:
立即学习“前端免费学习笔记(深入)”;
-
<input>不能有pointer-events: none或tabindex="-1" - 如果套了
<label>,必须确保for属性与input的id完全一致(大小写敏感) - iOS 下若字体小于
16px,系统可能自动缩放页面,导致动画错位;加font-size: 16px+<meta name="viewport">中设maximum-scale=1.0 - 避免用
transform: scaleX()模拟拉伸——光标定位会偏移,软键盘弹起后焦点丢失
更健壮的替代:flex 布局下的 flex 过渡
如果输入框和按钮共处一个 display: flex 容器,用 flex 属性控制伸缩比写死宽度更自然:
- 初始设
flex: 0 0 120px(不放大、不缩小、基准宽 120px) -
:focus时改为flex: 1,自动占满剩余空间 - 必须显式写
transition: flex 0.3s ease,否则仍是突变 - IE10/11 对
flex过渡支持弱,建议加-ms-flex前缀或降级回max-width方案
真正容易被忽略的点是:所有这些方案都依赖父容器有明确宽度约束。如果外层是 display: inline 或未设 width/min-width 的块级容器,width: 100% 和 flex: 1 都会失效——动画看起来“没动”,其实是根本没空间可伸。


















