How To: Resizeable Background Image

Published by Chris Coyier

If you are looking for how to do FULL SCREEN BACKGROUND IMAGE, go here.

My friend Richard recently came to me with a simple CSS question:

Is there a way to make a background image resizeable? As in, fill the background of a web page edge-to-edge with an image, no matter the size of the browser window. Also, have it resize larger or smaller as the browser window changes. Also, make sure it retains its ratio (doesn't stretch weird). Also, doesn't cause scrollbars, just cuts off vertically if it needs to. Also, comes in on the page as an inline <img> tag.

Wow, that's a tall order. My first thought was... uhm, No. But of course this is just the kind of challenge I enjoy, so I set about to thinkin'. Ultimately, I found a pretty good solution and we turned it into a pretty neat little project. First, check out the finished project, then I'll show you how it was done:

Finished Project: What's The Weather? Offline

resizeablebackgroundimage

Go ahead and resize your browser window around and notice how the image will resize to fit. It doesn't do it "on the fly", but it does work. It also meets all the other requirements: no scrollbars, and retains pixel ratio.

First Attempt

Well my first thought was that this really needs to be a CSS background-image. This will fill the screen edge-to-edge if the image is big enough. It also can be centered, so I figured this would be good enough. Large browser windows will reveal more of the picture and smaller ones less of the picture. If applied to the body tag, this will fill the screen nicely with no scroll bars. Pretty good solution I thought, even if it isn't technically resizeable, since you can't set the size of a CSS background-image. Here is how I went about this first approach.

<head>
	....
	<script type="text/javascript" src="js/jquery.js"></script>
	<script type="text/javascript">
	$(document).ready(function() { 
		$("img.source-image").hide();
		var $source = $("img.source-image").attr("src");
		$('#page-body').css({
			'backgroundImage': 'url(' + $source +')',
			'backgroundRepeat': 'no-repeat',
			'backgroundPosition': 'top center'
		});
	}); 
	</script>
</head>
<body id="page-body">
	<img class="source-image" src="images/image.jpg" alt="" />
</body>

You guessed it, jQuery. The above code will hide the image on the page, but snag it's "src" attribute and apply it as a background to the body element (via its unique ID "page-body"). Check out an example of this in action.

 

Second Attempt (better)

While the first attempt did a decent job, it failed at the most fundamental level: it wasn't "resizeable". So time for another take. In order to control the size of an image displayed on the screen without literally altering the file itself is to display it inline with the <img> tag. With the img tag, we can set "width" and "height" attributes to control the image's size. If we can get our hands on the exact pixel width of the browser window, we can use that number in the width attribute of the image and control its size while retaining the ratio.

We can, again, use jQuery and the dimensions plugin to get our browser window's width. Then we'll use that number to set the width attribute on the image, which we'll give a unique class name "source-image". We will need to do this as soon as the DOM is ready so it happens before the image even starts loading. We can also do this (FTW) any time the window is resized. Here is how it goes down:

<script type="text/javascript" src="/js/jquery.js"></script>
<script type="text/javascript" src="/js/jquery.dimensions.js"></script>
<script type="text/javascript">
	$(document).ready(function() { 
		var $winwidth = $(window).width();
		$("img.source-image").attr({
			width: $winwidth
		});
		$(window).bind("resize", function(){ 
			var $winwidth = $(window).width();
			$("img.source-image").attr({
				width: $winwidth
			});
		 });
	}); 
</script>

In order to get this inline image to behave more like a background image, we can use that unique class we applied to apply some absolute positioning.

img.source-image {
	position: absolute;
	top: 0;
	left: 0;
}

Because of this absolute positioning, anything that you want to put over it will also need positioning and a higher z-index value. If your source image is particularly tall, or your browser window is particularly wide, the image could easily become taller than your browser window and force a vertical scrollbar. In order to prevent this, simply set the overflow value on your body to hidden:

body {
  overflow: hidden;
}

Third Attempt (best)

Forget this javascript business! Thanks to Anders comment pointing out Stu Nicholls version, here is an even better way to handle this without the need for any javascript at all!

Since we already have a unique class on the image, the image is absolutely positioned, and the scrollbars thing is already taken care of, let's just set the width using a percentage directly in the CSS:

#img.source-image {
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

See a demo of this in action. This is the best solution yet, because the resizing happens on-the-fly for a nice fluid feel, and doesn't rely on any javascript whatsoever.

More about WhatsTheWeather.net

I just did the simple design for What's The Weather (Update Nov 2013: now offline), but Richard did all cool coding to make it work. From what I understand, it is a chain of 3 different APIs. First it gets your IP address and uses an API to turn that into a city and state. Then it uses some weather API to get the current weather. Then it uses the Flickr API to get a random image with tags that match the weather. If if it can't get your zip, it will ask you for it, like on the iPhone (which it also auto-detects and handles a bit differently). All done up with Ruby on Rails. Pretty fancy dancin'!