Core Web Vitals are the new metrics that Google uses to measure a users page experience. One of the metrics is Largest Contentful Paint (LCP) which indicates the time it takes for the pages main visible content to be shown to the user.

LCP is the way Google now determine if a page is fast or slow. Google’s page experience algorithm wants to see an LCP score of no more than 2.5 seconds. Typically, LCP relates to the main image for a page.

Our Tag Rocket app gathers Core Web Vitals metrics which power our Core Web Vitals report. We used this information for our demo Cornerstone theme to work out how to dramatically improve a stores LCP score via some alterations to the theme.

The following fixes were made on the base Cornerstone theme. They may need alteration if your theme has been modified.

Stop the products main image from lazy loading

The most critical issue we saw was that the theme was lazy loading the product pages main image. And it was lazy loading via JavaScript. This meant the image was not even requested until the JavaScript was loaded and run. Causing a big delay in the image showing and a large LCP score.

Luckily this was an easy fix. Cornerstone uses a component to add images to the page (components/common/responsive-img), and it has an option to disable lazy loading. So we did that for the products main image:

templates->components->products->product-view.html

  
         <figure class="productView-image"
                data-image-gallery-main
                {{#if product.main_image}}
                data-zoom-image="{{getImageSrcset product.main_image (cdn theme_settings.default_image_product) 1x=theme_settings.zoom_size }}"
                {{/if}}
                >
            <div class="productView-img-container">
                {{!-- Remove the surrounding a-element if there is no main image. --}}
                {{#if product.main_image}}
                    <a href="{{getImageSrcset product.main_image (cdn theme_settings.default_image_product) 1x=theme_settings.zoom_size}}"
                        target="_blank"{{#if schema}} itemprop="image"{{/if}}>
                {{/if}}
                {{> components/common/responsive-img
                    image=product.main_image
                    class="productView-image--default"
                    fallback_size=theme_settings.product_size
                    lazyload='disabled'
                    default_image=theme_settings.default_image_product
                    otherAttributes="data-main-image"
                }}
                {{!-- Remove the surrounding a-element if there is no main image. --}}
                {{#if product.main_image}}
                    </a>
                {{/if}}
            </div>
        </figure>

Stop the category and brand page first image from lazy loading

A similar issue happens on the category and brand pages. In this case it is often the first product image on the page that causes the LCP. Especially on mobiles where it is typically the only image visible as the page loads.

This time we needed to add some code to only disable lazy loading for the first image on the page.

templates->components->products->product-card.html

        <a href="{{url}}"
           class="card-figure__link"
           aria-label="{{name}},{{> components/products/product-aria-label}}"
           {{#if settings.data_tag_enabled}} data-event-type="product-click" {{/if}}
        >
            <div class="card-img-container">
                {{#and @first (if settings.request.absolute_path '!==' '/')}}
                {{> components/common/responsive-img
                    image=image
                    class="card-image"
                    fallback_size=theme_settings.productgallery_size
                    lazyload='disabled'
                    default_image=theme_settings.default_image_product
                }}
                {{else}}
                {{> components/common/responsive-img
                    image=image
                    class="card-image"
                    fallback_size=theme_settings.productgallery_size
                    lazyload=theme_settings.lazyload_mode
                    default_image=theme_settings.default_image_product
                }}
                {{/and}}
            </div>
        </a>

This is designed work on all pages using product cards except the home page as it contains multiple product sets that are lower down on the page, like featured/new/popular products.

Preload images

The above changes did not rock the boat much with regard to LCP, but they did open the option to preload the images. The combination means the LCP images start loading immediately, and are shown as soon as the html is rendered.

We also found that the home pages carousel was its LCP issue. The first image already had lazy loading disables, so we only needed to preload it to reduce the LCP score.

layout->base.html

Place this code early in the head section.

        {{#if product.main_image}}
        <link rel="preload" href="{{getImage product.main_image 'product_size' (cdn theme_settings.default_image_product)}}" imagesrcset="{{getImageSrcset product.main_image use_default_sizes=true}}" as="image">
        {{/if}}
        {{#if category.products.[0].image}}
        <link rel="preload" href="{{getImage category.products.[0].image 'productgallery_size' (cdn theme_settings.default_image_product)}}" imagesrcset="{{getImageSrcset category.products.[0].image use_default_sizes=true}}" as="image">
        {{/if}}
        {{#if brand.products.[0].image}}
        <link rel="preload" href="{{getImage brand.products.[0].image 'productgallery_size' (cdn theme_settings.default_image_product)}}" imagesrcset="{{getImageSrcset brand.products.[0].image use_default_sizes=true}}" as="image">
        {{/if}}
        {{#if carousel.slides.[0].stencil_image}}
        <link rel="preload" href="{{getImageSrcset carousel.slides.[0].stencil_image 1x=(default '1280w' '160w') }}" imagesrcset="{{getImageSrcset carousel.slides.[0].stencil_image use_default_sizes=true}}" as="image">
        {{/if}}

Note: for preloading to work it has to use the exact same image URL and srcset (if present) as the image that is causing the LCP issue. If not, the preload is just wasting time.

Conclusion

Testing the demo account on my machine and I saw LCP reductions in the 100s of milliseconds up to half a second.

We implemented similar changes for one client (They had a customised theme) and saw their LCP score move from “needs improvement” to “good”. We also fixed their Cumulative Layout Shift (CLS) issues meaning they now pass all metrics and are eligible for the page experience ranking boost.

Remember that Tag Rocket can gather your real Core Web Vitals metrics from your own visitors and report on them in detail. That is how we discovered these issues.

I’d love to hear how well it works for you.