Image Rollover Borders That Do Not Change Layout

Avatar of Chris Coyier
Chris Coyier on (Updated on )

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