Here’s one to file under the mobile is web is awful.
I’ve been writing a Slack-esque chat that lazy-loads new messages as you scroll up. The adventure of reliably anchoring scroll position as these new messages are added to the DOM is probably a blog post in itself, but there’s a specific issue on iOS that I’d like to share solution to.
Here’s the code to restore a previous scroll position, (which has to be recalculated to accommodate the newly-loaded messages):
node.scrollTop = node.scrollHeight - prevScrollTop;
Works great in every browser, except of course the modern-day IE:
Knew this wouldn't be so simple
As you can see, the scroll position stays at the top, almost as if we never manually reset the scroll position at all.
The problem, as I began to understand, was that if you try and manually set a node’s (and probably the viewport’s) scroll position while iOS is doing it’s out-of-bounds bouncy thing, that scroll position will be immediately overridden by the rest of the bounce animation.
To fix, we simply disable momentum scrolling on that element, restore scroll position, and then re-enable momentum scrolling:
node.style['-webkit-overflow-scrolling'] = 'auto'; node.scrollTop = node.scrollHeight - prevScrollTop; node.style['-webkit-overflow-scrolling'] = 'touch';
Here’s how that looks:
Not as graceful as I’d prefer, but looking at the timestamps the user is still left on the correct message. It also avoids funny residual momentum effects, so I presume this technique can also be used to kill scroll momentum when a pointer moves from one overflowing node to another.