:focus颜色未变是因outline被覆盖,需检查computed styles并手动设置outline;:valid/:invalid依赖type/required等原生属性;优先用纯css状态伪类,复杂逻辑用js;border过渡避开:invalid以提升体验。

input:focus 时颜色没变?检查 :focus 是否被其他样式覆盖
浏览器默认的 :focus 样式很弱,常被 CSS 重置或第三方库(比如 Bootstrap)的 outline: none 干掉。不是你写错了,是它被悄悄禁用了。
- 先在开发者工具里选中输入框,看 computed styles 里
outline是否为none或0 - 手动加一句
input:focus { outline: 2px solid #007bff; }测试是否生效 - 如果用了
box-shadow模拟焦点边框,记得加上outline: none避免双焦点环 - 别只写
input:focus,考虑textarea:focus和select:focus也需统一处理
valid/invalid 状态不触发?确保表单控件有 type 和 required 属性
CSS 的 :valid 和 :invalid 不是靠 JS 判断的,而是依赖原生表单校验逻辑——没 type、没 required、没 pattern,浏览器根本不会标记状态。
-
type="email"才会校验邮箱格式;type="text"即使填了 @ 符号也不会变:valid -
required是关键:空值时:invalid立刻生效;没加它,空输入永远算:valid -
pattern必须是完整正则(如pattern="[0-9]{6}"),开头结尾不加/ - 注意:用户未交互前,部分浏览器对空必填项仍视为
:valid(可加:user-invalid补充,但兼容性有限)
用 JS 动态改 class 还是纯 CSS?优先用 :valid/:invalid + :user-invalid
纯 CSS 方案更轻量、无 JS 依赖、支持服务端渲染,但得接受它的行为边界:它只响应原生校验,不响应自定义规则(比如“两次密码不一致”)。
- 简单场景(必填、邮箱、手机号)直接用
input:valid { border-color: #28a745; } - 复杂逻辑必须 JS 控制:给元素加
data-status="error",再写input[data-status="error"]规则 - 避免同时用 JS 改
className和 CSS 的:invalid——状态可能打架,比如 JS 清除了 error class,但 input 仍为空,:invalid又生效 - 移动端要注意:iOS Safari 对
:user-invalid支持较晚(iOS 15.4+),旧版本得降级用 JS
border 颜色切换太突兀?加 transition 但避开 invalid 状态的瞬时变化
transition: border-color .2s 能让变色柔和,但 :invalid 在输入瞬间就触发,容易造成“刚打字就变红”的压迫感。
立即学习“前端免费学习笔记(深入)”;
- 只对
:focus和:valid做过渡,:invalid保持无 transition——错误反馈需要明确及时 - 更稳妥的做法:用
input:not(:placeholder-shown):invalid,等用户开始输入后再激活红色边框 - 别给
outline加 transition,Safari 对 outline 过渡支持不稳定,容易闪动 - 深色模式下测试颜色对比度,
#dc3545在暗背景上可能看不清,建议用hsl(0, 60%, 50%)之类可调变量
真正难的不是怎么变色,而是判断什么时候该变、变给谁看——用户还没输完就标红,和输完了还不提醒,同样让人困惑。状态颗粒度和反馈时机,比颜色本身重要得多。










