CSS Background Images for Mobile

Kenneth Ahlstrom
The Coder’s Guide to Javascript
3 min readApr 21, 2019

The giant hero background image is everywhere on the web, and it’s really very easy to implement in CSS— on desktop:

body {
background: url('./img/hero.webp') center center fixed no-repeat;

/* Currently Firefox requires background-size declared separately or the background image will be blank */
background-size: cover;
}

That’s it … that’s all you have to do. Except that if you try to load this background image on almost any mobile device, you’ll likely see a blank background. That’s not what we want.

There are a lot of posts about this issue throughout the internet … and a lot of the ‘solutions’ don’t work. So … let’s create a solution that does work. And do so while gaining an understanding of why it works.

Diving into it, let’s first break out our background into a series of individual calls so that it’s easier to talk about each individual component:

body {
background-image: url('./img/hero.webp');
background-position: center center;
background-attachment: fixed;
background-size: cover;
background-repeat: no-repeat;
}

A lot of Stack Overflow answers will tell you that the main issue here is background-attachment: fixed; and that the solution is to change fixed to scroll. That’s not true. In fact, all of the major mobile browsers support the fixed value, but they handle it differently than the desktop does:

For Safari Mobile, Chrome Mobile, and Opera Mobile:

fixed: the background image is positioned but scrolls with content.

So, actually, our problem lies with a different value —background-position: center center; The first center references our vertical positioning, the second references our horizontal positioning. On a mobile device, this vertical positioning of center will place the background at the center-point of the entire vertical height of your page … not just the viewport. In all likelihood, that means your background image will not be visible at the top of the page.

The solution?

background-position: top center;

Well … almost. It seems that background-size: cover; also tends to give us trouble on mobile devices.

The description of cover, as given by MDN, is:

Scales the image as large as possible without stretching the image. If the proportions of the image differ from the element, it is cropped either vertically or horizontally so that no empty space remains.

When I left background-size: cover; for mobile devices, I did continue to see a background image, but the image was stretched far larger than I would have liked. My inference, informed by how fixed works on mobile browsers, is that cover is stretching the image to fit the entire page, not just the viewport. Again, the solution is relatively straightforward:

background-size: 100vw auto;

The background now scales to 100% of the viewport width. Unfortunately, attempting to scale 100vh height leads to unpredictable results, so we are left accepting whatever scaling a 100vw width can give us. In some cases, it may be acceptable to scale the width above 100 in order to increase the height of the image … just be careful to ensure that your image scales well.

The final CSS also selects for .webp vs .jpg images based on browser-support ( I use modernizr.js to help out here ) and picks an image size to load based on viewport size. It looks like this:

/* Desktop-only view. 
* Largest mobile view is iPad Pro with 1366 in landscape mode
*/
@media only screen and (min-width:1367px) {
:root {
--bg-image-webp: url('./images/hero.webp');
--bg-image-jpg: url('./images/hero.jpg');
--bg-size: cover;
--bg-pos: center center;
}
}
/* Large mobile device screens */
@media only screen and (max-width:1366px) {
:root {
--bg-image-webp: url('./images/hero.webp');
--bg-image-jpg: url('./images/hero.jpg');
--bg-pos: top center;
--bg-size: 100vw auto;
}
}
/* Load a smaller image for smaller screens */
@media only screen and (max-width:970px) {
:root {
--bg-image-webp: url('./images/hero768.webp');
--bg-image-jpg: url('./images/hero768.jpg');
}
}
/* Smallest image for phone screens */
@media only screen and (max-width:500px) {
:root {
--bg-image-webp: url('./images/hero375.webp');
--bg-image-jpg: url('./images/hero375.jpg');
}
}
body {
background-color: #fff;
margin: 0px auto;
padding: 0px auto;
}
.webp body {
background: var(--bg-image-webp) var(--bg-pos) fixed no-repeat;
background-size: var(--bg-size);
}
.no-webp body {
background: var(--bg-image-jpg) var(--bg-pos) fixed / var(--bg-size) no-repeat;
}

--

--

Kenneth Ahlstrom
The Coder’s Guide to Javascript

Developer, Snowboarder, Travel Enthusiast, Adventurer, ENTP. When I write, it’s because I have something to say.