I need to synchronise the scroll of two elements: A content area and a "header".
But when I used the scroll event to change the position of the other element with a CSS transform, there was a notable delay between the user scrolling and the header moving, which is distracting, specially on Chrome.
However, when comparing to other applications that use the same method for synchronising the scroll position, they didn't have it. After many hours trying to find why, I've finally found it: they have an invisible overlay that covers the whole scroll area, which is also not interactive (CSS pointer-events: none)
I've prepared a playground below, where the overlay is visible and doesn't cover the whole area so it can be compared easily.
At least this behaviour is happening in my machine, a Mac with Chrome, and I scroll through the trackpad gesture. There also needs to be some load, so this snippet also adds a 30ms blocking loop every 100ms to simulate one
const content = document.getElementById("content");
const header = document.getElementById("header");
// Add content
const helloes = new Array(100).fill("Hello!").join("<br /><br />");
header.innerHTML = content.innerHTML = helloes;
// Synchronize scroll of content to header by adding `transform`
content.addEventListener("scroll", (evt) => {
header.style.transform = `translateY(${-content.scrollTop}px)`;
});
// Simulates performance hit, either low-end computer or a component doing extra load
setInterval(() => {
let start = Date.now();
while (Date.now() < start + 30);
}, 120);
.main {
position: relative;
display: flex;
}
.main>div {
overflow: auto;
height: 200px;
padding: 10px;
border: 1px solid black;
border-radius: 5px;
white-space: nowrap;
}
#content {
padding-right: 200px;
}
#overlay {
position: absolute;
left: 160px;
top: 50px;
width: 100px;
height: 100px;
box-sizing: border-box;
background: rgba(0, 0, 0, 0.3);
pointer-events: none;
}
<div class="main">
<div>
<div id="header">
</div>
</div>
<div id="content">
</div>
<div id="overlay"></div>
</div>
As it can be quite tricky to reproduce, I've recorded this behaviour in this image
It's quite subtle, but as you can see, when I'm scrolling with the mouse over the scroll area, there's a visible lag. If I'm scrolling instead on top of the uninteractive overlay, the scroll synchronization is perfect.
However, I totally can't understand why this happens - What is the reason adding an overlay and scrolling with the mouse on top of it improves the performance?
