Full Screen Images – The Right Way

A guide on how to make an image on your website fill the entire browser window and making its source adapt to the environment using a Responsive Image implementation

Take a look at the demo and its code.

What I mean is actually not 'full screen' but rather 'full window' or 'full viewport'. Thus an image filling the entire width and height of the browser window. This is something that came up sooo many times during the three years I've been working in Frontend Development. Not that I don't like it. I think these kind of images make a very powerful impression and make for some cool layouts and designs. When I was working on a website for the famous Swiss watch manufacturer IWC Schaffhausen I had to implement window-filling videos and poster images. And as I had some new insights into this topic I thought it'd be a good moment to share what I learned. These kind of images usually get displayed quite big, so the file has to have a high resolution, which means a big file size the browser has to download. This is something that's often not done properly out in the wild web. Because do you really want your phone to download an image 3000 pixels wide? Right, you don't. Read how it's done the right way below.

Sizing and Positioning

CSS Only

Some years ago this wasn't really possible without manually calculating and applying dimensions using JavaScript. But luckily CSS and the respective browser support improved a lot. There's a property called object-fit which let's you do the whole magic in one line:

img {
    object-fit: cover;
}

Doesn't fill the window? Well let's consider the scenario that you've placed the <img> tag inside the <body> and defined the CSS as above. To understand why it didn't work, you have to know that this property doesn't size and position the <img> tag but rather what's inside. Which is, well, the actual image. This maybe sounds a bit strange to people who know how to do it manually. But it's really cool this way. It let's you size and position the <img> in a traditional way using only CSS and then just say that the actual image should always cover the area of the <img> tag. So what we need to add:

img {
    width: 100%;
    height: 100vh;
}

And now have fun resizing your browser window! :) Furthermore this works for <video> too.

object-fit is supported in all modern browsers except for Internet Explorer, Edge and IE Mobile. If you need to support these, you have the following options:

  • Fallback to just fill the width or the height of the window
  • Mimic the behaviour using aspect-ratio media queries
  • Use the background-size CSS property
  • Use JavaScript

I'd go with options one or four. Option one is a pragmatic fallback solution. The user sees the exact same information, just not as beautifully laid out. With option two you compare the aspect ratios of the image and the window and scale the image to either fill the width or height of the window. But I'm not really sure how well these kind of media queries are supported. Could be quite good actually. Option three is easy to do and it works exactly the same as when using object-fit but you have to set the image in CSS as a background image. Personally I think images belong into the HTML and not into your stylesheet. It's even worse when you want to serve different image files for different screen sizes and pixel densities. But hey, it works. Option number four is quite easy to implement as there are many ready to use solutions out there. Read about it below.

Using JavaScript

The math is actually quite easy. First you have to calculate the ratios of both the image and the window. This means, the width divided by the height. If the ratio of the image is smaller than the one of the window, the image's width will equal the window's width and its height will be proportionally upscaled. If on the other hand the image's ratio is bigger than the one of the window, the image's height will equal the window's height and its width will be proportionally upscaled. After that the only things left to do are calculating the images position to center it within the window or its container, applying the calculated dimension and position and maybe adding an event listener for the resize event to make sure the dimension and position get updated when the visitor resizes the window.

But as I already mentioned you don't have to do this yourself, there are many solutions out there that you can use. For example the advanced Fit.js by Justin Windle or the simpler solution foreground-size.js by myself. You just call the respective function and pass the desired images. Done.

This way you can be sure it works in every browser. Or even better, do it only this way for browsers not supporting object-fit and for those which do, you use the CSS property. There are cases when you maybe want to do it with JavaScript in modern browsers too. I've read about people having problems with animation performance when having set the background image's size with background-size: cover; on the animated element. So maybe those problems could also arise when using object-fit. But that doesn't have to be the case as I haven't tested it.

Considering File Size: Responsive Images

Responsive Images are all about serving the most fitting image size/file based on window size / screen pixel density and network connection speed. This is the part which I didn't know how to do until recently. The problem is that this way of displaying the image is very dynamic. You can't just say, as you'd normally do: "At this window width the image is 'this' wide and at that window width it's 'that' wide." I knew it's possible using JavaScript, but that has its own drawbacks (SEO, speed, complexity). But then while working on the IWC website I came upon a discussion where Alexander Farkas, one of the guys behind Modernizr, proposed a solution for handling this case with the native responsive image implementation.

So this is how it looks:

<img    src="image-1000w.jpg" 
        srcset="image-500w.jpg 500w, image-1000w.jpg 1000w, image-1500w.jpg 1500w, image-2000w.jpg 2000w, image-2500w.jpg 2500w, image-3000w.jpg 3000w" 
        sizes="(max-aspect-ratio: 16/9) calc(100vh * (16 / 9)), 100vw"
/>

In the src attribute a fallback image for browsers not supporting responsive images is defined and in the srcset attribute are different image sizes listed. The important part is the content of the sizes attribute. Here we have to work with the image's aspect ratio again. Basically it says: "If the window's ratio is smaller or the same as the image's, the image's width is so it's height equals the window's height, otherwise its width equals the window's width." The first scenario is the tricky one. There the image's width is proportionally calculated based on the window's height. When you want to use this you only have to fill in your own image's aspect ratio ('16/9' and '16 / 9'). I think this is pretty cool, thank you Mr. Farkas!

Take a look at this in action in the demo. In the demo all the available image files have text on them showing their resolution, so you know which one's been downloaded. As mentioned already, in browsers not supporting responsive images the file defined in the src attribute will be chosen. If you want that the correct image gets downloaded even in these browsers, use the matchMedia polyfill and Picturefill (in that order). You don't have to change your HTML at all. You can check the browser support here. One more thing. Even if your browser supports responsive images, it doesn't mean it will always switch the image file when resizing the window. Some do this only if the currently downloaded one is not good enough for the new window size and the network connection is fast enough, or even only when the page is reloaded. If you want to be sure to see the switching, clear your browsers cache, make your window really small and open the demo URL. Then increase the window size and reload the page every time you've resized the window. Now you should see the image getting updated as the window gets bigger.

Okay, to take this further, let's say the image covers an element on your page instead of the window (or an element with the window's dimensions). The second part of the sizes attribute is easy, you just determine it as you do with every normal responsive image, check how wide it is in comparison to the window. For example if its width matches its container's, which is 70% of the window's width, you'd write 70vw instead of the 100vw above. Or if its width is not fluid you'd just set it directly. For example 400px instead of 100vw. The problem is its height. If it's set, easy, just switch the 100vh in the code above with its height. For example 300px. But if its height is dynamic (based on its content) we have a problem. I guess then we're back at a custom JavaScript solution. Which is totally doable based on the same calculations used for sizing it.

I hope this helps someone else too, as especially the full screen image is quite a common use case.