内联样式写 transition 无效是因为浏览器未识别状态变化;需分三步:设初始样式+transition、强制重排(如 offsetheight)、再设目标值;动画应使用 requestanimationframe 而非 setinterval。

transition 用内联样式写无效?检查是否触发了重排
直接在 style 上写 transition 没反应,大概率是因为浏览器没机会“看到”属性变化前后的状态差。CSS 过渡需要两个关键帧:起始值、结束值,且这两个值必须在不同渲染帧中被识别。如果 JS 一口气改完 style(比如先设 left 再设 transition),浏览器可能合并成一次重排,过渡就丢了。
- 必须分两步:先设初始样式(含
transition),再强制触发重排,最后设目标值 - 触发重排最稳妥的方式是读一个会触发 layout 的属性,比如
offsetHeight、getBoundingClientRect() - 别用
setTimeout模拟“等一帧”,它不保证渲染时机,且在高负载下容易失效
element.style.transition = 'left 0.3s ease'; element.style.left = '0px'; // 初始位置 element.offsetHeight; // 强制重排,让浏览器记住这个状态 element.style.left = '100px'; // 此时才会真正过渡
JavaScript 实时计算过渡数值:别用 setInterval 模拟
想手动控制过渡过程(比如根据鼠标位置动态更新 opacity),直接用 setInterval + style 赋值,既卡顿又难对齐真实帧率。浏览器的 requestAnimationFrame 才是唯一能和屏幕刷新同步的机制。
-
requestAnimationFrame回调里读取当前时间戳(performance.now()),结合起始/结束时间算出当前进度比 - 避免用
new Date().getTime(),精度低且受系统时间调整影响 - 过渡函数(ease-in-out 等)建议用现成公式或
css-easing库,别手写三次贝塞尔近似
const start = performance.now();
const duration = 300;
function animate(t) {
const elapsed = t - start;
const progress = Math.min(elapsed / duration, 1);
const eased = 1 - Math.pow(1 - progress, 3); // ease-out-cubic
element.style.opacity = String(eased);
if (progress < 1) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);transitionend 事件监听不到?注意伪元素和继承属性
transitionend 不会冒泡,也不触发于伪元素(::before)、display 变化、或通过 CSS 继承得来的属性(比如 color 从父级继承)。监听失败,八成是目标属性根本没走 CSS 过渡流程。
- 确保监听的是实际发生变化的 DOM 元素,不是父容器
- 检查 computed style,确认
transition-property真的包含你要监听的属性名(如opacity,不是all) -
transitionend在 transition 被取消(如 class 移除)时仍会触发,需用event.propertyName做二次校验 - 不要依赖
event.elapsedTime判断是否完成——它只反映当前 transition 的持续时间,不反映是否真执行完了
内联样式 + transition 性能陷阱:慎用 layout 触发属性
用 top/left 配合 position: relative 做过渡,每次重绘都会触发 layout 计算,滚动或动画密集时掉帧明显。现代浏览器对 transform 和 opacity 有独立合成层优化,应优先用它们。
立即学习“Java免费学习笔记(深入)”;
- 把
left: 100px换成transform: translateX(100px),性能提升通常在 2–5 倍 -
transform和opacity是仅有的两个能进 GPU 合成层的 CSS 属性(其他如filter会触发 raster,开销大) - 如果必须用
top/left,加will-change: top提前提示,但别滥用——它会提前创建图层,内存占用上升
过渡数值实时计算本身不难,难的是让每一步都落在浏览器的渲染节奏里。漏掉一次 offsetHeight,或误监听了继承来的 color,整个动画就静音了。










