I found chrome will do a huge Recalculate Style
and Pre-Paint
for existing animations when I start a new animation wherever on the page. Is this by design or a Chromium bug? Imagine my real web page has thousands of DOM nodes and hundreds of existing animations, doing such animation invalidation will cause a huge CPU spike. Any ways I can avoid this?
PS:
- normally chrome devtools won't show invalidation detail, go to devtools settings > Experiments > check
Performance panel: invalidation tracking
, and there you go. - I deliberately throttled cpu 20 times down to clearly show the problem cause the repro has much less DOM nodes than real scenario.
The reproducible code is pretty simple. I defined five floating
elements running animation when the page starts. I also defined five backup
elements which have content and classNames already. Then click the button to periodically start a new animation. To not introduce other factors that way cause reflow or relayout, I'm using Web Animation API instead of toggling className to start a new animation.
const keyframes = [{
transform: "initial",
willChange: "transform"
},
{
transform: "translateX(0)",
offset: 0.01,
willChange: "transform"
},
{
transform: "translateX(-100vw)",
willChange: "initial"
}
];
const timing = {
duration: 3000,
iterations: Infinity,
easing: "linear"
};
const startButton = document.querySelector('#start');
startButton.onclick = start;
function start() {
const backupList = Array.from(document.querySelectorAll(".backup"));
let index = 0;
setInterval(() => {
if (index >= backupList.length) return;
const div = backupList[index];
div.animate(keyframes, timing);
index++;
}, 1000);
}
.container {
width: 100vw;
height: 100px;
background-color: red;
position: relative;
}
.floating,
.backup {
position: absolute;
will-change: transform;
color: black;
top: 0;
left: 100vw;
}
.floating {
animation: float linear 3s infinite;
}
@keyframes float {
0% {
transform: translateX(0);
}
100% {
transform: translateX(-100vw);
}
}
<div class="container">
<div class="floating">floating</div>
<div class="floating">floating</div>
<div class="floating">floating</div>
<div class="floating">floating</div>
<div class="floating">floating</div>
<div class="backup">backup</div>
<div class="backup">backup</div>
<div class="backup">backup</div>
<div class="backup">backup</div>
<div class="backup">backup</div>
</div>
<button id="start">Start</button>