Grow your CSS skills. Land your dream job.

Transparent Borders with background-clip

Published by Chris Coyier

Have you ever seen an element on a page with transparent borders? I think Facebook originally popularized it giving birth to lightbox plugins like Facebox. I don't think Facebook sports the look anymore, but it's still rather neat.

You might think it would be as simple as this:

#lightbox {
   background: white;
   border: 20px solid rgba(0, 0, 0, 0.3);
}

However, setting a transparent border on an element will reveal the elements own background underneath the border.

In the screenshot above, the borders use RGBa to be transparent, but they appear solid gray because they are only revealing the solid white background of itself below.

Fortunately there is a CSS3 property to save us! It's called background-clip and it's used specifically to specify which portion of the box model should be utilized to display the background. It does what it sounds like it does, it cuts off the background at the specified portion of the box. There are three values it can have, and vendor prefixes do get involved. Here are the three settings it could have. You wouldn't use them all at once, this is for convenience of displaying only:

#lightbox {

  -moz-background-clip: border;     /* Firefox 3.6 */
  -webkit-background-clip: border;  /* Safari 4? Chrome 6? */
  background-clip: border-box;      /* Firefox 4, Safari 5, Opera 10, IE 9 */
				
  -moz-background-clip: padding;     /* Firefox 3.6 */
  -webkit-background-clip: padding;  /* Safari 4? Chrome 6? */
  background-clip: padding-box;      /* Firefox 4, Safari 5, Opera 10, IE 9 */
				
  -moz-background-clip: content;     /* Firefox 3.6 */
  -webkit-background-clip: content;  /* Safari 4? Chrome 6? */
  background-clip: content-box;      /* Firefox 4, Safari 5, Opera 10, IE 9 */
				
}

Here are the schematics:

So I'm sure you see where I'm going here... if we set the background-clip to the padding-box, the white background will end before the border and the transparency will lay over other content acheiving the look we are going for!


View Demo

Related: background-origin

In our lightbox example, it's most likely that the background is a solid color. In that case, background-origin is rather irrelevant, as nobody will ever be able to tell where the color "started" from. However, if the background of the element is an image, it can be quite important where the origin point of the background starts.

This is related to background-clip, because if the background-clip is the padding-box but the background-origin is left at the default border-box, some of the background-image will be cut off, which may or not be desireable.

Here is the schematic:

And a visual example:

Browser Compatibility

Works in: Safari 5, Chrome 7, Firefox 3.6+, Opera 10, IE 9

I only tested these modern browsers and support is good. It may (and likely does) go back a bit further in the non-IE browsers.

If you'd more complete browser compatibility, you can always go with the double-div method.

<div id="lightbox">
   /* Set transparent background with PNG
       add padding to push inside box inward */

   <div id="lightbox-inside">
      /* Set white background in here */
   </div>

</div>

Another advantage to the double-div method is that you could achieve truly rounded borders. Unfortunately with the background-clip method, the outer border is round but the edge of the background stays straight-cornered.

Too bad we don't have something like background-radius to fix it:

#lightbox
   border-radius: 16px;
   padding: 8px;

   /* NOT REAL */
   background-radius: 8px;
}

Weirdnesses

20px of border was fine, but when I tried 30px, these mini boxes of death showed up in Safari 5.

In Chrome, little diagonal lines were present at any border width up to 20px.

Above 20px border, the corners completely darken.

Without border-radius, darkened corner boxes are always visible.

Thanks

Thanks to Alex Hall for the original idea and help.

Here's a simple demo showing the different values of background-clip as well:

Check out this Pen!

and background-origin:

Check out this Pen!

