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!
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:
- Removing lazy loading
- Making it responsive (let the browser pick the right size) using the srcset attribute
- 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 |
image_tag:
fetchpriority: high,
reveal
widths: '400,...,1000',
...
sizes:(max-width: 999px) calc(100vw - 48px), 640px'
}}
<!-- Output -->
<img
fetchpriority="high"
reveal
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.
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!
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.
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.