form-control.is-invalid加transition无效是因为Bootstrap 5校验反馈依赖JS动态添加类,而默认样式未定义过渡;需用:invalid/:valid伪类+@keyframes实现抖动与边框渐变动画,并注意移动端兼容及display限制。

为什么 form-control.is-invalid 加了 transition 也不动?
因为 Bootstrap 5 的校验反馈是靠 JS 动态添加 is-invalid 类触发的,但默认样式里根本没写任何 transition。你直接给 .form-control.is-invalid 加 transition: border-color .2s ease 是无效的——它只控制“类存在时”的状态,不控制“类从无到有”那一瞬间的入场动效。
必须用 :invalid + :focus 组合伪类触发动画
真正可控的入口是原生表单验证伪类,配合自定义动画类手动接管。关键点有三个:
-
:invalid:not(:focus)定义失焦时的错误态(比如红边+抖动) -
:valid:focus或:user-invalid:focus控制聚焦中修正时的过渡(比如边框渐变回绿色) - 抖动效果必须用
@keyframes配合animation,不能只靠transform过渡(后者只适用于连续变化)
示例(放在自定义 CSS 最后):
@keyframes shake {
0%, 100% { transform: translateX(0); }
25% { transform: translateX(-2px); }
50% { transform: translateX(2px); }
75% { transform: translateX(-2px); }
}
.form-control:invalid:not(:focus) {
animation: shake .3s cubic-bezier(.36,.07,.19,.97) both;
border-color: #dc3545;
}
.form-control:valid:focus {
border-color: #28a745;
transition: border-color .2s ease;
}
JS 层要禁用默认 setCustomValidity 的静默覆盖
如果你用 input.setCustomValidity('') 清空错误,会触发浏览器重置 :invalid 状态,但动画不会自动反向播放。常见陷阱:
- 只调
setCustomValidity('')不手动移除抖动类,导致动画残留 - 在
input上监听input事件时,未用requestAnimationFrame延迟重绘,抖动帧率错乱 - 忘记对
textarea和select单独处理,它们的:invalid行为不一致
稳妥做法是:在 JS 校验通过后,先移除 animation,再设空值:
input.addEventListener('input', () => {
if (input.checkValidity()) {
input.style.animation = 'none';
setTimeout(() => input.style.animation = '');
input.setCustomValidity('');
}
});
移动端 Safari 的 :user-invalid 兼容性要兜底
iOS 15.4+ 才支持 :user-invalid,老版本仍依赖 JS 添加 is-invalid。所以最终方案得双轨并行:
- CSS 层用
:invalid:not(:focus)覆盖现代浏览器 - JS 层监听
invalid事件,动态加is-invalid-animated类,并配独立动画规则 - 所有动画 duration 必须 ≤ 300ms,否则 iOS 触摸反馈延迟明显
最易被忽略的是:Bootstrap 的 .invalid-feedback 默认 display: none,而 CSS 动画无法驱动 display 变化。必须改用 opacity + visibility + max-height 三属性联动,否则提示文字会“闪现”而非淡入。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











