Grow your CSS skills. Land your dream job.

Creating a Body Border

Published by Chris Coyier

This article as originally published on February 25, 2008, but is now being completely re-written to be more comprehensive and show modern techniques.

Jon Hick's site Hicksdesign is where I first saw the concept of a "body border." In this case, it's a very subtle and lovely effect.

Characteristics of a body border:

  • Go around entire browser window, stuck to the edge regardless of screen size
  • All edges stay in place as page scrolls
  • Content goes beneath borders as page scrolls

View Demo

Technique #1: Four Divs

The way to do this with the deepest cross browser compatibility is to use four elements to do it. Hicksdesign does it this way, using four <b> elements and has this to say in an HTML comment:

I use the b tag borders because it's just visual stuff with no meaning so I may as well use the smallest tag I can find.

No matter what, this is presentational markup which is not ideal. We'll use a div here:

<div id="left"></div>
<div id="right"></div>
<div id="top"></div>
<div id="bottom"></div>

Then we style with CSS. Some properties are shared by all of the elements, some by only the top/bottom and left/right, and some unique to themselves. Here is a clean way to code that, without unnecessary repeated properties.

#top, #bottom, #left, #right {
	background: #a5ebff;
	position: fixed;
	}
	#left, #right {
		top: 0; bottom: 0;
		width: 15px;
		}
		#left { left: 0; }
		#right { right: 0; }
		
	#top, #bottom {
		left: 0; right: 0;
		height: 15px;
		}
		#top { top: 0; }
		#bottom { bottom: 0; }

This should work fine in IE 7 and up and just about any other good desktop browser. For IE 6, which doesn't support fixed positioning, we'll just get rid of it (no harm no foul) by using a conditional comment in the head:

<!--[if lte IE 6]>
	<style>#top, #bottom, #left, #right { display: none; }</style>
<![endif]-->

We also should ditch it on small screens (likely to be mobile) which also don't handle fixed positioning:

@media 

/* Fairly small screens including iphones */
only screen and (max-width: 500px),

/* iPads */
only screen and (min-device-width: 768px) and (max-device-width: 1024px) 

{
	#top, #bottom, #left, #right { display: none; }
}

So now we get the effect where we want it and not where we don't:

Technique #2: Pseudo Elements

In the above example, we needed four unique elements to get the job done. But that's four more elements than are appropriate semantically in our document. Ideally we would use zero. Well wouldn't ya know it, there are two elements that are the size of the browser window already, the <html> and <body> elements. Using the :before and :after pseudo elements on those, we get four!

We would use the same properties and values as above, only we would use:

html:before, html:after, body:before, body:after {
    content: "";
    position: fixed;
    background: #a5ebff;

    /* etc. */
}

Harry Roberts had this idea as well and published it on CSS Wizardy.

While the browser support for pseudo elements is pretty good, it's not as good as Technique #1. A bigger problem is that there is an WebKit bug which the background on an html-element pseudo element bleed over the entire viewport. This makes using pseudo elements on the html-element a no-go for the time being.

But there is a solution! While saying semantic!

We don't really need four unique elements, we really only need two. The top and the bottom need to be unique, so they can be of fixed position and not scroll. For the left and the right, we can literally just use a border on the <body>.

body:before, body:after {
    content: "";
    position: fixed;
    background: #900;
    left: 0;
    right: 0;
    height: 10px;
}
body:before {
    top: 0;
}
body:after {
    bottom: 0;
}
body {
    border-left: 10px solid #900;
    border-right: 10px solid #900;  
}

Same exact effect, slightly less browser support, way more semantic.

View Demo

For Funzies: Kottke.org body border

Jason Kottke's Kottke.org has a pretty cool body-border effect.

It takes Jason eight different elements and eight different images (!) to pull this off. Because this border style doesn't stay fixed to the top and bottom of the viewport (just the top and bottom of content) this is actually really easy to pull off with CSS3.

We'll use box-shadow on the <body> element, and it's neat ability to comma-separate multiple shadows. Here it is in it's entirety with

