When a list mutates while away, restore the item, not the pixel offset
Aliases: item-based restore · scroll anchor · not pixel offset
What it is
While the user is in a detail, a feed may insert posts at the top, an inventory list may lose rows. Coming back, scrolling to the scrollTop recorded at leave parks the viewport on a different set of objects. Restoring by item remembers the id then in view, and its position inside the viewport; after the collection changes, that row is found and aligned again. Basic “don’t jump to the top” assumes the list did not move. Once it moved, the pixel bookmark points at a different page of the book.
Why it happens
A pixel offset is a measurement of that layout, not a reference to an object. Inserts, deletes, and height changes from images loading all make the same offset hit another row. The user’s bookmark is an object—“that blue card”—not “1374 pixels.” CSS overflow-anchor and browser scroll anchoring handle inserts in the same frame; a round-trip is outside their scope—the list is often destroyed and rebuilt, and the anchor node is gone from the DOM.
Id-based restore changes the coordinate system to a primary key on the collection. On return, ensure that id is in the rendered window, then roll it to the same relative place in the viewport. Ten inserts at the top make pixel restore feel like “the things I saw ran downward” or “I was sent to earlier content”; id restore leaves those ten above, with a light “new content above” if needed, rather than dragging the user to the top. The key must be stable: anchoring on the array index of that moment misaligns after a reorder, which is the old coordinate system under another name.
Studying it
While the user is away, insert a known number of items at the head. Compare pixel restore with id restore.
- Independent variables: strategy (scrollTop / object id / none), insert count, whether item heights are uniform.
- Dependent variables: whether the original object is in the viewport on return, error in its relative offset, reports of “the wrong item.”
- Methodological note: uniform heights understate pixel failure—N inserts are a pure translation and can still look like “that band.” Use a card stream with large height variance. Do not run this leaf on a static list with no inserts; that is the basic jump-to-top problem. Cold start after process death must be run separately: in-memory DOM anchors are gone, only ids remain.
Where it stops holding
If the collection was filtered or sorted into another set, the old id may not be in the new results; item restore fails, and the honest move is to admit the collection changed rather than stall on blank. If the user deleted that item in the detail, return should align on a neighbour—still object-based. Ad slots and timestamp separators have no stable id and must not be anchors; anchor on a neighbouring content item. A collaborative list reordered by someone else while away still has the id, but the surrounding rows changed; people match the object and miss “those around it.” That is a failure to explain, not something pixel restore would fix.
Applying it
- On leave, record the object id and its fraction inside the viewport (e.g. 30% from the top). Do not record only
scrollTop. - On return, fetch that id into the render window first, then align. Inserts at the top stay above; a weak notice is allowed; do not drag the user to the top to make pixels match.
- Anchor on a stable primary key, not the index or “which screen” of that moment.
- Verify: open a detail from a visible item; while away, insert at least one screen of new items at the top; return. The original item must still be in the viewport. Run the same recording with pixel restore as a contrast: the viewport should already show a different set—that is what this leaf exists to avoid.
Related
- Within the group: G4.07.2 Infinite-scroll restore depends on how much was loaded; returning too deep retriggers fetch · G4.07.3 Unsubmitted input drafts should survive leaving by navigation, not be cleared · G4.07.4 When position restore fails, say why—deleted or reordered · G4.07.5 Cross-device resume stores position on the account, not in local state
- Adjacent: G4.03 State persistence · E5.07 Infinite scroll · G4.01 Back stack and back semantics
- Search terms:
scroll anchor·item-based restoration·scroll restoration
Cards in the same group
- G4.07.2Infinite-scroll restore depends on how much was loaded; returning too deep retriggers fetch
- G4.07.3Unsubmitted input drafts should survive leaving by navigation, not be cleared
- G4.07.4When position restore fails, say why—deleted or reordered
- G4.07.5Cross-device resume stores position on the account, not in local state