Why does the reported scroll of an element differ from what we see?

18 hours ago 3
ARTICLE AD BOX

I have implemented a short function which logs a message inside a div and keeps the div scrolled to the bottom if it was already scrolled to the bottom before. You can see a short demo of it here.
Small warning, the demo is slightly laggy. More lag illustrates the effect better, while less lag makes it trigger slightly more reliably. You can play with the lag function iteration count.

function log(text: string): void { const isBottom = logDiv.scrollHeight - logDiv.offsetHeight - logDiv.scrollTop < 3; logDiv.appendChild(document.createTextNode(text)); logDiv.appendChild(document.createElement("br")); if (isBottom) { logDiv.scroll(0, logDiv.scrollHeight); } } while (true) { //Keep the CPU busy to simulate a lower framerate (makes the issue easier to see) (omitted code for brevity) await new Promise(resolve => setTimeout(resolve)); //Make some random message (omitted code for brevity) log(text); }

The problem is that while the logic works for most situations, it usually fails here.
I would say on Firefox, it fails about 75% of the time when scrolling up, and 40% on Chrome. Meaning that after the element has visibly scrolled up, it reports it has not been scrolled up, and snaps back to the bottom. With some different code, these percentages were higher.
In the other direction, trying to get it to snap to the bottom, I would say both browsers fail about 90% of the time. The element is visibly scrolled to the bottom, but the browser reports it is not, and thus does not stay scrolled to the bottom when a new line is added.

I'm aware there are different approaches entirely to achieve this functionality, but as far as I can tell, my code is logically sound. I am mainly curious why the browser reports an incorrect value, and I'm secondarily curious why the browser does not always report an incorrect value?

As an added bonus, if you know of a fix that does not use an entirely different approach, that would be nice as well.

Read Entire Article