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.
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).
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?
Outline doesn’t work in IE 8.
See w3schools reference page on the css property:
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.
If we can do it with javascript why not ? I think it will be the best solution instead of IE Conditional stylesheet.
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
simple yet sweet as hell. Great tip!
nice :) cooooooool
I never even knew about this tag blush. Is it just IE that doesn’t support it out of the major browser players?
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.
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!
thanks for tips
Awesome!
Alternatively on fix #2, you could use “border” instead of outline and add margin:0px to the hover
https://css-tricks.com/image-rollover-borders-that-do-not-change-layout/ – outer borders doesnt appear to work with IE7
example-problem a img, #example-problem a { border: 3px solid transparent; float: left; }
example-problem a:hover { border: 3px solid black; }
Nice tip! didn’t know about the inner borders fix
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.
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?
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?”
Simple and nice tips.
Nice! really cool trick
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.. :(
shifting layout has always been a problem with images in a grid…
thanks for sharing the solution… :D
Thanks Chris! When you mailed me back I didn’t know about the outline property, it was a great learning.
Thanks for sharing!
Fix #3: Background-color and padding. (the image shrinks)
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!)
How about a transparent border on non-hover?
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
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; }
Just set a 3px white border to begin with, I just think you are over complicating the issue.
Never knew about the inner border; well, I probably have done it, just never realized it, or memorized the coding. :P
cute! Very useful trick.
Never used a negative margin before. Neat trick.
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}
Never used a negative margin before, Good Tut
Thanks for the tip!
Like Chris (the other one) said, I would use margin: 0 and border instead of outline for fix #2.
Very cool
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.
simple and smart, i like fix #1
Thanks for the simple to learn CSS rollover tutorial! Is this CSS W3C compliance?
Source: w3schools
Thanks very much, I didn’t even know about the
outline
property!You can use box shadows as well..
box-shadow : 0px 0px 0px 5px #000;
Is there drawbacks to using box-sizing (fix 3)? I noticed it’s now included by default in starter themes like underscores.me and it seems the least hackish..?
One of the fixes I use that is somewhat of a hack for one sided borders on lists and such is to add a border to all items in the list and just change the color of the border if wanted. This keeps the layout from changing as well.