CSSTransition内联过渡时长异常:文本上浮动画反向回退
这个问题的核心在于内联样式和CSS类在过渡属性生命周期上的差异,咱们一步步拆解原因和解决方案:
首先说为什么CSS里设置时长正常:
你在.diff-enter-active类里定义的transition-duration是和这个类绑定的——动画活跃阶段这个类存在,过渡生效;动画结束后CSSTransition会移除这个类,元素的过渡属性也就跟着消失了。当onEntered触发后,prev更新导致diff变为0,in属性切换为false,此时元素要回到.diff类的默认样式:visibility: hidden和默认的transform: translate(0,0)。因为过渡属性已经没了,这个变化是瞬间完成的,所以你看不到回退,元素直接隐藏。
而用内联样式设置transitionDuration时就不一样了:内联样式是直接附着在元素上的,不会随着diff-enter-active类的移除而消失。当进入exit阶段,元素从动画后的translate(0,-100%)回到默认位置时,过渡属性依然有效(浏览器会保留之前的过渡属性配置,或者默认过渡所有变化的属性),所以就会触发反向的过渡动画,也就是你看到的“回退”,之后才会隐藏。
最优解决方案:用CSS变量统一维护时长
既遵循DRY原则,又完美避开内联样式的坑。只需两步:
- 在JS里给元素设置CSS变量,把
timeout值传进去:
const AnimatedDiff = ({value}) => { const [prev, setPrev] = React.useState(value) const diff = value - prev const diffSign = diff > 0 ? '+' : '' const diffStr = diffSign + diff const timeout = 800 return ( <CSSTransition classNames='diff' timeout={timeout} in={diff > 0} onEntered={() => setPrev(value)} > <div className='diff' style={{'--transition-duration': `${timeout}ms`}} > {diffStr} </div> </CSSTransition> ) }
- 在CSS里通过变量引用时长:
.diff { position: absolute; right: 0; visibility: hidden; } .diff-enter-active { visibility: visible; transform: translate(0, -100%); transition: transform var(--transition-duration); }
这样,时长只在JS的timeout变量里维护一次,CSS自动引用,完全符合DRY,而且过渡属性依然和diff-enter-active类绑定,动画结束后自动消失,不会出现反向回退的问题。
如果你坚持用内联样式(不推荐)
可以给exit阶段添加样式,强制元素保持动画后的位置直到隐藏:
.diff-exit-active { visibility: hidden; transition: visibility 0ms linear var(--transition-duration); transform: translate(0, -100%); /* 锁住动画后的位置,避免回退 */ }
但这种方式需要额外维护exit样式,不如CSS变量简洁。
内容的提问来源于stack exchange,提问作者dhmk083