body {
	padding: 40px;
	overflow-x: hidden; /* For Opera */
	-webkit-box-shadow:
		inset #19d4ff 0 0 0 5px,
		inset #18cdf7 0 0 0 1px,
		inset #53dfff 0 0 0 10px,
		inset #50d8f7 0 0 0 11px,
		inset #8ce9ff 0 0 0 16px,
		inset #88e2f7 0 0 0 17px,
		inset #c5f4ff 0 0 0 22px,
		inset #bfecf7 0 0 0 23px;
	-moz-box-shadow:
		inset #19d4ff 0 0 0 5px,
		inset #18cdf7 0 0 0 1px,
		inset #53dfff 0 0 0 10px,
		inset #50d8f7 0 0 0 11px,
		inset #8ce9ff 0 0 0 16px,
		inset #88e2f7 0 0 0 17px,
		inset #c5f4ff 0 0 0 22px,
		inset #bfecf7 0 0 0 23px;
	box-shadow:
		inset #19d4ff 0 0 0 5px,
		inset #18cdf7 0 0 0 1px,
		inset #53dfff 0 0 0 10px,
		inset #50d8f7 0 0 0 11px,
		inset #8ce9ff 0 0 0 16px,
		inset #88e2f7 0 0 0 17px,
		inset #c5f4ff 0 0 0 22px,
		inset #bfecf7 0 0 0 23px;
}

Bug Note: Opera (Mac, 11.10) has a weird bug where it expands the size of the element to accommodate for the shadows on the outside (even thought the shadows are inset). This triggers unwanted scrollbars, since we're using it on a full-width body element. Horizontal scrollbars can be hidden by hiding overflow-x. But unfortunately there will still be a bit of space at bottom of screen.

While this has the least browser support of all the stuff covered, it's not bad: IE 9+, Fx 3.5+, Opera 10.5+, Chrome any, Safari 3+

View Demo

