In part 1 of this series we covered cache optimization. Once we've taken care of that, we can be sure that we’re only asking the server to produce a response when absolutely necessary. If you have not yet read part 1, we suggest you start there.
Capellic maintains a suite of nonprofit Drupal websites that have been built over the past several years, using a very familiar but steadily evolving toolset. We adopted a component-driven approach to design and development years ago, and have steadily kept up with the popular tools used in the Drupal community to produce themes that adhere to the pattern. Today we're going to cover the next logical step in your quest for front end performance after you've got the cache sorted out:
Ship the smallest and most optimized media assets required for a visitor to have a great experience.
After caching, the next thing we typically look at on a client’s website is image/video/asset handling. Modern cameras are capable of capturing stunning images at extraordinary levels of detail. The raw images produced by a modern camera can be close to 50MB in size. On a 242MB broadband internet connection (the average in the US in 2022), it will take a full second to download one of those images. According to Pingdom, there are an average of 42.8 images on the typical homepage. If each image was a raw image uploaded directory from a pro camera, that would cause a massive slowdown for every user that loads the page and a massive waste of network transfer and compute resources to transmit information the visitor will never see.
Thankfully, Drupal comes well-equipped with amazing tools for right-sizing your media assets before delivery.
Image styles
Drupal ships with image style support out of the box, and the most obvious thing you can do with this is to resize your images to a consistent and appropriate size for the context they’ll be displayed. This avoids shipping wasted pixels to visitors who will never see them. Drupal’s “scale and crop” image style action is perhaps the most useful, allowing you to perfectly resize a myriad of source images to uniform and efficient outputs that fit any design perfectly. When combined with the Focal Point module, this transformation makes presenting perfectly art-directed images on your Drupal site fairly painless, while also helping performance. The client can upload beautiful and large source images, and site visitors will get just the number of pixels they need in the page output.
Responsive Images
Drupal also ships with support for responsive images, that is, a system that serves differently-sized images to visitors depending on the size of their browser viewport. This allows us to ship beautiful expansive images to large and high-resolution displays (which are more likely to be on a high bandwidth connection) while shipping low-resolution images to vintage Android phones with only 300-400 odd pixels of horizontal real estate to play with (and are more likely to be on a low bandwidth connection).
At Capellic we use a very regimented system of responsive image style curation for our clients. This includes a set of image styles for every image context on the site, with variations for each breakpoint of the site theme, and a variation for various pixel densities (standard, 2x[retina], etc) for each of those breakpoints. This can be a lot of styles to maintain, and we have a custom script to generate derivative image styles for the breakpoints and pixel densities, based on the source image contexts.
This gives us the best chance to serve exactly the right size image to a visitor when they hit a site, no matter what device they may be using, from Google Pixel to 6k iMac, to smart fridge.
Image Optimization & Modern Formats
Aside from shipping visitors the right size images when they need them, there is a lot about an image that controls its size and performance that is not related to the actual pixel count. Images on the web can be served in a variety of file formats, the most common being JPEG and PNG. These common formats, which most site administrators will have their source images in, are not the most size-efficient formats that modern browsers are capable of displaying. At the time of writing, the currently recommended formats are AVIF and WebP, you can read more about formats in this Smashing Magazine article.
WebP support is fairly easy, Drupal core now ships with WebP conversion out of the box, use the “Convert to WebP image transformation in your image styles, and Drupal will take care of the rest. This however does not currently work with the responsive image styles noted above, to support that feature you can look into some contributed modules.
At Capellic we’ve been using the Image Optimize and ImageAPI Optimize WebP modules to handle this, allowing Drupal to render responsive images with webp priority images and jpeg/png fallbacks when the browser does not support them. Additionally, the pipelines supported by Image Optimize allow us to provide additional optimizations to our images, like compression before we convert them to WebP (and compression of the legacy image format if it is all that a browser supports).
Depending on the configuration of your server, you can use a variety of the submodules provided by the Image Optimize module to provide compression. For our sites hosted on Pantheon, we use the reSmush.it submodule to provide image compression since Pantheon does not have the necessary binaries in their containers to perform on-server compression.
Once you’ve combined all the above tools and techniques, you should be shipping just the right size image to every visitor, regardless of the device they use to consume site content.
Image Loading
Another important tool in your arsenal is the use of image tags image-loading attributes. Supported in all modern browsers, and directly supported by the latest version of Drupal core (10.2), the image loading attribute allows you to specify the behavior of the browser concerning when it downloads media assets. The two possible values are “eager” and “lazy”. Drupal core now defaults to “lazy” when you create a new image field. This is the sensible default for most cases. It instructs the browser to not load a media asset until that asset is needed to render in the viewport. The only real exception to this default is for images that will be in the viewport when the page loads. For example, the “hero” image is commonly used on most modern landing pages. The field that renders this image should be set to “eager” so that the image is downloaded as soon as possible which will improve the page load performance by allowing the on-screen content to be rendered sooner.
Lazily loaded images will only be fetched and rendered to the visitor when they need them, and if they never scroll to the image in question, it won’t be delivered to them at all.
There are other media optimization techniques to consider, like the facade-images for embedded videos that Stephen covered in his article, but getting these basics right makes a huge difference to page performance.
That's all for today's entry, next week we're going to dive into a meatier topic, and really the set of concepts that spawned this article series. Has Google been complaining about unused CSS and Javascript on your sites? Have you been getting sub-par LCP scores, even though you've optimized your images on perfectly cached pages? Read part 3 in this series to get to the bottom of it!