Watch Out for Lazy-Loaded Images When Anchor Scrolling
When using anchor scrolling, you might encounter an issue where lazy-loaded images are not properly loaded when the page is scrolled to the anchor. This can lead to layout shifts and thus the document height would not be correct.
I was fixing this Javascript issue in a project. Visiting the anchor link #section-1
(you know that link that you click on to scroll to a specific section of the page), and URL would be like https://example.com/#section-1
. The problem was that the scrolling position was wrong in some cases.
Then after lots of debugging, I spotted some issues with the document height, on Top of the page, document height was like 5000
, and on the bottom it was 3000
. I took time debugging thinking the Sticky header and other fixed elements was screwing this, but wasn't the case.
The Problem
When a browser first paints a page, it tries its best to figure out where everything goes. If an image, especially one loaded "lazily" (meaning its actual content is fetched only when it's about to scroll into view), doesn't tell the browser how much space it'll eventually take up, the browser makes a guess. Often, that guess is "not space at all."
Then, as the page loads, the lazy loader kicks in, the real image data arrives, and suddenly that tiny placeholder needs to expand to the image's full dimensions. If this image is above your target anchor, everything below it gets shoved down. Your anchor link, which initially pointed to a spot based on the placeholder layout, is now pointing to a spot that's wildly incorrect relative to the actual content.
The problem was that the scrolling position would not be correct because the document height kept changing as images loaded in.
The Solution
Option 1: Placeholder image
First solution is to use a placeholder image that is the same size as the actual image. This way, the browser will have a correct guess of the space the image will take up. But this might not work in some cases, I don't know why exactly but some cases not good for me, perhaps it was because I was trying to use SVG as a placeholder.
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://example.com/image.jpg" alt="Placeholder Image">
Option 2: Instead of placeholder, let browser knows the space the image will take up
Setup the image with width
and height
attributes. Or, you can use style
attribute to set the width and height.
<img src="https://example.com/image.jpg" alt="Image" width="100" height="100">
or
<img src="https://example.com/image.jpg" alt="Image" style="width: 100px; height: 100px;">
and/or, if you can add Aspect Ratio to the image. Adjusting to the adequate size of the image.
<img src="https://example.com/image.jpg" alt="Image" style="aspect-ratio: 150/150;">
Well, I hope this helps someone. I entered in a rabbit hole this time, because Lazy Loaded was not really explicit in this codebase I was working on, glad I found the solution.