三种常见抱怨,其实是同一件事:
- 登录页的密码框被填成了注册时的密码;
- 后台管理界面的输入框突然变成一片浅黄;
- 花半小时做的输入框样式,用户一用自动填充就崩了。
Chrome 判断”这是什么字段”的依据
它看的不是 autocomplete="off",而是 name、id、type、placeholder、label 的文本、以及字段周边的文字。一旦判定为密码 / 地址 / 信用卡,off 会被直接忽略——这是既定行为,不是 bug,提 issue 也没用。
能动的是语义,不是开关:
<input type="password" name="new_pass" autocomplete="new-password">
<input type="password" name="confirm" autocomplete="new-password">
注册 / 改密码场景用 new-password,登录场景用 current-password。两个密码框都要写,只写第一个不够——实测第二个仍会被填进旧密码。
浅黄背景的来路
那是 UA 的 :-webkit-autofill 伪类,浏览器用自己的背景色盖住你的 background。你不能直接改 background-color,只能”盖一层不透明的阴影”:
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
-webkit-text-fill-color: #1f2328; /* 文字色也得单独改 */
-webkit-box-shadow: 0 0 0 1000px #fff inset; /* 用阴影覆盖背景 */
transition: background-color 9999s ease-in-out 0s; /* 老版本保险 */
}
0 0 0 1000px 的意思是一个 1000px 的 inset 阴影——足够大,能盖满整个输入框。标准伪类是 :autofill,Firefox 和 Safari 认,Chrome 现在也支持,两个都写更稳。
怎么知道用户用了自动填充
监听 input 事件不够可靠——自动填充的某些阶段不触发它。业界用了很多年的办法是借一个空动画:
@keyframes onAutoFillStart { from {} to {} }
input:-webkit-autofill { animation-name: onAutoFillStart; animation-duration: 1ms; }
document.addEventListener('animationstart', (e) => {
if (e.animationName === 'onAutoFillStart') {
console.log('被自动填充了:', e.target);
}
}, true); // 注意第三参数 true,事件在捕获阶段才能拿到
动画名命中就说明 UA 给它套上了 :-webkit-autofill。这个技巧不依赖任何私有 API,改版也难失效。
我的取舍
与其跟浏览器对抗,不如承认用户的数据已经在浏览器里了,把”被填充后的样子”也调好看。真正需要对抗的只有一个场景:注册页的密码框被填成了旧登录密码——那个用 new-password 就够了,不需要 off,也不需要 JS 清空。
顺便一提,那些”用 JS 定时清空输入框”的方案副作用都很大:用户自己输入到一半的内容也会被吞掉,还会让密码管理器反复弹窗。能不写就不写。