The Image Loading Module in Page Lightning helps you prioritise how images are loaded, with important images loading early and quickly (preload, eager, and high priority) while letting other images load just before they are required (lazy loading).

The app intercepts images being added to the page and modifies them as required. For this to work, the images need to be set to be lazy loading in the theme using the responsive-img component, otherwise the image starts loading before we can fix it. This is a setting in the theme customisation (Styles->Global->Lazyloading Mode). We also recommend avoiding the LQIP options, as they automatically load a small version of the image.

Theme changes to add support for all responsive images

The home page carousel and brand pages’ main images have lazy loading disabled, meaning we can’t fix them without changes to the theme that enable lazy loading. Only do this if you enable the relevant feature in the app.

The home page’s main carousel image

templates\components\carousel.html

{{#if @first}}
    {{> components/common/responsive-img
        image=stencil_image
        class="heroCarousel-image"
        fallback_size='1280w'
        lazyload='lazyload'
    }}
{{else}}
    {{> components/common/responsive-img
        image=stencil_image
        class="heroCarousel-image"
        fallback_size='1280w'
        lazyload='lazyload'
    }}
{{/if}}

Brand main image

templates\pages\brand.html

{{> components/common/responsive-img
    image=brand.image
    fallback_size=theme_settings.thumb_size
    lazyload='lazyload'
}}

Without this fix, a bug in responsive-img causes it to load a brand image that will fill the page, while typically only a small brand image is shown. This fix will probably not affect LCP when the brand image is so small, but it will improve the users’ experience and use up less of their bandwidth.

Dealing with responsive images and sizes

Most of the images the app intercepts are responsive images. This means the image tag provides a choice of image URLs for the browser to use based on the size the image will be on the page. This is great because smaller devices load smaller images, which speeds up page load time. The app currently supports optimising the following responsive images:

  • Product Page – Main Image
  • Category Page – Main Image
  • Blog Posting – Thumbnail Image
  • Brand Page – Main Image
  • Home Page – Main Carousel Image
  • The Logo

To help the browser decide which image to use, we need to pass it the rules for how big the image should be, based on the browser’s display width. If we do not provide any rules, it assumes the image will fill the page. The rule is placed in an attribute called sizes, which helps pick an image with a width that will suit (equal to or larger than the size it will be displayed at).

This is the tricky bit, because images can grow and shrink as the browser width changes. Look at a category page and see how the product cards move around and change size as you change the width. Or the product page where the image jumps to full width on small widths.

sizes uses media queries based on width to define the rules.

We have developed a Responsive Image Analyzer tool to work out optimal sizes values. And it’s accessible from the app. Once you have entered a URL to analyse and the CSS selector for the image in question, you can start the analysis. We’d be happy to go through that for you. Just reach out.

For those that would like to learn more…

Before I developed the tool, I determined the sizes by changing the browser size to see when layouts changed. I then inspected the CSS at each layout to find the rules that determined the image’s size and the width that triggered it. Lots of manual analysis and not as accurate.

Some examples of sizes values:

100px

The image is always 100px wide. e.g. the small brand image.

100vw

The image always fills the screen. 100% viewport width. This is rare, as themes tend to have a max content width. e.g., the image fills the screen up to 1400px wide, then it sticks at 1400px. A typical banner image where the main content never exceeds 1400px wide:

(min-width: 1400px) 1400px, 100vw

For a product’s main image, it may be full-width (100vw) until the page is 800px wide, then half-width (50vw) until 1100px, where it stays at half the width of 1100px.

(min-width: 1100px) calc(1100px / 2), (min-width: 800px) 50vw, 100vw

Above, we introduce the calc() function, which performs calculations. It could be replaced with the result (550px), but I did this to make it clear that it is half the content’s maximum width (1100px).

Queries do not have to be this complex; they can be more complex to account for borders. However, simpler queries could be used to ensure the result is a size larger than the required width. There is a break-even point between accuracy and effect. But for fun:

(min-width: 1200px) calc(1200px / 4), (min-width: 801px) 25vw, (min-width: 551px) calc(100vw / 3), 50vw

Product card images are quite complex. The cards expand to fit the page, and the number of cards can change. In this case, the queries deal with 2, 3, or 4 cards side by side, with a max content width of 1200px.

calc(100vw / 3) is a more accurate way than 33.3vw to say a third of the viewport.

It turns out that product card images don’t change much in size because of the changing column count. A query of ‘260px’ would pick the same image most of the time.

(min-width: 1200px) calc(1200px / 4), (min-width: 801px) calc(100vw * 0.75 3), (min-width: 551px) calc(100vw / 3), 50vw

Guess what this one is! 2 or 3 product cards with a sidebar when the width reaches 801px.

Here are the settings for a vanilla Cornerstone theme:

ImageCSS SelectorSizes
Product Page – Main Image.productView-image–default(min-width: 1071px) 500px, (min-width: 810px) calc(50vw – 35px), (min-width: 542px) 500px, calc(100vw – 42px)
Category Page – Main Image.category-header-image(min-width: 1286px) 1116px, (min-width: 1262px) calc(96vw – 111px), calc(100vw – 42px)
Blog Posting – Thumbnail Image.blog-post-figure img(min-width: 234px) 190px, calc(86vw – 11px)
Brand Page – Main Image.brand-image-container img100px
Home Page – Main Carousel Image.heroCarousel-image(min-width: 1404px) 1400px, 100vw

How it works

There are two techniques for controlling how images are loaded.

Preloading images

A line of code is added to the page head, requesting that the browser load a specific image as early as possible (preload) and as quickly as possible (fetchpriority=”high”).

For built-in features, only the sizes query needs to be specified to add the preloads.

The preload code accesses the Stencil object to get information about the images to preload.

Modifying images

Modifications can convert a lazy-loaded image to an eagerly loaded one, such as the product main image.

Like preload, this feature needs the sizes query. It also needs a CSS selector to identify the image on the page.

It monitors for images being added to the page and processes each one accordingly.