Comments

  1. David
    Permalink to comment#

    Chris,

    Great article, and the tip will certainly come in handy!

    Thanks,
    David

  2. Permalink to comment#

    Chris –

    The last two screenshots, I assume are related to the one above them. Meaning that the last two are in Chrome. Just wanted a little clarity.

    Thanks

  3. Sid
    Permalink to comment#

    Beautiful. Crazy that I was just trying out rgba yesterday and wondering why the hell transparency didn’t work.

  4. Permalink to comment#

    Do you have a screenshot of what this looked like in IE 7/8?

  5. Permalink to comment#

    That’s neat. But the cons really weird. Those black line and box are an odd problem. I guess its maybe on the browser side problem to render the CSS

  6. Andre
    Permalink to comment#

    This is a really cool idea. I could think of display data linked via text i.e. a dictionary definition, photo details etc. Unfortunately IE is left in the dust with these cool visual styles. However I’ve stumbled across PIE CSS3 for IE! This allows support for RGBA value and other CSS3 properties. I haven’t had a chance to test it out myself, but I’m working on it and looking forward to it!

  7. Mini boxes of death!

  8. Noah
    Permalink to comment#

    I’m just so happy that IE9 is supporting all this. It’ll make our job easier.

  9. Je Kyran
    Permalink to comment#

    “…transparent border on an element will reveal the elements own background…”

    Would the use of outline rather than border not overcome this problem?

    However, I realise that outline would not permit the coolification by addition of radius.

  10. Permalink to comment#

    supercool, I did those with underlaying transparent div, for compatibility’s sake, but this will be neat once we get rid of that IE<9 basterds (wishes, nobody can take them from me! :D )

  11. KaZ
    Permalink to comment#

    FYI Facebook didn’t develop Facebox.

    • Permalink to comment#

      he said he thought FB originally started the “transparent border” thing (I’m not sure either), which led to things like Facebox.

  12. Permalink to comment#

    Very nice Chris.

    As a side note. From working with Chris I can tell he takes great lengths to study every aspect of something before he writes a tutorial on it so almost everything he teaches is the best way to do something too.

  13. Pankaj
    Permalink to comment#

    This site is a great resource for web designers and developers..I just Loved it! thank you Chris.

  14. Permalink to comment#

    Nice tips; though I think that using a double div with a transparent png border might be more graceful on IE; the RGBa value being the problematic property. With a PNG double div you’ll at least retain the transparent effect, but keeping graceful degradation in mind you could do some very slick looking modals in this method, or :focus and :hover effects.

    • Permalink to comment#

      I am with this idea. Chris’ idea about the transparent border is freaking awesome, but to bleeding edge for sites that have heavy legacy users.

  15. Permalink to comment#

    Sorry,
    but I just don’t understand what the big deal is, and what transparent borders would be needed it anyways?.

    • Permalink to comment#

      Transparencies are the new drop shadows. That’s all.

    • Permalink to comment#

      It’s more for the fact that rgba can’t simply be added to borders and they just work because the background colour sits underneath the border (effectively making it not transparent but changing the shade). Using the methods above you can get around this little issue.

  16. awesome, great, superb article………………………..help more intrested crew wit articles like dis……hats off really great

  17. Permalink to comment#

    Hi Chris,

    Did you report the bugs to the Chrome and Safari teams respectively (if they’re not already reported)? :)

    Nicely illustrated article btw, I could never explain things so good myself. :)

  18. Permalink to comment#

    Excellent effect the transparent borders, especially with the inner rounded too! Thank you for the CSS3. LT

  19. Really neat trick, I had been trying to get transparent borders on a lightbox I am developing… Another possible route I was trying is a transparent div as the parent… it also had the bonus of having rounded corners inside of rounded corners.

  20. Permalink to comment#

    After going over this a few times, I’ve got to say, there is just way too much cross-browser weirdness going on there..

    Here’s my version. Works in IE6+, FF, Safari, Chrome.

    http://blog.pressedweb.com/demos/facebook_border/

    • Permalink to comment#

      Impressed. Very impressed.

    • Permalink to comment#

      But you’re using three elements to create that one box, the method Chris uses has just one element.

      However, I realise that this method won’t work on anything but the latest browsers and your version is the cleanest method I could think of that would work across all platforms, so very nice job!

  21. devlim
    Permalink to comment#

    Nice explain the background-clip and background-origin by using image.

  22. Very Nice and more help full

  23. amidude
    Permalink to comment#

    I apologize if my question is irrelevant to the original intent of your article, but if I may ask, what was the original solution Facebook used and did it degrade gracefully?

  24. Ree Tung
    Permalink to comment#

    OK this makes a lOT of sense dude. Wow.

    Lou
    http://www.online-privacy.eu.tc

  25. Permalink to comment#

    Thanks for sharing your expertise. I wish there were was a better implementation of this great CSS feature without the developer jumping though hoops. I can already see most designers using the double div method.

  26. Permalink to comment#

    thanks for the compatibility screenshots

    is it more compatible or as compatible as using background:url(whitealpha.png);

    thanks…

  27. Permalink to comment#

    All I need new is a client who wants transparent borders enough to pay me to do all this? One day!

  28. Kyle
    Permalink to comment#

    For the life of me I can’t get this too work. I even copied your css from the demo, I always get this result – http://drp.ly/1TXs

    • Permalink to comment#

      Set that inner white block (blockquote p I believe) to have that stroke’s bg color.

      Right now it’s picking up it’s default bg or something.

  29. Permalink to comment#

    CSS getting awesome day by day. What if there is no browser war? Still we need to consider old styles to make sure our web apps has a consistent look among browsers. Some client that much crazy (or we?) like using still ie6. Thanks for the post.

  30. Permalink to comment#

    Love your article.

    Thanks a lot!

  31. Permalink to comment#

    Its amaizing!

    Thanks for sharing.

  32. As sloppy as it is, for compatibility reasons, could you make two divisions?

    #border (set background image to a transparent black png, and give it the same padding as the border width.)
    #popup (white background, inside border division.)

    Not all IE versions will support this, but I guess it could be a simple solution in some cases.

  33. Permalink to comment#

    Nice thing to implement :) but i couldnot reproduce this on IE7

  34. Permalink to comment#

    Very nice, thanks for sharing.

  35. Permalink to comment#

    very nice indeed! something new to play with.

  36. someone
    Permalink to comment#

    using rgba definitions is better. at last, this is supported by only modern browsers too.

  37. Permalink to comment#

    I couldn’t find this anywhere so I thought I’d share… This gives a semi transparent border outline around a box while retaining the 100% transparency of the inside box…essentially giving a ‘window’ to peer through the 50% transparency box.

    Using SASS allows you to change the width of the ‘border’ by changing only 1 line of code. Gotta love SASS

    Setup the ‘Window':

    <div class=" relative trans_border_box">
        <div class="top-line trans50"></div>
        <div class="right-line trans50"></div>
        <div class="bottom-line trans50"></div>
        <div class="left-line trans50"></div>
        <div class="inside-content">
            <p>
                <a href="">Content Link</a>
            </p>
        </div>
    </div>
    

    The SASS / CSS (I’ve included the long version of the border for clarity). This uses a white png image with 50% transparency.

    /*Peer Through The Window*/
    
    $transborder: 8px;
    
    .trans_border_box{
        position: relative;
        min-height: 20px;
    
        .top-line,
        .bottom-line,
        .right-line,
        .left-line
        {
            position: absolute;
            min-height: $transborder;
            min-width: $transborder;
            background: url('../../../assets/img/trans/trans50.png') repeat transparent;
            background-clip: border-box; 
            -moz-background-clip: border;     /* Firefox 3.6 */
            -webkit-background-clip: border;  /* Safari 4? Chrome 6? */ 
        }
        .top-line{
            top: 0;
        }
        .bottom-line{
            bottom: -$transborder*2;
        }
        .left-line{
            left: 0;
            top: 0;
            margin: $transborder 0;
        }
        .right-line{
            right: 0;
            top: 0;
            margin: $transborder 0;
        }
        .top-line,
        .bottom-line{
            width: 100%;
        }
        .right-line,
        .left-line{
            height: 100%;
            border-radius: 0;
            -webkit-border-radius: 0;
            -moz-border-radius: 0;
        }
        .top-line{
            border-radius: $transborder $transborder 0 0;  
            -webkit-border-radius: $transborder $transborder 0 0;
            -moz-border-radius: $transborder $transborder 0 0;
        }
        .bottom-line{
            border-radius: 0 0 $transborder $transborder;  
            -webkit-border-radius: 0 0 $transborder $transborder;
            -moz-border-radius: 0 0 $transborder $transborder;
        }
        .inside-content{
            text-align: center;
            p{
                padding-top: $transborder*2;
            }
        }
    }
    .relative{
        position: relative;
    }
    

    Quite a few lines of code, but the result is pretty.

    Enjoy :)

  38. gracezlj
    Permalink to comment#

    Hi, chris, thanks for sharing :)

    I found that there is a little mistake in the background-origin pic, the default value of background-origin should be “padding-box” instead of “border-box”.

  39. gigs

    Another approach would to use a box shadow without blur:

    border-radius: 10px;
    background: #FFFFFF;
    box-shadow: 0px 0px 0px 10px rgba(0,0,0,0.30);

    Any downsides I’m overlooking?

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