300

I have a row that I am applying a background highlight to on hover.

.jobs .item:hover {
    background: #e1e1e1;
    border-top: 1px solid #d0d0d0;
}

However, as the border adds 1px additional to the element, it makes it 'move'. How would I compensate for the above movement here (without using a background image)?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
David542
  • 104,438
  • 178
  • 489
  • 842
  • 4
    Does your element have a defined height? If so, you can 1) use `box-sizing: border-box` (with the necessary prefixes) for modern browsers, or 2) cheat by adding a border the same color as the default background and shave 1 pixel off the specified height. – BoltClock Mar 08 '12 at 04:12
  • see my answer below and let me know if a am lagging here, so i can understand you problem more specifically. – w3uiguru Mar 08 '12 at 04:22
  • My situation does not work with the solutions below, which I tried before even seeing this thread. I have multiple different buttons that 1. already have borders and 2. have different margins on them. I cannot simply make a transparent border because I already need a small border when not hovering. I cannot just decrease the margin by the differential because each margin is different, and I can't do this with calc(). I have to either go to each individual element with different css and set the hover margin differently (awful) or make the border a **gradient from my color to transparent** – Justin Feb 26 '20 at 23:46

4 Answers4

626

You can make the border transparent. In this way it exists, but is invisible, so it doesn't push anything around:

.jobs .item {
   background: #eee;
   border: 1px solid transparent;
}

.jobs .item:hover {
   background: #e1e1e1;
   border: 1px solid #d0d0d0;
}
<div class="jobs">
  <div class="item">Item</div>
</div>

For elements that already have a border, and you don't want them to move, you can use negative margins:

.jobs .item {
    background: #eee;
    border: 1px solid #d0d0d0;
}

.jobs .item:hover {
   background: #e1e1e1;
    border: 3px solid #d0d0d0;
    margin: -2px;
}
<div class="jobs">
  <div class="item">Item</div>
</div>

Another possible trick for adding width to an existing border is to add a box-shadow with the spread attribute of the desired pixel width.

.jobs .item {
    background: #eee;
    border: 1px solid #d0d0d0;
}

.jobs .item:hover {
    background: #e1e1e1;
    box-shadow: 0 0 0 2px #d0d0d0;
}
<div class="jobs">
  <div class="item">Item</div>
</div>
methodofaction
  • 70,885
  • 21
  • 151
  • 164
  • 13
    anyone seen a way to solve this by using CSS attribute `box-sizing:border-box;`? – tim Feb 26 '13 at 00:22
  • 5
    @tim yes, it works with `box-sizing:border-box;` too. – methodofaction Feb 26 '13 at 12:46
  • 4
    Simple and it works. Thanks! Sometimes the obvious answer isn't so obvious until it hits you in the face. – Sean Kendle Feb 18 '14 at 16:34
  • 2
    It's better if you use color transparent: – chemitaxis Jun 19 '14 at 12:28
  • 1
    @Duopixel It does not seem to work with `box-sizing: border-box` fiddle: https://jsfiddle.net/u2ngmktw/. Can you add more info? – mc9 Mar 30 '16 at 06:02
  • 5
    @SungWonCho for `box-sizing: border-box` to work you would need to specify the width and the height of element, which I assume is not what you want. Use the technique described in the answer https://jsfiddle.net/g9qc2kg3/ – methodofaction Mar 30 '16 at 19:21
  • @Duopixel Didn't know that I needed to specify width and height. Thanks for sharing. – mc9 Mar 30 '16 at 23:19
  • I came across this by accident and was surprised that no one had included background-clip: padding-box; with the border: 1px solid transparent; css. Seems a must for me to include both entries when addressing this issue esp. with box-sizing:border-box;. – Borgboy Sep 08 '16 at 17:55
  • This doesn't work. The box still expands when the border is applied .Yes, I am specifying width and height. – felwithe Feb 24 '19 at 17:43
  • @felwithe making this box-sizing: content-box; made the accepted solution work brilliantly. – Mitch Moccia Jun 12 '20 at 20:43
  • What if I already have a border in default state? This answer doesn't work then. – omeralper Jan 10 '21 at 12:17
  • @omeralper added two alternatives for you – methodofaction Jan 11 '21 at 01:27
  • @methodofaction wow, how I missed this trick, thank you smartie! – Harsha Aug 22 '22 at 12:28
126

add margin:-1px; which reduces 1px to each side. or if you need only for side you can do margin-left:-1px etc.

Dips
  • 3,220
  • 3
  • 20
  • 21
  • 13
    That was the best solution for me because, in my case, I set a 1px border to the orignal element and want to get, on hover, a thicker border (3px). Using `margin: -2px;` indeed works. – Mathieu Castets Aug 12 '14 at 11:58
  • 1
    Indeed the best solution when the border thickness changes from one state to another. – laurent Nov 21 '14 at 11:03
  • 1
    easiest solution – ricks Feb 15 '19 at 19:20
  • 5
    To clarify and formalize this solution: add the negative margin only when applying the thicker border, and use a margin size equal to the thick border minus the thin border. So to transition from a 2px border to a 5px border on hover, you'd use `.some-class{ box-sizing: content-box; border: 2px solid #333 }` then you'd have `.some-class:hover{ margin: -3px; border: 5px solid #333}` (Or whatever colors you like). `box-sizing: content-box` is also needed on the element in question to keep it from shifting when the thick border is applied. [codepen](https://codepen.io/aleph_one/pen/OJVEoGQ) – aleph_one Mar 18 '20 at 18:36
22

Try this it might solve your problem.

Css:

.item{padding-top:1px;}

.jobs .item:hover {
    background: #e1e1e1;
    border-top: 1px solid #d0d0d0;
    padding-top:0;
}

HTML:

<div class="jobs">
    <div class="item">
        content goes here
    </div>
</div>

See fiddle for output: http://jsfiddle.net/dLDNA/

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
w3uiguru
  • 5,864
  • 2
  • 21
  • 25
20

Add a border to the regular item, the same color as the background, so that it cannot be seen. That way the item has a border: 1px whether it is being hovered or not.

Topr
  • 872
  • 3
  • 21
  • 34
danapaige
  • 373
  • 3
  • 16