Improve Largest Contentful Paint (LCP) by removing image transitions

Improve Largest Contentful Paint (LCP) by removing image transitions

Image transitions are a technique used to animate images as they appear on screen. Examples include scaling or fading the image into view for visual flare. However, often these transitions are implemented in a way that causes a large degradation in performance and thus user experience.

We worked with Case-Mate to fix this issue on their website, resulting in a 6 second improvement in Largest Contentful Paint (LCP)! In this case study, we'll walk through the experience and the steps we went through to make this improvement.

Transitions in Action Jump to heading

To understand this more the video below shows a page with a transition on the left. The screen displays the product image after 13 seconds. Rather than suddenly appearing, the image fades in during a half a second period (transition).

The video on the right shows the same page with the transition removed. As a user I know which version I prefer!

Video of page loading with and without image transition
Video to show what a transition looks like and how it impacts the performance of a page.

This example came up in a recent office hours session. Lazy loading is often always the cause of a slow loading image. But in this example, the team at Case-Mate had already optimised the image by:

  1. Removing lazy loading
  2. Making it responsive (let the browser pick the right size) using the srcset attribute
  3. Telling the browser this image is more important than others by adding fetchpriority=”high”

A simplified version of the Liquid and source code can be seen below:

<!-- Input -->
{{ product |
image_url: width: 1000 |
fetchpriority: high,
widths: '400,...,1000',
sizes:(max-width: 999px) calc(100vw - 48px), 640px'

<!-- Output -->
srcset="image.jpg?width=400 400w, … image.jpg?width=1000 1000w"

sizes="(max-width: 999px) calc(100vw - 48px), 640px"

Using WebPageTest we investigated when the image was being downloaded and displayed. We could see there was a large delay between those two events.

Waterfall with image transition
The product image (loaded at object 25) is downloaded just before 5 seconds. It does not appear in the browser until after 12 seconds as shown by the dotted green line on the right hand side.

After loading the page a few times using Chrome Dev Tools we noticed the 'opacity: 0' style was assigned to the 'reveal' attribute that made the image invisible. The JavaScript logic responsible for fading it into view was part of the theme.js file. This file did not run until around 12 seconds of the page load. As a quick test we asked the team at Case Mate to remove this attribute.

The video images below show the result of removing the transition. The attribute "reveal" was causing a 6 second delay in displaying the image, a full second of delay per letter of HTML!

Waterfall after removing transition
The product image (loaded at object 18) is downloaded just before 5.5 seconds. It appears in the browser after 7 seconds as shown by the dotted green line on the right hand side.
Filmstrip of image transition tuned off
WebPageTest's filmstrip shows us the visual difference in making this change.

Fixing the delayed LCP problem Jump to heading

Now that we properly identified the problem, we came up with two possible solutions:

Option 1 - Remove transitions completely

My preference is to remove all image transitions completely. I don’t think they offer much of an enhanced user experience. In the example above, removing the behavior was as simple as removing the attribute from the image.

Option 2 - Don't render-block the transition

If you really want to keep transitions, find the code that does the transition and check when it runs. If it is buried in a library or bundled JavaScript file then it may be faster to extract it into a file of its own.

Filmstrip of separated JavaScript vs no transition
This film strip shows a product page with no transition against a page where the transition code has been separated into its own file.

In the example above the code was run in theme.js. By moving the code to its own file and loading asynchronously near the top of the page, the impact of transitions was reduced to 0.5 seconds (shown above). This seems like a better compromise to make if transitions are deemed to be important.

Conclusion Jump to heading

Transitions and other aesthetic flair can make a site seem slick, but make sure that you're not sacrificing user experience and performance. Consider removing transitions that don't provide much value or by minimising their impact to performance and accessibility.

Read similar articles tagged...

Back to blog