Fix slow hero images & Core Web Vitals

Improve the Largest Contentful Paint by speeding up slow hero images

Arjen Karel Core Web Vitals Consultant
Arjen Karel
linkedin

How To Fix Slow hero images - in short

Hero images are large images on top of a web-page. Those hero images will cause a long Largest Contentful Paint when the hero images are not optimized. 9 out of 10 sites that I am asked to optimize will have issues with the hero images. In this article I will show you different techniques on how to speed up hero images.


What is a hero image?

A Hero Image or sometimes called a called a 'hero header' is a large image with text, often placed at the top of a webpage. A hero image serves as a user's first glimpse of your company and offering because of its prominent placement towards the top of a webpage that usually extends full-width.

hero image example coke.

A quick reminder: Hero images, the Core Web Vitals and the Largest Contentful Paint

Because of the size of the hero image (it usually spans the entire width of the page a good portion of the height of the visible viewport) this element will become the Largest Contentful Pain element in almost all of the cases.

The largest Contentful Paint is an important Core Web Vitals metric. The largest contentful paint element is the Largest Element that will be painted in the visible viewport of the browser.

Because un-optimized images tend to take up much bandwidth and therefore take a long time to load hero images will often cause bad Largest Contentful Paint Metrics

Optimizing the hero image and the Largest Contentful Paint

There are many techniques for optimizing the hero images and the Largest Contentful Paint. I will explain them here. Most techniques can be combined for even better results!

1 Preload the hero image or Send 103 headers

When you want an element to be available as soon as possible in the browser you could preload that element. Preloading involves using resource hints. Resource hint tell the browser something about the priority of an element and will trigger a very early download of that resource.

<link 
  rel="preload" 
  as="image" 
  href="wolf.jpg" 
  imagesrcset="hero_400px.jpg 400w, hero.jpg 800w, hero_1600px.jpg 1600w" 
  imagesizes="50vw">

In the near future 103 early hints will be supported by chrome browsers. This will make it possible to send resource hints BEFORE the final HTML response has been sent. 103 early hints are expected to be a game changer when it comes to improving the Largest Contentful Paint. If you are interested in learning about early resource hints check out my article.

Why should 
                   I preload the largest contentful paint image

2 Compress the hero image & use next-gen formats

Compressing images will make their file-size smaller. Smaller file-sizes will take up less bandwidth and are available to the browser as soon as possible. Compressing images can be done in your photo editor, in your CSM (tip: your developer can set the wordpress compression level) or with an online image compression tool

Most slow hero images are slower then they need to be because they are served in the 'wrong' image container like PNG of JPEG. There are much faster alternatives to JPEG and PNG like WebP and AVIF. 

For many CMS systems there are conversion plugins that will convert your images to gext-gen format. When image conversion is difficult to integrate into your website a CDN with image conversion support might be the solution you are looking for.

jpg vs compressed jpg vs webp

3. Do not use background images, use normal responsive images

Your hero image should be a normal image and never a background image. The usual way of doing hero images is by adding a background image to the hero container and setting the background-size of that container to cover. This will ensure the hero image will fit the screen in all cases.

Fast hero image

Background images are bad for Core Web Vitals. Remember that! There is no good reason to ever use background images.

  • Background images are loaded at a lower priority
  • Background images are not responsive (not unless you really want to complicate things)
  • Background images might cause Core Web Vitals issues with most lazy loading libraries.

The way I do it is by adding a normal image in an absolute position and setting the object-fit property of that image to cover. Once I have changed the background image to a normal image I can start using responsive images

Responsive images means that for different devices (mobile,desktop,tablet) a different version of the same hero image can be sent. For a desktop device I might send a huge 1920x1280 hero image while for a mobile device I would only need to send a smaller 400*266 pixels hero image. That is 25 times less data!

  • The hero images are now loaded with a higher priority
  • I can now use responsive images for the hero image

style.css

<style>
#herocontainer{
    position:relative;
    padding:4rem 0
}
#heroimg{
    object-fit: cover;
    width: 100%;
    height: 100%;
    position: absolute;
    top: 0;
}
</style>

index.html

<div id="herocontainer">
<h1>Welcome to my site</h1>
<picture>
    <source 
        type="image/webp" 
        media="(max-width:540px)" 
        srcset="herosm.webp">
    </source>
    <img loading="eager" decoding="async" src="hero.webp" id="heroimg">
</picture>
</div>

4. Serve hero images from the main domain & consider a Content Delivery Network (CDN)

