移动端搜索框展开动画需设最小宽度32px保焦点,用max-width替代width实现响应式,js控制is-expanded类名管理焦点与收起时机,并通过will-change或transform优化渲染性能。

移动端搜索框用 width + transition 展开会丢焦点、裁图标
直接设 width: 0 再过渡到 width: 240px 在 iOS Safari 和部分 Android Chrome 上大概率失效:输入框视觉消失后无法聚焦,软键盘打不开;图标被压扁或错位;动画中途跳变。根本原因是 width: 0 让元素脱离正常布局流,浏览器无法稳定计算渲染中间帧。
必须保留最小可交互尺寸:width: 32px(刚好容纳放大镜图标),配合 overflow: hidden 和 white-space: nowrap。这样 input 始终可点击、可聚焦,动画插值也稳定。
- 初始状态写死
width: 32px,不要用0或auto -
transition必须写在 input 元素自身上,如transition: width 0.3s ease-in-out,单位px不可省略 - 收起态加
padding-left: 32px,再用::before绝对定位图标,扩大热区——否则用户点不到 32px 宽的区域
为什么 max-width 比 width 更适合响应式展开
max-width 不强制重排内容流,只限制伸展上限,天然适配不同屏幕。比如写 max-width: min(320px, 80vw),PC 上最多撑到 320px,小屏则自动缩到视口宽度的 80%,不用写媒体查询。
但要注意:max-width 动画必须搭配 overflow: hidden,且起始值不能是 0(同 width 问题)。稳妥起手值是 max-width: 40px,刚好包住图标+微留白。
- 展开时设
max-width: min(320px, 80vw),比固定像素更鲁棒 - 避免同时过渡
padding或border—— 它们和max-width不同步,会导致视觉撕裂 - 父容器不能有
overflow: hidden且高度固定,否则动画会触发意外重排
:focus 在移动端不可靠,必须用 JS 切换类名
Safari iOS 常不触发 :focus 伪类,尤其软键盘弹出后失焦再聚焦;Android Chrome 某些版本对快速点击响应滞后。纯 CSS 的 .search-input:focus 方案在真机上失败率高。
正确做法是用 JS 监听 focus 和 blur,手动加/删类名,比如 is-expanded。CSS 里写 .search-box.is-expanded .search-input 覆盖样式,控制力更强。
- blur 后别立刻收起:加
setTimeout(() => el.classList.remove('is-expanded'), 150),防止点击清空按钮时误收 - input 要加
tabindex="0",确保非点击方式(如键盘 Tab)也能触发 - 避免用
display: none或visibility: hidden做收起——它们不支持 transition,且会中断焦点链
动画卡顿的真正原因不是写法,而是渲染层没切对
即使 transition 写得完全正确,动画仍可能卡顿,常见于 Safari。这不是代码 bug,而是浏览器把 width 或 max-width 变更判定为“需要重排”的操作,没走 GPU 合成层。
最有效的提速手段是:在展开瞬间给 input 加 style="will-change: width"(注意仅限展开态,收起后要移除),或改用 transform: scaleX()(需配合 transform-origin: left center)。后者硬件加速更稳,但需额外处理文字缩放失真。
- 用 Chrome DevTools 的 Rendering 面板勾选 “Paint flashing”,看是否整行重绘 —— 如果是,说明
width动画正拖慢主线程 -
will-change是“提示”,不是万能药;滥用反而降低性能,只在动画开始前动态添加 - 真正难调的不是动画本身,是让文字不换行、图标不位移、焦点不丢失这三件事同时成立 —— 它们依赖
white-space、overflow、box-sizing和 JS 触发时机共同约束
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











