Rails will soon be making it possible to enable browser built-in lazy-loading of images across your whole app.
Read on to learn about the feature and what to consider before using it.
This is (hopefully) the first part in a series about upcoming features of Rails. Follow me on Twitter for more.
Until recently web browsers loaded all images on the page eagerly, even when hidden far off the page. That means lots of wasted bytes since the visitor downloads images they never end up seeing.
For supporting browsers, native lazy loading will only load images when they are about to scroll in to the viewport.
This progressive enhancement seems like a big win. Less wasted energy. 🌎❤️
How to setup app-wide lazy image loading in Rails
In Rails you will be able to specify
config.action_view.image_loading (in your app or environment specific config) with either
Rails.application.configure do config.action_view.image_loading = "lazy" end
:lazy) will mean all HTML image tags generated by the Rails image tag view helper will have the
loading="lazy" attribute. This will tell supporting browsers to lazy-load the images.
Equally setting to
:eager) will mean image tags will have the
loading="eager" attribute, i.e. the browser to use the current eager loading behaviour (which is the default loading strategy).
The Deep Dive: But why
eager as default?
There are some concerns about having the default image loading to be “lazy”, both at browser level and in Rails.
Lets dive deeper…
1. Privacy concerns 🛡
First there are privacy/fingerprinting concerns for browser vendors.
Browser developers have a really tough time. It seems to be a constant fight to stay ahead of tracking attempts.
Eg, the HTML spec on lazy loaded resources suggests browser devs hide the true scroll speed of the user for this reason:
“typical scrolling speed on the current device could be imprecise so as to not introduce a new fingerprinting vector.”
2. The dreaded Layout shift
Then there is layout shift, the annoying jumping of content on the page when something changes.
In this case, if the user is scrolling and an image is lazy-loaded, but isn’t ready by the time the user scrolls to its position, they may see the layout change when it finally does pop in.
The general recommendation to prevent layout shift is:
- always ensure images have their
heightattributes specified on the HTML tag (or use CSS).
But it is often the case that these attributes have not been specified.
"lazy" will set the image to lazy load even if there are no dimensions specified.
From web.dev article on the topic:
“If you are unable to include dimensions for your images, lazy-loading them can be a trade-off between saving network resources and potentially being more at risk of layout shift.”
Why care about Layout Shift (CLS)?
- layout shift is annoying for viewers,
- lots of layout shift may affect your search engine ranking from this year when CLS is added as a metric for user experience.
3. Lazy loading affects “preload”
The Chromium team recommends to not lazy-load images that will start off in the viewport (ie images high up on the page or “above the fold”) due to the
loading attribute preventing “preloading” of images.
Addy Osmani has written up all about preload. Essentially the preload declaration tells the browser to make requests for resources without blocking the document’s onload event.
But as the browser scans for resources it might preload, it will skip any that are marked as
This may affect the so called “time to interactive” of your page by disabling the preload optimisation on those images.
A higher TTI may affect user experience and ranking in the same way as CLS.
Why care about Time to Interactive (TTI)?
- waiting to interact with a page is annoying for viewers,
- long TTI may affect your search engine ranking from this year when TTI is added as a metric for user experience.
To enable the built-in browser lazy-loading, specify
config.action_view.image_loading with the value
"lazy". But note the caveats discussed above.
Personally I will be enabling the feature as soon as possible and evaluating CLS (Cumulative Layout Shift) and TTI (Time to Interactive) to check for any degredation in real life usage. User experiece and search rank is important, but our planet more so.
If you found this article useful, why not follow me on Twitter for more.
Target Rails release
You can use native lazy-loading now
Of course you can set HTML attributes on images already by passing to
<%= image_tag "pic.png", loading: "lazy" %>
The main point of the new config is to allow this to be set application wide.
What about browsers that don’t support native lazy-loading
Browsers which don’t support the
loading attribute will safely just ignore it.
lazysizes by the web.dev team.
The lazy loading attribute is not image tag specific
It is actually defined as part of the “Fetching resources” section of the “Common infrastructure” part of the HTML specification. For example, apart from images it is also defined for use with
“anti-tracking measure, because <…> it would be possible for a site to track a user’s approximate scroll position throughout a session, by strategically placing images in a page’s markup such that a server can track how many images are requested and when.”
loading attribute is not enabled by default in Safari
While enabled already in Chrome and Firefox, the feature is still experimental in Safari, both on MacOS and iOS… hopefully it will follow suite and be enabled by default soon.
- The feature pull request at
- The excellent “Browser-level image lazy-loading for the web” on
- The HTML spec on it
- Supporting browsers
Synchronous / Asynchronous Image Decode support for image tags!
Follow me on Twitter to find out when I publish.
Read more • Coming soon to Rails