☝️☝️☝️ Pictured in the cover image is what happens when app visitors run into cumulative layout shift.
Cumulative layout shift is when the content of a webpage changes places when you least suspect it... Ahhh!
Sometimes it's an advertisement — ughhh! But the worst offender in general is images. Images load async so that the webpage can load and get the image when it's available... But when the image shows up, it can push the rest of the content out of the way unless we reserve space for it.
You reserve space for images by including
width attributes. These are old school HTML attributes which are generally overridden by CSS, but they are still used by the browser to determine aspect ratios and ultimate reserve space for images.
width attributes: Easy enough, right? Well not really: Who wants to sit around inputing that information, and generally who can be trusted to get it right. This seems like something the computer can do for us...
The computer can do this for us, but you have to be clever. In order to get image metadata, the image needs to be inspected. This could cause latency in the content saving process.
Long story, short: Forem now automatically detects image size by inspecting image data, and it does so asynchronously so
width attributes are updated after initially saving the post.
DEV is an instance of Forem, so that is why if you refresh this page, the above gif will not cause text to jump. Even if you disable cache, crank network settings way down, you will still not see cumulative layout shift. Forem is open source, so it's all there for your learning pleasure. Here is the pull request where this all went down.
Forem uses FastImage to quickly and minimally inspect images for their height and width attributes as well as whether they are animated gifs. This is used to help with issues pertaining to
prefers-reduced-motion in our efforts to provide the most accessible experience.
Attempting to do too much of this on the client would bog down the experience. Doing it at save time ensures our capacity to make best use of basic browser functionality.
If you are working with Ruby, you could most likely implement FastImage exactly as we have. If you are using different tools, this pattern is still likely to be an effective way to generally handle enriching and progressively enhancing content as it changes. Generally content is consumed far more often than it changes, so it is efficient to do this at the moment of change and allow the consumption experience to be as unencumbered as possible.
For more on CLS, here is the de facto guide. That's where the gif came from.
DEV runs on Forem, which anyone else can use to run their own content-based communities like ours, so it is important to us that we continually refine the core experience for the most possible collective benefit.
If you are interested in chipping in, this functionality could be slightly optimized. We currently inspect images twice. Once for
size and once for
animated?... PRs absolutely welcome if you can improve this and include a test along the way.
Happy coding! ❤️