All too often I see the largest contentful paint image being served from a different domain, for example 'static.mydomain.com'. These subdomains often point to a CDN. While I encourage the use of a CDN (see below) a setup like this is not advisable. The image on the subdomain requires a new connection to a new server. New connections are costly and will take up valuable time. When the image is served from the main domain (www.mydomain.com for example) the images can be fetched much faster though the already established server connection.

When setup on the main domain a CDN might offer a huge speed increase. Especially when your sites is visited from all over the world. A CDN has servers strategically placed all over the world where your static resources (like images are cached) for fast local response times. This means data does not have to travel all over the world but can be served from a local edge server.

cdn world

5. Avoid lazy loading the largest contentful paint images & explicitly eager-load the hero image

Make sure that there is no lazy loading being applied to your hero image. Hero images should always load eager.

Many sites, especially WordPress sites, are using some sort of WordPress pagespeed plugin like WP Rocket or WP Core Web Vitals. These plugins usually do a great job in speeding up slow sites but they cannot fix stupid :-)

These plugins will lazy load images that seem like a good candidate to lazy load. If the hero images is not an eager image those plugin will probably also lazy load the hero image.

This, at best, will cause a small delay in the LCP metrics. At worst, especially when JavaScript based lazy loading is activated it will cause a larger delay.

Making images load eager is pretty simple. Just ass loading="eager" to the image and you are done.

<img src="hero.webp" loading="eager" width="800" height="400">

6. Avoid lay-out shifts caused by the hero image

Another common issue I see with hero banners and hero images is that they cause a huge layout shift. These layout shifts may occur for different reasons.

  • The hero element is created with JavaScript. Some hero plugins and page builder like elementor are know to rely on JavaScript to render the hero content. Though there is nothing wrong with JavaScript make sure the hero element renders the same without JavaScript.
  • The fonts in the hero element cause a layout shift. The hero element usually contains some large text with a call to action and a tagline. Make sure these large fonts do not cause a layout shift.
  • Missing image dimensions. When the hero image is not a cover images (either as a background image or a an absolute positioned image) missing image dimensions (width and height) will certainly cause a large layout shift.

While fixing the layout shift not improve the Largest Contentful Paint, it will improve the Core Web Vitals of the page. For more information on how to fix the layout shift please read this in-depth guide on how to fix the layout shift!

CLS caused by image before
CLS caused by image after

7. Use 2-stage loading to improve the hero Core Web Vitals

2-stage loading is an fast technique that we apply to all our images. We first serve an extremely low quality image that is expected to download much earlier then the larger high quality image. Once the low quality image has been painted on the screen we the browser is triggered to fetch the high quality image in the background. Once the high quality images has been downloaded the low quality images will be replaced by the high quality image.

There are 3 methods of 2-stage loading. The first two are methods you should consider. The last one is one you should not do.

Stage 1: low quality webp 3-5kb

Stage 2: high quality webp 20-40kb

1. Full 2-stage loading

With full 2-stage loading the first loq quality image has the exact same dimensions (width and height) as the original hight quality image.

The result of this 2-stage loading is that the largest contentful paint element will be the much faster, low quality image (which will then lazily be swapped). The swapping of the image will all happen so fast that a casual visitor will probably never notice. The result of this technique is that the LCP is painted much earlier the page appears 'ready' much sooner which contributes to a far better user experience and improved Core Web Vitals.

2. Smaller in-line placeholders

The smaller placeholder is a pretty cool technique that has one drawback: it does not improve the Core Web Vitals. It is still a great technique because it improves the user experience.

The basic idea is the same as for the 2-stage loading technique but in stead of one low quality image with the same dimensions a much smaller images with smaller dimensions is placed inline though a data uri. The final hero image which will be the largest contentful paint image is still downloaded in the background. This trick will not improve the Largest Contentful Paint but will make the page appear ready even faster then the 2-stage loading technique

3. Transparent placeholders

A common 2-stage loading technique and a method to trick the browser into sending an early Largest Contentful Paint metric is to use transparent svg elements. Those elements are small and can be placed inline, just like the smaller inline placeholder.

Using an inline svg elements and swapping them is actually a lazy loading technique. The advantage of this technique is that it works cross-browser. 

Lazy loading, of course should only be applied to elements outside of the viewport. In this case the transparent svg element will only delay the real hero image and has no added value for your visitor. Where the paint metrics might be great, the UX of the page will actually worsen.

That is why the hero image should always be loaded eagerly without tricks that cause a bad UX.

I help teams pass the Core Web Vitals:

lighthouse 100 score

A slow website is likely to miss out on conversions and revenue. Nearly half of internet searchers don't wait three seconds for a page to load before going to another site. Ask yourself: "Is my site fast enough to convert visitors into customers?"

Fix slow hero images & Core Web VitalsCore Web Vitals Fix slow hero images & Core Web Vitals