Grow your CSS skills. Land your dream job.

Image Rollover Borders That Do Not Change Layout

Published by Chris Coyier

It's a fact of CSS life that the 'border' of any block level element gets factored into its final box size for layout. That means that if you add a border on a hover to an element that didn't already have a border of that exact size, you will cause a layout shift. It's one of my pet peeves, for sure, when I see it in final designs. I find those little shifts, even 1 pixel, jarring and awkward. (quick little video example)

CSS does provide us with one very useful property that allows for borders that do not affect layout, and that is the outline property. Outline is nice, but it is limited in that you cannot apply one side or another. It's all or nothing. Also, outlines can only be applied outside an element. We'll be using the regular border property to get around that to create some inner borders.

 

View Demo

 

Problem CSS

#example-problem a img, #example-problem a   { border: none; float: left; }
#example-problem a:hover                     { border: 3px solid black; }

This CSS applies a border on a hover where there was none before. Layout problems ensue.

Fix #1: Inner Borders

#example-one a img, #example-one a           { border: none; overflow: hidden; float: left; }
#example-one a:hover                         { border: 3px solid black; }
#example-one a:hover img                     { margin: -3px; }

This CSS applies a negative margin on all sides of the image of the exact size of the border. This pulls the border inside and causes no layout changes.

Fix #2: Outer Borders

#example-two a img, #example-two a           { border: none; float: left; }
#example-two a                               { margin: 3px; }
#example-two a:hover                         { outline: 3px solid black; }

This CSS uses the outline property to ensure no layout changes take place. Alternatively, you could apply a border color that matches the background color and simply change it's color on rollover, but this is more elegant.

Thanks to Ney Ricardo Barão who got the idea from this site.

Fix #3: Change Box Model

If the width of the element included the border width, this wouldn't be a problem. So you can change it.

Fix #4: Clip

Reader Mattijs Bliek writes in with another idea:

When the image is inside a containing element however, there's an easier solution which works cross browser. You can use the css clip property to crop the image, and then apply a regular border. You can just move the clip of the image by the same amount of px as your border width. For instance if you have a 60x60 image, and you want a 1px border, you clip it at 1px left, 1px top and give it a width and height of 58px (all done via the css clip property).

