CSS overflow-anchor: Scroll Anchoring
Keep the chat log from jumping
Loading older messages used to mean saving scrollHeight, prepending the nodes, then adding the difference back to scrollTop. overflow-anchor lets the browser hold the words you were reading in place.
function prependMessage(log, node) { const prev = log.scrollHeight; log.prepend(node); log.scrollTop += log.scrollHeight - prev;}.log { overflow-y: auto; overflow-anchor: auto;}/* browser holds the visible message when older ones prepend */overflow anchor Browser Support
Since 2026 this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.
Works in all modern browsers. May need a fallback for older browsers.
Baseline Newly available since September 2026, when Safari 27 and iOS Safari 27 shipped. Chrome 56, Firefox 66, and Edge 79 already had it. Older Safari still jumps when messages are prepended, so keep the scrollHeight delta behind @supports not (overflow-anchor: auto) if those versions matter.
Same pixels stay put
Content inserted above the anchor changes scrollTop in the same layout pass. The line you were reading does not move.
On by default
auto is the initial value. The usual bug is a stylesheet that sets none, or a list of absolutely positioned rows the browser cannot anchor.
Not a stick-to-bottom
Anchoring holds a message that is already on screen. A bubble growing at the end of the log still needs scrollTop = scrollHeight while the reader is following it.
How it works
Scroll anchoring picks an element in the visible area and, when layout above that element changes, moves scrollTop by the same amount. Loading older chat messages, an image finishing above the fold, or a tool row opening higher up the thread all used to shove the viewport. The old compensation stored scrollHeight before the insert and added the difference to scrollTop afterward.
overflow-anchor: auto marks an element as a possible anchor. none takes it out of the running. The initial value is auto, and browsers that support anchoring already do this without a rule. You write auto when a reset set none, or to make the choice obvious. Absolutely positioned rows are not anchor candidates, so a virtualized list that takes every row out of flow turns anchoring off even when the property says auto.
Anchoring does not follow growth of the anchor itself. A streaming reply getting taller, or a new message arriving while the reader is pinned to the end, still needs one scrollTop = scrollHeight write, and only while they are already at the end. Safari 27 and iOS Safari 27 shipped this in September 2026. Chrome has had it since 56, Firefox since 66, and Edge since 79. Global support is about 80% on caniuse. MDN lists it as Baseline Newly available since September 2026.