I came across an interesting little problem while working on a web project with the GF. She wanted to display a background image on her pages which would automatically fill the entire viewport, without tiling. She also wanted to be able to infinitely resize the browser window and have the background redraw accordingly.
“Oh sure,” says I, “we can do that. No problem.”
Only, it turned out to be a little trickier than I anticipated!
I quickly realised that there’s currently no way to do this directly with the background properties.1 CSS3 provides a background-size parameter that would’ve been perfect. But with cross-browser CSS3 support being about as imminent as the collapse of the sun, I had to find another solution.
After a couple of hours of Googling and with numerous false starts behind me, I eventually realised that what I needed to do was to build my design on three layers.
The first is simply the base layer. In this layer we define a width and height of 100% and we remove all padding and margins:
html, body { margin: 0; padding: 0; width: 100%; height: 100%; }
The second layer contains the background image. The image also has its width and height set to 100%. Additionally we set a z-index, position the image and “fix” its position:
#bg_image { position: fixed; top: 0; left: 0; z-index: 1; width: 100%; height: 100%; }
Our third and final layer is a container for the content itself. This is an absolutely positioned block with width and height set to 100% and a z-index that places it above the image layer:
#scrollable { position: absolute; width: 100%; height: 100%; top: 0; left: 0; z-index: 2; }
Thus the background image is contained in a dedicated, fixed layer and the content in a layer that sits on top of it. Both layers are completely independent of each other.
As you can see, the CSS turned out to be relatively simple. Luckily enough, so is the HTML:
<body>
<div><img id="bg_image" src="/path/to/image.png" alt="" title="" /></div>
<div id="scrollable">
… content …
</div>
</body>
One div for the background image layer and one for the content. Easy!
It should be noted that the profile described above results in a background image that will be automatically resized in both the horizontal and vertical axes. More often than not this is going to result in a distorted image due to an incorrect aspect ratio. This didn’t matter in the GF’s case because she wanted to use abstract images for her backgrounds and quite liked the resulting pixelisation.
If, however, it’s important to retain the aspect ratio of your images, then only trivial changes are required to the CSS. The background image I’ve used on the page, “25 Most Dangerous Programming Errors,” for example, resizes only on the horizontal axis. The height of the image is governed by the aspect ratio of the image rather than by the CSS. Thus its perspective is maintained and the image never looks distorted. Compare the source of that page with this and you’ll see only minor differences between them.
So, as you can see, this technique offers a lot of flexibility for a very small expenditure in complexity. I’m glad I managed to figure it out (keeps the GF quiet anyway).
Last Revision: May 12th, 2009 at 21:52
Short URL: http://wp.me/phEOu-pF (Tweet This!)
Nice tip. One of these days I should really get around to learning CSS. And I mean *really* learn it. Not just hack around until something appears to look marginally as I intended but having no clue why
For fun and frustration in equal doses — try learning CSS!
Great explanation. I’ve done this a few times in flash and I’ve been looking for a way to do it in CSS since part of me always feels like I’m “cheating” with flash…
The one thing I’m trying to do differently is to add a fade-in effect with the entire page including background using JQuery. Does anyone see any reason why the technique described on this page could not be combined with the jquery fade in function explained here?
http://wdlog.com/tutorials/how-to-fade-all-the-pages-with-jquery/
Let me know what you think! I’m pretty new to using javascript instead of flash for effects, so any insight would be awesome. I’ll be your friend forever.
I’m glad you like the technique Bowser. I don’t see any reason at all why this technique and the jQuery fade can’t be combined as you describe. In fact, I’m intrigued now. I’m going to try it out. I’ll document the results here in a day or two (I’m kind of busy at the moment). Of course, if you get there first… please let us know here.
You got it DarkBlue. I’m planning to pick at it tomorrow so I’ll definitely post when/if I get it sorted out.
Thanks you saved the day with this one. It was so easy I failed the first time trying too hard. I spent hours on his in jquery and did not get it to work in all browsers. This has worked well enough!
and how the heck did you get my user pick to show without me uploading it?!!! My god that was awesome!!
@bradley: Always pleased to learn that what I write here has made a difference to someone, somewhere. Your user picture comes from the Gravatar service (http://gravatar.com/) where you presumably have registered at some point. If you haven’t then please feel free to continue to bow in awe at my most-amazing programming skills.
wow .. that was amazing tech tip !
will keep it in mind ! twitting out this article @v_render @veeroo18
No problem v-render. I’m glad it was useful to you. Thanks for the Tweets.
thanks for this!
could you please help me ?
i had a code, but it doesn’t work
i want the background to automatically resize and fixed scroll
code:
…
body { background:#040507 url(http://i37.tinypic.com/29xxggp.jpg) top center no-repeat; height: 100%; left: 0px; position: absolute; top: 0px; width: 100%; z-index: 0; color:#bbb; font:12px/14px helvetica, arial,Sans-serif; }
…
why doesn’t it work ?
Because your code is incorrect. You can’t make a background render fullscreen that way. Use the code I’ve posted here, it does exactly what you want and involves only a little extra code.
[…] Link to author’s blog […]
Wow, this is cool and almost exactly what I’m looking for. I’m not good with CSS (yet, one day) but am using a nice JQuery image rotation function. I want to give the illusion of rotating background images. But I want to contain the height
Here’s my question. How might I make the bg_image span the width of the browser window, but keep the image height fixed between a header and footer? It’s ok that the image distorts.
Anyway, thanks for the great tutorial!
@ChrisS: How do you mean my friend? Like this one?
Hi, Jonathan. Thanks for responding!
The client specifically referenced a site using Flash (IANAFlashDeveloper) though that site changed a bit. But I think i can convey what was requested.
Check out this site, and imagine the entire black area (where the video clip is placed) as an image, with the four rectangles under the clip, layered over the bg image:
http://www.thecorner.com/
Just to add, the image would always be 100% of the width of the browser window, but the height (as you can see on thecorner.com’s black middle section) would always be fixed.
I know, seems odd, but the customer is always yada yada yada.
Okay ChrisS, I understand a bit better what you are trying to achieve now. You could certainly do that with (X)HTML and CSS as my examples here illustrate. However, as you’ve already indicated, your customer’s site is built on a Flash component and that’s a different ball-game. I know it can be done in Flash, I’ve seen it on many sites, but I don’t know how. I have absolutely no idea about Flash development as it’s not something I’ve ever worked with. Sorry.
Oh sorry, I wasn’t being clear. That’s not my customer. That’s the site my customer wants to emulate. I want to do this in CSS, not in Flash.
Thecorner.com uses Flash, but I don’t. That’s why I’m here.
@Chris S: Oh I see. My bad, I completely misunderstood. I’ll email you directly and we’ll see if we can’t get it working between us.
No problem, Jonathan. I’m easily misunderstood . I look forward to hearing from you. Thanks!
Jonathan, thanks! This is a great simple solution.
I see that the image looses proportions, right?
Take a look here: me.com
What do you think is the trick used?
Thanks,
Laura
I got it.
2 images: one positioned static at 50% the other in the bg set with the property to repeat-x and also set to be at 50%.
This makes the visual trick.
Thanks,
Laura
Exactly right Laura, in fact they could even use just a plain colour for the background and set the main image above it.
It’s easy to do this with the technique I have described here, and it’s easy to maintain the correct aspect ratio (so the proportions aren’t lost). It all depends on just a couple of minor variations in the CSS.
Did you look at the other examples on this page, a couple have them have images that don’t loose their proportions?
Kindest regards,
Jonathan.
Kool!!! Simply neat!