正确做法是用绝对定位label模拟placeholder,input:focus时对其应用transform和opacity过渡,同时设置input的padding-top预留空间、显式声明transform-origin,并用for/id绑定确保可访问性。

input:focus 时 placeholder 怎么平滑上移
必须用 ::placeholder 配合 :focus-within 或 :focus 控制显隐,不能靠 JS 模拟位移。原生 placeholder 文本本身不参与布局,直接对它做 transform 无效——它只是伪元素,且浏览器限制其可动画属性极少。
正确做法是:把占位符文字“借”给一个额外的 label 元素,用绝对定位覆盖在 input 上;input 获焦后,给这个 label 加 transform: translateY(-1.2em) scale(0.85) 和透明度过渡。
-
label必须设pointer-events: none,否则会拦截 input 点击 - transition 要写在 label 默认状态里,不是 :focus 里,否则首次聚焦无动画
- scale 缩放建议用 0.85~0.9,太小看不清,太大和输入框文字比例失调
label 和 input 怎么绑定才不影响可访问性
用 for 属性绑定 id 是最稳妥的,比包裹式(<label><input></label>)更可控。尤其当 label 需要绝对定位、脱离文档流时,包裹结构容易导致焦点管理异常或屏幕阅读器误读。
常见错误是 id 写错、漏写 for,或 JS 动态生成 input 后没同步更新 label 的 for 值——这会让 Enter 提交时 label 失效,甚至影响表单验证的关联提示。
立即学习“前端免费学习笔记(深入)”;
- input 必须有
id,label 的for值必须与之完全一致(区分大小写) - 不要用 class 名或 data 属性模拟绑定,辅助技术不识别
- 如果 input 是 disabled 状态,label 也要加
aria-disabled="true"
placeholder 上移后怎么避免遮挡输入内容
关键在 input 的 padding-top。label 上移后,若 input 顶部没留空,用户输入的第一行文字会和 label 下沿重叠。这不是 z-index 问题,是盒模型挤压。
推荐方案:默认状态下 input 的 padding-top 设为足够容纳 label 高度(比如 1.2em),获焦后保持不变;label 则用 top: 0.4em + transform 上移,这样两者始终错开。
- 别依赖 margin-top 推 input,会导致整体高度跳变,影响父容器布局
- line-height 和 font-size 差异大的时候,用 em 单位比 px 更可靠
- 移动端需额外测试 iOS Safari,它的
::placeholder渲染位置偶尔偏下 1px
Chrome 和 Safari 对 transform-origin 处理不一致怎么办
Safari 默认以左上角为 transform-origin,Chrome 通常按中心,这会导致同样 transform: translateY(-1em) scale(0.85) 在 Safari 里 label 上移不足、文字被裁切。必须显式声明 origin。
统一设成 transform-origin: top left 最安全——因为 label 是绝对定位、宽高固定,从左上角缩放+位移,行为最可预测。
- 不要省略
transform-origin,哪怕只写transform - 如果 label 用了
text-align: center,origin 改成top center,但需同步调整left值居中 - Firefox 115+ 已对齐 Safari 行为,旧版本不用单独 hack










