I have a feed of photos that are scrolled vertically in my app and I'm using snap scroll. The feed is a virtual scroller, i.e. - only X elements are actually on the DOM, and elements above and below are removed/inserted as needed.
Important to note that this is a mobile web app.
However, when I scroll and DOM changes happen while scrolling, I'm getting the following buggy behaviors:
- The previous photo flickers while transitioning to the next photo
- The feed scrolls to the previously seen photo (doesn't repro 100% of the times)
I created a simulation in Codepen to repro the issues; a div is added to the DOM every 0.5secs, and trying to scroll while on mobile view repros both issues - [link to Codepen], please use a mobile view.
HTML:
<div class="snap-scroll-container"></div>
JS:
const snapScrollContainer = document.querySelector(".snap-scroll-container");
[
"https://media.istockphoto.com/photos/gray-british-cat-kitten-picture-id1086004080?k=20&m=1086004080&s=612x612&w=0&h=tvQKNjBGIsfCmUPR8YVJYfjLrTZ9JINbisKRjMj87IY=",
"https://images.unsplash.com/photo-1595433707802-6b2626ef1c91?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=880&q=80",
"https://images.unsplash.com/photo-1592194996308-7b43878e84a6?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
"https://images.unsplash.com/photo-1574144611937-0df059b5ef3e?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=764&q=80",
"https://www.warrenphotographic.co.uk/photography/bigs/08483-Ginger-kitten-portrait.jpg",
"https://img.freepik.com/premium-photo/kitten-portrait-beautiful-fluffy-gray-kitten-cat-animal-baby-british-blue-kitten-with-big-eyes-sits-beige-plaid-looking-camera-blue-background_221542-1665.jpg?w=740",
"https://libreshot.com/wp-content/uploads/2018/02/cute-kitten-portrait-861x1292.jpg",
"https://www.warrenphotographic.co.uk/photography/bigs/35147-Portrait-of-tabby-kitten-8-weeks-old.jpg",
].forEach((src) => {
const image = document.createElement("img");
const div = document.createElement("div");
div.setAttribute("class", "snap-scroll-child");
image.setAttribute("src", src);
div.appendChild(image);
snapScrollContainer.appendChild(div);
});
const addEmptyDiv = () => {
const div = document.createElement("div");
div.innerHTML = "bla";
snapScrollContainer.appendChild(div);
}
setInterval(addEmptyDiv, 500);
CSS:
body {
margin: 0;
padding: 0;
}
.snap-scroll-container {
scroll-snap-type: y mandatory;
height: 100vh;
overflow-y: scroll;
}
.snap-scroll-child {
scroll-snap-stop: always;
scroll-snap-align: end;
}
img {
object-fit: cover;
height: 100vh;
width: 100vw;
}
Unfortunately giving up on the virtual scroller is not an option as the perf hit will be large.
Going over SO and docs (including docs about restoring scroll position automatically after DOM changes), I couldn't find any plausible solution, other than maybe:
- Implementing snap scroll in JS (I would rather not)
- Deferring DOM changes until scrolling is complete (not optimal)