A fullscreen background image for mobile Safari

Providing a fixed, fullscreen background image for mobile Safari comes with it’s own set of small challenges. There are limitations on the number and size of the resources that can be loaded, large images will be scaled automatically to fit the browserwindow and older versions of mobile Safari have no support for fixed positioning. In this article we will explore how we can create a webpage with a fullscreen, fixed background image that will also look good on older versions of mobile Safari. We will use a CSS only approach because JavaScript feature detection for fixed positioning seems to be difficult and too ‘heavy’ for what we are trying to achieve.

Viewports, images and fixed positioning

Two viewports

Mobile browers have two viewports, the “visual area” which has the dimensions of the browserwindow and the “layout viewport” which has the same dimensions as the webpage that is being displayed. Because of this we are able to browse webpages on mobile devices that are actually intended for a desktop experience and use pan and zoom to explore the content. Otherwise these ‘desktop’ webpages would be crammed into the mobile device’s browserwindow and be unusable. An indepth look on mobile browser viewports can be found in the article A tale of two viewports on quirksmode.

Support for fixed positioning

Mobile Safari for iOS up to version 4.3 has no support for fixed positioning and will position these elements relative to the layout viewport. That means that these elements will scroll together with the document and appear te be not fixed at all. So for older versions of mobile Safari we will have to provide an alternative solution.
In iOS 5+ position: fixed is partially supported. In this case that means we can use a fullscreen background image with the same dimensions as the visual viewport that will stay fixed when the user scrolls the page.

The code


<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <title>A responsive webpage with a fullscreen background image</title>
  <link rel="stylesheet" href="css/main.css">
</head>
<body>
  <header class="page-header">
    <section>Your content</section>
  </header>

  <div role="main">
    <section>Your content</section>
  </div>

  <footer class="page-footer">
    <section>Your content</section>
  </footer>

  <div class="page-bg"></div>
</body>
</html>

The viewport metatag

By default mobile Safari renders a webpage in a ‘virtual’ viewport that has a width of 980px and then scales it down to fit the visual area of the iPad or iPhone. Because our webpage targets iOS specifically, the first thing to do is to set the width of the layout viewport equal to the width of the visual area. We can do so using the viewport metatag. See the highlighted line in the head-section.

The width property is set to device-width. The device-width is the actual width of the screen in pixels. For example the iPad has a ‘real’ screen resolution of 768 px * 1024 px dispite the fact that it uses techniques to upscale this resolution to a higher density.

The initial-scale property controls the zoom level when the page is first loaded. We set the value to 1 and prevent any zooming from taking place. The maximum-scale property set to 1 disables zooming which can occur for example when the orientation of the device changes.

A seperate element for the background image

Mobile Safari does not support background-attachment: fixed so applying a fixed background-image to the body element will not work. As a workaround we will add a div element that holds our background image. See the second highlighted line just before </body> in the markup. We give the div a fixed position and place it underneath the content of the page with z-index: -1. Also we only want to serve the background image to larger screen sizes so we place the stylerules inside a media-query like this:


/* min 768px */
@media only screen and (min-width: 48em) {
  .page-bg {
    position: fixed;
    top: 0;
    right: 0;
    left: 0;
    height: 1707px;
    background-image: url('../img/bg-image.jpg');
    background-position: 50% 0;
    background-repeat: no-repeat;
    z-index: -1;
  }
}

The height of the div is set to the same height as the background-image. When we will be targeting different versions and orientations of the iPad with specific media-queries later on the height will be adjusted.

iPad 3

Support for position: fixed for the iPad 3 is good enough so we are able to provide this device with two seperate background-images that have the exact dimensions of the screen in portrait and landscape orientation. We use the query (-webkit-min-device-pixel-ratio: 2) to make sure these stylerules do not apply to the iPad 1 and 2 and adjust the height of the ‘background’ div to be the same height as the image. Now when the orientation of the device changes, a different background-image will be served.


/* Page background-image landscape for iPad 3 */
@media only screen
  and (min-device-width: 768px)
  and (max-device-width: 1024px)
  and (orientation: landscape)
  and (-webkit-min-device-pixel-ratio: 2) {
  .page-bg {
    height: 768px;
    background-image: url('../img/bg-landscape.jpg');
  }
}
/* Page background-image portrait for iPad 3 */
@media only screen
  and (min-device-width: 768px)
  and (max-device-width: 1024px)
  and (orientation: portrait)
  and (-webkit-min-device-pixel-ratio: 2) {
  .page-bg {
    height: 1024px;
    background-image: url('../img/bg-portrait.jpg');
  }
}

iPad 1 and 2

Mobile Safari for iOS up to version 4.3 has no support for position: fixed. For these ‘older’ devices we have to provide an alternative solution. With the code we have now the div with our background image will scroll together with the document and that’s fine. But what if the height of the content is larger than the height of the image? The bottom edge of the image will be visible and this is not the look we are aiming at. To make the background appear to be full-screen we will load an image that has the same width as the screen and at least the same height as the content. If you have a lot of content on the page or the height of your content is not known this might not be the best approach. To be more flexible you can make the height of the image as large as possible keeping performance and Safari resource limitations in mind. We can target the iPad 1 specifically with the query (-webkit-min-device-pixel-ratio: 1).


/* Page background-image landscape for iPad 1/2 */
@media only screen
  and (min-device-width: 768px)
  and (max-device-width: 1024px)
  and (orientation: landscape)
  and (-webkit-min-device-pixel-ratio: 1) {
  .page-bg {
    height: 1900px;
    background-image: url('../img/bg-scroll-landscape.jpg');
    -webkit-background-size: 1024px 1900px;
    background-size: 1024px 1900px;
  }
}
/* Page background-image portrait for iPad 1/2 */
@media only screen
  and (min-device-width: 768px)
  and (max-device-width: 1024px)
  and (orientation: portrait)
  and (-webkit-min-device-pixel-ratio: 1) {
  .page-bg {
    height: 2500px;
    background-image: url('../img/bg-scroll-portrait.jpg');
    -webkit-background-size: 768px 2500px;
    background-size: 768px 2500px;
  }
}

Images and background-images that are larger than the visual area will be scaled back to fit inside the browserwindow. To prevent this from happening to our background image we can specify it’s size with the background-size property.

Overlapping support for fixed positioning on iPad 2

The iPad 2 (with iOS 5.0) does have support for fixed positioning but because we are using media queries based on device features rather than browser features this device will be served the image with the larger height and display it as fixed. This is a limitation of the CSS only approach and you should keep this in mind when creating the images.

Note

It is generally considered a bad practice to design and develop with specific devices in mind. Try to serve all devices the best that you can first and then make adjustments for specific devices or browsers.