案例
点击开始按钮,让div执行动画。一个简单的demo来试一下回流重绘应用场景。
开始简单的布局
<div class="box"></div>
<button id="btn">开始</button>
html,
body {
height: 100%;
}
body {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 20px;
}
.box {
width: 100px;
height: 100px;
background: #badc58;
}
点击实现动画
这里的动画就用css实现,通过给div加上一个类名,这个类名里面包含了动画;现在只需要点击按钮给div加类名即可
.box.animate {
animation: jump 500ms ease-in-out;
}
@keyframes jump {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
const btn = document.querySelector("#btn");
const box = document.querySelector(".box");
btn.addEventListener("click", () => {
box.classList.add("animate");
});
回流的使用
动画可以实现,但是只能实现一次,因为第一次过后类名就会保留下来,再次点击也不会有效果。
那我们就可以想到,每次点击的时候先把类名干掉,再重新加上去.
btn.addEventListener("click", () => {
box.classList.remove("animate");
box.classList.add("animate");
});
发现和之前一样,还是只有第一次可以动起来;这是为什么呢?因为我们删除和添加操作一瞬间完成的。浏览器不会感知到页面的变化,自然不会重绘;那我只能让它强制重绘,给它补一个回流(回流必重绘)。
btn.addEventListener("click", () => {
box.classList.remove("animate");
// 让浏览器强制回流,哪些操作可以让浏览器回流,可以看下面的介绍。
void box.offsetWidth;
box.classList.add("animate");
});
哪些操作会执行回流呢
-
DOM的增删行为
比如你要删除某个节点,给某个父元素增加子元素,这类操作都会引起回流。如果要加多个子元素,最好使用documentfragment。 -
几何属性的变化
比如元素宽高变了,border变了,字体大小变了,这种直接会引起页面布局变化的操作也会引起回流。如果你要改变多个属性,最好将这些属性定义在一个class中,直接修改class名,这样只用引起一次回流。 -
元素位置的变化
修改一个元素的左右margin,padding之类的操作,所以在做元素位移的动画,不要更改margin之类的属性,使用定位脱离文档流后改变位置会更好。 -
获取元素的偏移量属性
例如获取一个元素的scrollTop、scrollLeft、scrollWidth、offsetTop、offsetLeft、offsetWidth、offsetHeight之类的属性,浏览器为了保证值的正确也会回流取得最新的值,所以如果你要多次操作,最好取完做个缓存。 -
页面初次渲染
这样的回流无法避免 -
浏览器窗口尺寸改变
resize事件发生也会引起回流。