Comments

  1. It’s probably worth noting that this process is really only useful if you want a fixed-width/height border on a page where content won’t necessarily fill the page. Otherwise, wouldn’t it make waaay more sense to just wrap all content in a div, give it “margin: 10px” and change the page background to your border color / style?

  2. Oh, I see. I misread that they wanted the border through all viewable area. In this case, I still say it’d be better to use a #page-container div rather than assembling the border with divs. Again, if you can ensure enough content on every page to fill out a browser window, the page-container can use “overflow: auto”.

  3. @Brent: That’s pretty smart thinking, but the problem with doing it that way is that you won’t get the bottom border if the page has enough content that it scrolls. This way you get all four borders no matter what.

    It is also worth noting that because these div’s are absolutely positioned they automatically get stacked higher vertically (z-index) than anything else on the page that isn’t absolutely positioned. So, they will “cover up” anything below them.

    • What about using a div with a margin all around to get the top, left and right borders and then using another div to construct the bottom border. Then you only need to divs (or a div and a b tag). Is that not more semantic?

    • Remy Bach

      I half agree with Brent on that one, with the exception being that I’d give the body a padding of ‘0 10px’ and having two b tags for the left and right.
      The only problem I guess would be if the site needs to scroll horizontally, but that’s something that should be avoided anyway.

  4. Permalink to comment#

    Brent asked what I was going to. :) It’s great to see the “why”s behind particualr techniques, so thanks.

  5. Permalink to comment#

    The Hicksdesign link has an extra alias in it :D

  6. Thanks Tim, fixed that.

  7. Permalink to comment#

    Here’s some additional information: The frame, or box-border, was used in a design and published in the CSS Zengarden-book called “The Zen of CSS Design: Visual Enlightenment for the Web”, and you can view the awesome design at this url:
    http://www.csszengarden.com/?cssfile=069/069.css (by: Mike Davidson)
    Try to scroll and notice the frame follows.

  8. Maybe you can make it slightly transparent for extra-spiffyness! Divs couldn’t overlap, though.

  9. hm, why don’t you just use one div with border instead of 4?

  10. Have not test this yet, but should do okay:

    html {background-color:#5a5a5a;height:100%}
    body {margin:10px;background-color:#fff57a;height:100%;border:8px inset #ff6e73;}
  11. @Dejan: You can get it to LOOK right with one div with a border, just set each of top/bottom/left/right to 0px and apply a fixed position and border. But that will break the entire layout!

    See, since absolutely positioned items are, by default, placed above in the vertical stacking order (z-index), that div will be above everything else on the page. Even with a transparent background color, it will still be “on top” which will deaden any links and make text un-selectable. Not good!

  12. @Arjan: More smart thinking there, but that way will also not get you the bottom border if your page content exceeds the browser window vertically and needs to scroll.

  13. Beau
    Permalink to comment#

    I was thinking “couldn’t you just use a wrapper div for this” but I see that you want that bottom border always to show. Instead of using 4 divs for the border though, couldn’t you use a wrapper div and set the borders for top, left, and right, then just use an absolutely positioned div for your bottom border? That might make the CSS even simpler, and cut down on some markup!

  14. Permalink to comment#

    I just tried this:

    html	{
    	height: 100%;
    	}
    
    	
    body	{
    	border: 10px solid pink;
    	min-height: 100%;
    	padding: 10px;
    	}
    * html body	{
    	height: 100%;
    	}
    

    and it gives me a bottom border whether my content scrolls or not in both IE and FF. No extra markup at all.

    The only small problem is that if there is not enough content to make the page scroll, the page’s actual height is 100% + 20px since the border gets added to the height.

    • Permalink to comment#

      modified your code a little bit

      html{
          height:100%;
          height: -webkit-calc(100% - 20px);
          height: -moz-calc(100% - 20px);
          height: calc(100% - 20px);
      }
      
      
      body    {
              border:10px solid #fff;
          min-height: 100%;
          min-height: -webkit-calc(100% - 20px);
          min-height: -moz-calc(100% - 20px);
          min-height: calc(100% - 20px);
          padding: 10px;
          }
      

      tested with ie10+chrome, works perfect, thanks

  15. @NatalieMac: This looks to me like it pushes the bottom border off the viewable area no matter what. Still an interesting idea… I think we are onto a way to do it with less markup here though. If we can do the top, right, and left borders this way and then just do a fixed bottom border, that would be only one empty div needed, much better.

  16. Permalink to comment#

    Interesting technique, I’d usually use padding in the same way so it certainly adds to the arsenal of tools available.

  17. Interesting..

    Good ..

    thanks.

  18. Claudia
    Permalink to comment#

    koew,

    I couldn’t see a reason for wanting this until I looked at the example you gave at http://www.csszengarden.com/?cssfile=069/069.css

    That is seriously beautiful.

    • Yeah well, when your design looks like that!! But I totally agree that this may be just a tad bit useless =). Unless someone really really wants those borders!

  19. Thank you for this Css-Trick and i bookmark your Rss-Feed ;)

    Ralph

  20. thinsoldier
    Permalink to comment#

    I have a dream.

    div#viewportBorder {
    position:absolute;
    top:0; left:0;
    width: 100%; height: 100%;
    border: 5px solid red;
    clickthrough: true;
    }

    just 1 div

    • Couple years later… now we have pointer-events. Worth looking at!

    • Ehrm, Chris.. pointer-events? Seriously? I thought of all people, you would understand that preaching about interface functionality within CSS is going overboard and should be left at JavaScript.
      Still, if you meant what I think you meant: #something:active is not going to work in this case, because the click then occured on the element on top and not the link in question. Also, if it were to work, you’d get weird effects like part of the layout “flickering” on the screen.

    • I like pointer-events. Shrug.

      It’s perfect for the code in this thread. Put transparent div over entire page which accomplishes border, but will cover content and make things unclickable. Pointer events means you can click through it. That belongs in CSS if you ask me. I’m down to hear a rebuttal though. Blog it!

  21. html { 
      background: black; 
    }
    body {
      margin: 10px;
      background: white;
      height:100%;
      position:relative;
    }
    #bar {
      width:100%;
      background: black;
      position:fixed;
      bottom:0;
      height:10px;
    }
    

    Seems to work in ff/mac, not tested in other browsers/os.

    Oh, looks like you actually don’t need ‘position: relative’ on the body element with the css i posted… anyway, my solution may not be the magic bullet, but i think is worth throwing into the mix

  22. Adrian Salceanu
    Permalink to comment#

    Hi
    As interesting as the effect may be if used properly, it should be pointed out that the four divs have absolutely no semantical or structural meaning whatsoever – so, that’s a big “no no!”. But if used to progressively enhance the markup, it could come up really sweet. Thanks for sharing it with us.

  23. Agree entirely with Adrian, semantics should play presidence not the styling as CSS should merely compliment your markup. Firstly try to use the markup already used, and if that’s not suitable then do it this way.

    There are several techniques to attain this effect with less markup but my instincts say that this one would encounter less issues.

    Thanks for sharing mate

  24. Permalink to comment#

    Ahhhh, the “semantics” folks. They always come along and punch holes in otherwise great design ideas. I’m no usability or semantics expert, but is it always necessary to consider semantically coding your layouts all the time? I just don’t understand why it’s such a big “no-no” to not have them on your mind every time you write CSS. Is it really going to have such a negative impact that it will ruin the experience for the visitor? I’d probably catch hell from these folks for saying all this, but c’mon, easy with the perfectionism all the time.

    Anyhow, on a totally different note, I wanted to say that your website is easily among my top-10 favorites to peruse, and the design is simply genius! I’ve always loved this site – keep up the good work!

  25. Permalink to comment#

    Coby, if there’s not reason to use semantic/meaningful code you could just use a table for things like this. However, a table wouldn’t be logical since you (probably) won’t be displaying tabular data inside the border.

  26. DJ

    I’m using FF 4.0.1 and it does NOT seem to honor fixed positioning on your last example with multi-colored borders top and bottom.

  27. LastLifeLost

    I feel like I’m missing something. Why can’t it be done like this?

    body:before {
    			content: "";
    			position: fixed; top: 0; bottom: 0; left:0; right:0;
    			border:20px solid red;
    			padding: 20px;
    }

    One pseudo element rather than two, leaving the second one for other effects.

    • Not sure what the padding is for there. The problem with that is it’s a big layer that sits on top of everything that you won’t be able to click through and interact with the page. You can try pointer-events: none; on it which should help with that, but that’s dangerous territory as if a browser doesn’t support that the whole page is shanked.

      When you have an idea like this, make a test page for it! Only takes a second, you learn, we learn, everybody gets better faster.

    • LastLifeLost

      I did make a test of this, but didn’t even think to test the usability stuff like clicking links. The padding is there from an earlier version of the testing. I knew there must have been a reason that the simple solution wouldn’t work!

  28. I like this tip. Thanks.

  29. Same as regular, something new.
    Now I learned the “only screen and” options of CSS

  30. This is awesome :)
    CSS is so fun, especially while learning fun new tricks like this.

  31. Max

    Just to toss in another example of this type of thing: 24ways.org

  32. Some guy

    I’m not a fan of body borders, they draw too much attention.

  33. is it necessary to put “inset” inside of “-webkit-box-shadow” ?

  34. Another useful stuff, hope to get it working..

  35. Given a top Body border with a previous article on Glow Form <http://css-tricks.com/glowform/&gt; the page can have this <http://www.pushinpixels.co.uk/index.html&gt; only in webkit do you have animation but we have a fallback for others.

  36. Does adding a border to the html element not work?

  37. GNO

    @Nils, no it wont work the same way, as the top and bottom border will scroll away with content. However…

    @Chris Coyier, I know that this maybe is going beyond the scope of this article, but adding the border’s color as the background of the html element and putting a margin and a background color on the body element will provide a decent fallback for smaller screens and mobile-devices. It gives more vertical space on lower screens and it does not bug out mobile safari as the fixed positioned stuff does. It could even be used as fallback for browsers where fixed positioning and pseudo elements is not supported.

    One could argue that it is a minor detail, but I think that having that kind of fallback yields a more consistent feel.

  38. Richard

    This site also has a body border:
    ibuypink.com

    He put the borders into an unordered list and assigned the list items classes for each side.

    • its not that big of a difference, but i like the idea of using an unordered list as opposed to divs.

  39. Maybe this idea would work better, and you would just need one extra element.

    You set the element to be fixed, automatic width, and then left:10, right:10, top:10, bottom:10 and give it a 10px border. Wouldn’t that work?

    • It works, certainly it works, but you can’t click on anything, as the new element avoids it. Extra note: you have to give a value of 0px to left, right, top and bottom.

  40. Switching between the kottke.org demo and the actual kottke.org, I noticed some differences in the metrics. The following modifications will replicate the original site pixel for pixel:

    inset #19d4ff 0 0 0 4px,
    inset #18cdf7 0 0 0 5px,
    inset #53dfff 0 0 0 9px,
    inset #50d8f7 0 0 0 10px,
    inset #8ce9ff 0 0 0 14px,
    inset #88e2f7 0 0 0 15px,
    inset #c5f4ff 0 0 0 19px,
    inset #bfecf7 0 0 0 20px;
  41. Nice article! And what about something like that?
    I didn’t test it on Opera, but I think I only need to add the line below if it results broken:
    overflow-x: hidden; /* For Opera */

    Here the code:


    body:after {
    content:" ";
    display: block;
    position: absolute;
    width: 100%;height: 100%;top:0;
    box-shadow: inset -20px -20px 0 pink,
    inset 20px 20px 0 pink;
    /* z-index: -1; just uncomment this to set this as a part of the background */
    padding: 60px; /* eventual padding, 40px + 20px of the inset box-shadow */
    position: fixed;
    }

    I usually put this when I want a subtle inset shadox on a repeated texture, but I think it’s also suitable in order to get a body border.

    Let me know what do you think about this!
    Best regards,
    raozuzu :)

  42. felicja

    This article shows how to complicate simple things… To solve this problem I wrote in firebug: body {border:10px solid #000} and <div style="position: fixed; width: 100%; height: 10px; background: #000; left: 0; bottom: 0"></div>. And it works. I think that the simplest solutions are the best.

  43. Permalink to comment#

    Really nice tutorial! that really means a lot to me. Such a nice start for beginners. Thank you for taking the time to do all of that!

  44. Prince
    Permalink to comment#

    Hi, How can I have a Border (with an image or rather a series of similar images) around my webpage . Someone suggested the code shown below but its not working properly.

    div
    {
    -webkit-border-image:url(http...border.png) 30 30 round; /* Safari 5 */
    -o-border-image:url(http...border.png) 30 30 round; /* Opera */
    border-image:url(http...border.png) 30 30 round;
    }
    
  45. Dingle
    Permalink to comment#

    This is all you need:

    html {
        min-height: 100%;
        border: 10px solid red;
        box-sizing: border-box;
        -moz-box-sizing: border-box;
        -webkit-box-sizing: border-box;
    }
    
    • Yasmin
      Permalink to comment#

      Thanks for this, helped a lot! The only thing i couldn’t do was have a fixed bottom of the border where I could still scroll the content within without it disappearing so I modified it a bit adding a div as a fixed bottom border.

          html{
              min-height: 100%;
              border: solid 1em #E8EBED;
              box-sizing: border-box;
              -moz-box-sizing: border-box;
              -webkit-box-sizing: border-box;
              border-bottom:none
          }
          .border{
              position:fixed;
              width:100%;
              height:3.5em;
              background:#E8EBED;
              left:0;
              bottom:0;
              z-index:1;
          }
      
  46. Guilherme Ventura
    Permalink to comment#

    Chris, it’s a great technique, but, when the page doesn’t have much content, the border on the body doesn’t fit vertically. To solve this, i’ve just added this rule on CSS:

    html, body { height: 100%;  }
    

    This make the trick works even when we don’t have much content on the page.

    All the Best

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".