I’ve recently been working on an update/overhaul of both my various websites and the server backend. As part of this process I’ve been trying ot make sure everything is using the latest standards to maximise performance and compatability. One of the best features of recent versions of wordpress is the native support for responsive images — where the imgset=”” attribut eis used to supply alternative sizes of images in a group so the browser can use the most appropriate. In combination with async loading and lazy loading this can make pages load far faster whilst still looking good to all visitors. However css has not adopted these newer features so background images are much trickier to deal with. It can be done though…
It is possible to use media queries in CSS to provide an appropriately sized image for most visitors. However here is no equivalent of async or lazy loading for CSS so your (probably large) image will hold up page rendering which can make a huge difference on a slow connection. The pagespeed insights tool for one of my sites was seeing a render time of around 1 second vs 4 seconds just by adding the background image. 4 seconds it too long, but I didn’t want to lose the background image, so I wondered if it was possible to have a div element with a normal lazy loaded image in it and to fit that to the page and put it behind every other element.
I did some searching and found a CoreWebVitals article by Arjen which talked about the exact same issues I was having. However the code provided there didn’t do what I needed, it appears to be for a div that is meant to be part of the flow of a page.
After some playing around on codepen and a helpful suggestion by luukvhoudt on stackoverflow that google turned up I was eventually able to get code that worked to make a normal image in html act just like a background image. Like a css background I was able to set all of the desirable behaviours…
- Image fills full width of screen
- Image keeps aspect ratio
- Image is vertically centred (so top and bottom are cropped)
- Image stays in position when scrolling page down
- Image doesn’t interfere with any other elements on the page
- Even when viewport becomes ‘portrait’ the image still fills the whole width and height and keeps the correct aspect ratio
- Thanks to HTML the image loads async and lazy so doesn’t impact performance
The code needed was actually surprisingly easy. The HTML code goes immediately inside and at the top of the body tag, and then a little CSS does the rest. Note that you should put the smallest image in the src=”” attribute. I’ve also used aria-hidden=“true” to tell screen-readers to ignore our image since it’s meant to be a background
<div id="bg-container">
<img src="/path/to/bg768.jpg" aria-hidden="true" alt="background" decoding="async" loading="lazy" srcset="/path/to/bg768.jpg 768w, /path/to/bg1024.jpg 1024w" >
</div>
Next the CSS
#bg-container
{
display: inline-block;
overflow: hidden;
position: fixed;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1;
top: 0px;
left: 0px;
}
#bg-container img
{
width: 100%;
height: 100%;
object-fit: cover;
}
“Hi James I realise it has been a long while, but I just checked this on windows 11 (build 23H2)…”