transition 在 class 切换时未生效,主因是浏览器未能识别连续样式变化:display 变化、强制重排、未声明 transition-property、依赖 transition: all、伪类退出无过渡、transition-delay 误用等。
直接改 className 但过渡不动,大概率是因为浏览器没把「旧样式→新样式」识别为可过渡的连续变化。常见原因是:切换前后元素的 display 值不同(比如从 none 切到 block),或新 class 的样式在首次应用时被强制同步计算(例如读取 offsetHeight 后立刻改 class),导致过渡链被中断。
opacity、transform、background-color),且没有 display: none / visibility: hidden 这类“硬切”行为offsetTop、getBoundingClientRect() 等),否则会强制同步计算,清空过渡队列setTimeout(() => { 添加 class }, 0) 或 queueMicrotask 把 class 切换推到下一帧transition: all 0.3s ease 看似省事,但实际中经常失效——尤其当目标属性在旧 class 中未声明(值为初始值 auto、normal 或 inherit),浏览器无法确定起始状态,过渡就跳过。
transition: opacity 0.3s ease, transform 0.3s ease

opacity: 1,目标是 opacity: 0)all 处理 height、width 等需要精确数值的属性;它们从 auto → 数值不可过渡,应改用 max-height 或 transform: scaleY()
如果用 :active 写点击过渡(比如按钮按下去变色),松开后样式立刻复原,看起来像没过渡——这是因为 :active 是瞬态伪类,浏览器不会对它的退出做过渡处理,只对进入生效。
is-pressed),配合 click 或 touchstart/touchend 事件手动增删touchstart 后需 preventDefault() 防止延迟 300ms,否则过渡感知卡顿:active,改用 is-holding 类 + setTimeout + clearTimeout
加了 transition-delay: 0.5s 却发现点击后等半天才动?这是预期行为,但容易误判为失效。更隐蔽的是:父元素或祖先元素设置了 transition-delay,会继承影响子元素(虽然 transition 本身不继承,但 delay 值可能被意外复用)。
transition,确认生效的 delay 值是否来自当前元素.card)里写带 delay 的 transition,除非明确需要统一延时outline: 1px solid red 等视觉标记,确认 class 是否真的被添加/移除.button {
opacity: 1;
transform: scale(1);
transition: opacity 0.2s ease, transform 0.2s ease;
}
.button.is-active {
opacity: 0.7;
transform: scale(0.95);
}
过渡真正起作用的前提,是浏览器能拿到两个确定的数值状态,并且中间没有 layout 强制刷新或属性不可插值。很多“失效”其实不是 CSS 写错了,而是 JS 操作时机或 DOM 状态干扰了渲染流水线。