Comments

  1. Permalink to comment#

    Then again, outline isn’t supported by all browsers, is it? If you have a set width/height on the pictures, why not just use a 3px white border – same as the background color?

  2. Josh
    Permalink to comment#

    Outline doesn’t work in IE 8.

  3. Outline is still the correct way to do it. Definitely account for IE with a conditional stylesheet if necessary.

    • I tend to think that the “correct” way would be the way that is supported in the browser that your users are using, regardless of what the WC3 says.

      Option #1 is a good idea. Thanks for the tip.

    • Sorry, I meant “W3C.”

    • Personally, I think it’s high time that we just stop making exceptions for IE. Design for the standard, and ignore Internet Explorer.

      The public will become aware of IE’s problems when things start breaking, and Microsoft will be faced with the choice of fixing their crap or losing marketshare to angry users.

      Firefox is up to 20% marketshare (and Safari, Opera, Chrome, etc. collectively have a lot too) and rising, and people are leaving IE every day. It’s time.

    • you can’t ignore IE when you are working on a heavy traffic site. when you leave it like that your company will suffer.

    • redouane
      Permalink to comment#

      If we can do it with javascript why not ? I think it will be the best solution instead of IE Conditional stylesheet.

  4. Permalink to comment#

    I think we shouldn’t test in IE8 yet since it’s a browser which actually not support some MS sites either ;). I always use Fix 1 since I don’t want the outline to cover other content such as other images.

    Cheers’
    Simon

  5. simple yet sweet as hell. Great tip!

  6. Gjergji
    Permalink to comment#

    nice :) cooooooool

  7. David Jones
    Permalink to comment#

    I never even knew about this tag blush. Is it just IE that doesn’t support it out of the major browser players?

  8. Great tip with the inner border solution. Always found it irritating how you have to have a gap between images if you want to add a border on hover, shame it doesn’t work in IE8 though.
    Another downfall before it’s even released.

  9. It’s little stuff like this that makes the difference between “Nice, professional site” and “What, your little cousin make this for you?” on the web. Clean, fast and, above all, easy to impliment!

  10. Permalink to comment#

    thanks for tips

  11. Chris
    Permalink to comment#

    Awesome!

    Alternatively on fix #2, you could use “border” instead of outline and add margin:0px to the hover

  12. Pete K
    Permalink to comment#
  13. Ryan
    Permalink to comment#

    example-problem a img, #example-problem a { border: 3px solid transparent; float: left; }

    example-problem a:hover { border: 3px solid black; }

  14. Angela
    Permalink to comment#

    Nice tip! didn’t know about the inner borders fix

  15. That problem is SO annoying. Too bad we can’t just do border-align: inside; or something. These are nice fixes to keep in the playbook though.

  16. Permalink to comment#

    I was thrown off by the statement that this doesn’t work in IE 8? I am using the latest build of IE Tester with IE8 RC1 and the demo pages works as expected?

    As for other IE support, the inner borders appear to be working as intended as well in IE 6 and 7. But the outer borders do no work at all.

    Looking up Outline support, every resource I come across stated that outline is NOT supported in IE at all. This has been something that I have had in my head for years. I was told it didn’t work, never tested it. Not that I am testing it, it works?

    • Permalink to comment#

      ok, total error there.

      “Looking up Outline support, every resource I come across stated that outline is NOT supported in IE at all. This has been something that I have had in my head for years. I was told it didn’t work, never tested it. Not that I am testing it, it works?”

  17. Simple and nice tips.

  18. Paul
    Permalink to comment#

    Nice! really cool trick

  19. I love the option #1,
    for option #2, how about using css in jQuery.
    $(‘#example-two a’).hover(function() {
        
    $(this).css(‘outline’,’3px solid #000′);
    }, function() {
        
    $(this).css(‘outline’,’0′);

    });
    this is not genuine css way though.. :(

  20. shifting layout has always been a problem with images in a grid…
    thanks for sharing the solution… :D

  21. Thanks Chris! When you mailed me back I didn’t know about the outline property, it was a great learning.
    Thanks for sharing!

  22. Josh
    Permalink to comment#

    Fix #3: Background-color and padding. (the image shrinks)

  23. Wow, this a nicer implementation. I used to encapsulate the image into a div, and make it’s background change. (BTW, i know better now!)

  24. How about a transparent border on non-hover?

    • Permalink to comment#

      It’s not about showing or not-showing the border, it’s about placing the border. ;) You need the space whether you make it visible or not.

      Simon.

      twitter.com/simoncolijn

  25. Permalink to comment#

    I always did it like Ryan but with a color instead of transparent:

    example-problem a img, #example-problem a { border: 3px solid *white*; float: left; }
    example-problem a:hover { border: 3px solid black; }

  26. Permalink to comment#

    Just set a 3px white border to begin with, I just think you are over complicating the issue.

  27. Permalink to comment#

    Never knew about the inner border; well, I probably have done it, just never realized it, or memorized the coding. :P

  28. cute! Very useful trick.

  29. Permalink to comment#

    Never used a negative margin before. Neat trick.

  30. Permalink to comment#

    Well, I think background-color can solve many problems,
    #example-one a {background-color:none;}
    #example-one a:hover {background-color:black}
    #example-one a img {margin: 3px}

  31. Permalink to comment#

    Never used a negative margin before, Good Tut

  32. kaba
    Permalink to comment#

    Thanks for the tip!

    Like Chris (the other one) said, I would use margin: 0 and border instead of outline for fix #2.

  33. Very cool

  34. Permalink to comment#

    How hard is it to set a default border first, and only change the color on hover, instead of changing the width? ??

    Outline is used by the browser to indicate when an element is SELECTED, so not really appropriate for a HOVER effect.

  35. simple and smart, i like fix #1

  36. Thanks for the simple to learn CSS rollover tutorial! Is this CSS W3C compliance?

  37. Permalink to comment#

    Thanks very much, I didn’t even know about the outline property!

Leave a Comment

Current day month ye@r *

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