The problem with one-size-fits-all backgrounds
Many sites ship heavy background images that aren't tailored to the screens they're served on. A single large image file may be perfectly adequate for a desktop monitor, but that same file is wasteful on a mobile phone where a much smaller, lighter image would do. Using media queries to serve responsive background images is a straightforward way to cut transferred bytes and speed up page loads.
To see the issue in action, open the unoptimized demo in Chrome and check the Network tab after reloading. The only request is background-desktop.jpg at roughly 1006KB. Resize the browser window and reload again—no new requests appear, confirming that the same image is used at every viewport size.
The CSS controlling this behavior lives in style.css:
body {
background-position: center center;
background-attachment: fixed;
background-repeat: no-repeat; background-size: cover;
background-image: url(images/background-desktop.jpg);
}
These properties work together to stretch or crop the image to fill the screen:
background-position: center centercenters the image both vertically and horizontally.background-repeat: no-repeatprevents tiling.background-attachment: fixedkeeps the background from scrolling.background-size: coverscales the image to cover the entire container.background-image: url(images/background-desktop.jpg)supplies the image itself.
Serving one image for all screens has two downsides. First, every user downloads the same byte count even when a phone could display a far smaller file just as well. Second, on narrow viewports, cover may crop out important parts of the image.
Switching images with @media rules
The @media rule lets you define breakpoints at which different styles—and therefore different background images—apply. The approach is simple: remove the hard-coded image URL from the main rule, then declare per-breakpoint image rules.
body {
background-position: center center;
background-attachment: fixed;
background-repeat: no-repeat; background-size: cover;
background-image: url(images/background-desktop.jpg);
}
Define one rule per standard device category, keyed to max-width:
For mobile screens up to 480px:
@media (max-width: 480px) {
body {
background-image: url(images/background-mobile.jpg);
}
}
For tablets between 481px and 1025px:
@media (min-width: 481px) and (max-width: 1024px) {
body {
background-image: url(images/background-tablet.jpg);
}
}
For desktop devices above 1025px:
@media (min-width: 1025px) {
body {
background-image: url(images/background-desktop.jpg);
}
}
The optimized stylesheet applies the correct image based on the viewport's current width, so users on phones pull down only the mobile asset.
Verifying the savings
Open the optimized version, narrow the viewport below 480px, and reload. The Network tab now shows background-mobile.jpg—the desktop image is never fetched. The mobile file is about 67% smaller than the desktop original. As you widen the viewport past the breakpoints, the tablet and then desktop images load in turn.
Background images and LCP
CSS background images can be LCP candidates, but they aren't visible to the browser's preload scanner. That means the request may not go out until the parser hits the rule, which can delay your LCP. If an LCP candidate can work as a regular <img>, prefer that—the preload scanner will discover it and start the request early, especially with srcset and sizes for responsiveness.
When a background image can't be avoided, you can preload the right variant yourself. The <link> element's media, imagesrcset, and imagesizes attributes tell the browser a resource hint applies only under certain viewport conditions, preventing wasted preloads for images that don't match the current screen.
A look ahead: image-set()
Media queries are broadly supported and get the job done today. A newer CSS feature, image-set(), can achieve the same result with fewer lines of code, but browser support is not yet universal. It's worth tracking as an eventual alternative.



