transition必须写在基础选择器中而非:hover等伪类里,且所有参与过渡的属性需显式声明初始值,否则首次变化会跳变;不可过渡属性如display、height:auto需用opacity、transform或max-height替代。

transition写在:hover里,第一次变化必然跳变
浏览器只在属性值变化时触发过渡,但前提是transition声明必须从变化前就存在。如果只写在:hover、:active或某个状态类中,那鼠标移入或JS加类的瞬间,浏览器还没“记住”要过渡——它直接把新值渲染出来,动画根本没机会启动。
常见错误写法:.btn:hover { background-color: #007bff; transition: background-color 0.3s; }。这样移入是瞬切,移出才可能带动画(还不稳定)。
- 正确做法:把
transition放在基础选择器里,例如.btn { transition: background-color 0.3s ease; } - 验证方式:打开 DevTools → Elements → Computed 面板,搜索
transition-property,确认它在元素常态下就存在,而不是只在 hover 后才出现
目标属性没有显式初始值,浏览器无法算起点
过渡需要明确的起点和终点才能插值。如果某个属性初始值是auto、initial或压根没声明(比如left未设值,默认为auto),浏览器无法计算中间帧,就会直接跳变。
典型表现:第一次 JS 切 class 或 hover 时“啪”一下到位,第二次才动起来。
- 必须显式写出初始值,例如
.box { left: 0; width: 100px; opacity: 1; transition: left 0.3s, width 0.3s, opacity 0.3s; } - 特别注意:
width、height、top、left、margin等布局属性极易踩坑;auto和unset都不能作为过渡起点 - 用 Computed 面板确认当前值不是
auto或initial,尤其是从 JS 动态插入的元素,容易漏掉初始样式
JS 添加类名后立即重排失败,浏览器没机会读旧值
CSS transition 不是“类一加就动”,它依赖两次样式设置之间存在浏览器重排(re-layout)机会。如果 JS 加完 class 立刻进入下一帧,浏览器会把读旧值和写新值合并成一次渲染,跳过过渡。
- 补救方式:在设新类前加
el.offsetHeight或void el.offsetWidth强制同步读取布局,让浏览器“拍下旧快照” - 示例:
el.classList.add('fade-in'); void el.offsetWidth; // 强制重排 el.classList.add('active'); - 在 Vue/React 中,需确保 DOM 更新完成后再触发过渡,比如 Vue 的
nextTick、React 的flushSync
用了不可过渡的属性,写了transition也白搭
不是所有 CSS 属性都支持过渡。浏览器只对可计算中间值的属性支持插值,像display、z-index、position、height(当值为auto时)这些,写了transition也无效,还不报错。
- 典型错误:
transition: height 0.3s;+height: auto;→ 完全不动 - 可安全过渡的属性包括:
color、background-color、opacity、transform、margin、padding、font-size等 - 替代方案:
height改用max-height(设一个足够大的固定值);display切换改用opacity+transform+overflow: hidden
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











