Implementing a Practical Server-Side Solution for Cumulative Layout Shift
Published: 2021-10-26 22:35:55

### ☝️☝️☝️ **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!

![cls](https://www.katielingo.co.uk/wp-content/uploads/2020/07/Cumulative-Layout-Shift-CLS.gif)

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 `height` and `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.

Include accurate `height` and `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 `height` and `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](https://github.com/forem/forem/pull/15170) where this all went down.

Forem uses [FastImage](https://github.com/sdsykes/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](https://web.dev/cls/). 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! ❤️