Loading older messages without moving the reading position
Analyze stable scroll anchors for chat history, including delayed images, concurrent incoming messages and the moment automatic correction should yield to the user.
Exploration · Principles and possible approaches inspired by a project context.
- Chat UI
- Scroll anchors
- Dynamic height
- Interaction state
Related project: Business communication and after-sales collaboration. History loading and message navigation motivate this analysis; the full strategy is not presented as an existing implementation.
Preserve the message being read
After a user scrolls into history, prepending another page can push the current message out of view. The useful state is not an absolute scrollTop, but a message identity and its position inside the viewport.
Height compensation has assumptions
A common formula is:
new scrollTop = old scrollTop + new scrollHeight - old scrollHeight
It works when changes occur only above the viewport and existing content has stable height. Concurrent messages appended below contaminate the total-height delta. An image loading later can invalidate the measurement again.
Anchor a stable message ID
Before inserting data, record a visible message ID and its offset from the container’s content viewport. After layout, locate that same message and compensate for its displacement.
If its offset changes from 24px to 184px, increase the scroll position by 160px. Array indices cannot identify that message after prepending or sorting.
If the anchor disappears, choose a surviving neighbor or report that the target is unavailable. A recycled DOM element is not a replacement identity.
Late layout changes and user control
Reserve image and attachment dimensions where possible. When sizes cannot be predicted, observe relevant changes and correct the anchor only while the same reading intent remains active.
Cancel pending restoration when the user actively scrolls. Otherwise the application may undo their new position. Also account for the browser’s own scroll anchoring so the same displacement is not compensated twice.
Following the latest is a different intent
Maintain a distinction between following the latest message and reading history. Incoming messages can keep the first state at the bottom; the second should preserve its anchor and show a new-message affordance.
Allow a small tolerance when determining whether the user is at the bottom. End pending restoration when switching conversations so an old callback cannot reposition a new list.
Verify geometry, not just arrays
Compare the same message’s viewport position before and after insertion. Delay image loading, append incoming messages concurrently, resize the viewport and scroll manually during restoration.
The result should preserve reading intent while allowing explicit user actions to take priority.