// 03.May.2009

Create a Dynamically-resizing Background Image Using CSS

The Web Bot

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).

NOTE: To really see the magic in this, resize your browser window a few times and scroll around. This technique has been tested in Safari, Firefox and Opera running on OS X. Your mileage might vary. Those of you who are reading this in an RSS reader won’t be able to see anything different - come on, get your arses on to the site! :-)
BMW Art Cars
OpenCL
10 Sexy Macintosh Workspaces


  1. Please correct me if I’m wrong!

Last Revision: May 12th, 2009 at 21:52
Short URL: http://wp.me/phEOu-pF (Tweet This!)


39 Comments for “Create a Dynamically-resizing Background Image Using CSS”

  1. 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 ;-)

  2. For fun and frustration in equal doses - try learning CSS! :-)

  3. 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.

  4. 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.

  5. You got it DarkBlue. I’m planning to pick at it tomorrow so I’ll definitely post when/if I get it sorted out.

  6. 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!

  7. and how the heck did you get my user pick to show without me uploading it?!!! My god that was awesome!!

  8. @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. :-)

  9. wow .. that was amazing tech tip !
    will keep it in mind ! twitting out this article @v_render @veeroo18

  10. No problem v-render. I’m glad it was useful to you. Thanks for the Tweets. :-)

  11. 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 ?

  12. 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.

  13. […] Link to author’s blog […]

  14. 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!

  15. @ChrisS: How do you mean my friend? Like this one?

  16. 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/

  17. 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.

  18. 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.

  19. 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. :D

  20. @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.

  21. No problem, Jonathan. I’m easily misunderstood ;-) . I look forward to hearing from you. Thanks!

  22. 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

  23. 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

  24. 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.

  25. Kool!!! Simply neat!

  26. Hey,
    I tried this and it works great! Any idea on how I might go about giving the user a method of changing the Bg image yet still keeping aspect ratio using your technique?
    example for changing bg:
    http://osc.template-help.com/wordpress_27034/

    I will be playing with this idea - I’ll keep you posted when I get. Thought you might know of solution.

    Cheers!

  27. Thank you so much for this. Tried so many different ways of doing this from many different sites and finally came across this sexy, elegant solution!

    Thanks again! :)

  28. @Acecazle, Stylie & Russell: I’m glad this post was useful to you. Thank you for commenting here.

  29. This looks really great. I’m having trouble wrapping my head around my issue though. It’s probably something simple and I’m thinking to complex.

    Can you tell me what is wrong on this page?

    I’m not getting it…

    http://www.acowancreative.com/pork/index.html

    Help! :)

  30. Chris, you are closing your “body” too soon. The background image should be contained within a “div” pair, not a “body” pair.

    Hope that helps.

  31. Question for this thread. Is there a way control the size of the image using the background tag in CSS? So I have header section on site which will contain a logo. This header section is 250×250, but the image I am using is 1000×1000. I could always scale the raw image, but was wondering if there is a way to do it via CSS. I could change the HTML to use the IMG tag, but then I need to maintain that tag across all of the pages. Thanks.

    Here is the CSS

    #header #header-image {
    position: absolute;
    top: 12px; right: 30px;
    width: 294px;
    height: 234px;
    background: url(../images/APlayfulPlanet.png) no-repeat;
    }

    The HTML contains a simple DIV

  32. Hi Chris - it just so happens that I might be able to help here! :-)

    I have written a web-server application that will resize images on-the-fly (amongst other things). With my Image Director application installed on your web-server your CSS would include a line like this:

    background: url(/image_director/image_director.php?src=../images/APlayfulPlanet.png&amp;w=250) no-repeat;

    The background image would then be resized to 250 x 250 pixels (assuming a square source image) upon its first request. The resulting, resized image would be cached on the server and then used from then on so as to minimise the footprint of the Image Director application.

    You can learn more (and download the application - free) here: Image Director.

    Have fun!

  33. Question: I’ve tried your method and other scripts - I can get the background image to scale, works great - but can not get the scroll bars to come back on - I think its because I have DIV tags nested within the “scrollable” DIV - Can someone take a look at this and help me troubleshoot ?http://www.fluxprojects.org/scroll-1.html

  34. Hi again, actually got the scrollbars to work on Mac Safari - but doesnt work on Firefox - any suggestions for what might be this cross-browser code error? http://www.fluxprojects.org/scroll-1.html

  35. @Jenny Smith

    Jenny, try it without using a <table> for your background image (a simple <div> should suffice).

  36. This has been a great help! Works great in Firefox! But sadly IE doesnt seem to like it - surprise surprise! I think I need to tweak my CSS for the content or container divs but I’m running out of ideas??
    http://www.landingnet.co.uk/dev/villa/index.php

  37. Ignore that - I was been a spanner!! Didnt close a tag properly! Doh! Great work, thanks very much!

  38. Thought someone else might find this useful - here is the CSS for the sticky footer implemented with the full background image resizing:

    /* 2 column css layout with sticky footer */
    * {
    margin: 0;
    padding: 0;
    }
    html,body {
    margin: 0; padding: 0; width: 100%; height: 100%;
    }
    #bg_image {
    position: fixed; top: 0; left: 0; z-index: 1; width: 100%;
    }
    /*---------- LAYOUT --------------*/
    html, body, #wrappper {
    height: 100%;
    }
    body > #wrapper {
    height: auto; min-height: 100%;
    }
    #main {
    position: relative; width: 100%; height: 100%; top: 0; left: 0; z-index: 2;
    padding-bottom: 40px; /* must be same height as the footer */
    }
    #footer {
    background: #0C0;
    position: relative;
    margin-top: -40px; /* negative value of footer height */
    height: 40px;
    z-index: 3;
    clear: both;
    }
    /* CLEAR FIX*/
    .clearfix:after {
    content: ".";
    display: block;
    height: 0;
    clear: both;
    visibility: hidden;
    }
    .clearfix { display: inline-block; }
    /* Hides from IE-mac \*/
    * html .clearfix { height: 1%; }
    .clearfix { display: block; }
    /* End hide from IE-mac */
    * {
    margin:0;
    padding:0;
    }
    <!-- SOME CONTENT IN THE MAIN SECTION -->
    <!-- main content -->
    <!-- contentcontainer -->
    <!-- wrapper -->
    SOME CONTENT FOR A STICKY FOOTER
    <!-- footer -->

    You just need to put your background image in the code. See ya!

  39. @Stylie

    Great stuff. Thanks for your valuable contribution Stylie. (Note: Code and comments edited for brevity.)

Contribute to the Discussion:

The comment handler is Gravatar enabled.