If a feed prepends new rows while someone is reading older ones, inspect the scroll container before adding JavaScript to adjust its offset. Chromium may already be compensating for the inserted height through scroll anchoring. A transform on the relevant path can suppress that compensation, producing a jump even though the prepend code did not change.
Reproduce the two states
Save this as scroll-anchor.html and open it in Chromium. Click Prepend after the list settles. Then open the same file with ?suppressed=1 and repeat. The two runs differ only in the transform applied immediately before the insertion.
<button id="prepend">Prepend</button>
<div id="viewport" class="viewport"><ol id="feed"></ol></div>
<style>
.viewport { height: 300px; overflow: auto; }
.viewport.transform-shift { transform: translateY(0); }
#feed li { min-height: 72px; }
</style>
<script>
const viewport = document.querySelector('#viewport');
const feed = document.querySelector('#feed');
for (let index = 0; index < 30; index++) {
const row = document.createElement('li');
row.textContent = `Message ${index + 1}`;
feed.append(row);
}
feed.children[16].scrollIntoView({ block: 'center' });
document.querySelector('#prepend').addEventListener('click', () => {
const before = viewport.scrollTop;
if (location.search.includes('suppressed=1')) {
viewport.classList.add('transform-shift');
}
const row = document.createElement('li');
row.textContent = 'New message';
feed.prepend(row);
requestAnimationFrame(() => {
console.log({ before, after: viewport.scrollTop });
});
});
</script>
With anchoring enabled, the browser should increase scrollTop to keep the same message near its prior viewport position. With the transform applied, the controlled Chromium fixture used for the original article leaves the offset unchanged, so visible content moves. Compare both the measured offset and the message in view; a single number alone can hide what the reader experienced.
Decide whether to keep anchoring
If the feed should preserve the current reading position, investigate transforms on the scroller and its ancestors before adding manual scroll correction. If movement is intentional, overflow-anchor: none is the explicit CSS opt-out. Apply it only to the section where that behavior is wanted, then retest insertion and focus behavior. Avoid disabling anchoring across a whole page to hide a local layout problem.
This example is a small browser fixture, not a recipe for virtualized lists. The recorded independent test ran in Chromium on Linux; it does not establish identical results in other browsers or in a framework's scrolling abstraction. The MDN scroll anchoring overview describes suppression triggers, and the MDN overflow-anchor reference covers the opt-out.
Top comments (0)