326

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)?

3
  • 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. Commented Mar 8, 2012 at 4:12
  • see my answer below and let me know if a am lagging here, so i can understand you problem more specifically. Commented Mar 8, 2012 at 4: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 Commented Feb 26, 2020 at 23:46

4 Answers 4

663

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>

Sign up to request clarification or add additional context in comments.

11 Comments

anyone seen a way to solve this by using CSS attribute box-sizing:border-box;?
@tim yes, it works with box-sizing:border-box; too.
It's better if you use color transparent:
@Duopixel It does not seem to work with box-sizing: border-box fiddle: jsfiddle.net/u2ngmktw. Can you add more info?
@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 jsfiddle.net/g9qc2kg3
|
132

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

4 Comments

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.
Indeed the best solution when the border thickness changes from one state to another.
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
That's exactly what I did and it still was not working. So I will add this here if anyone encounters the same problem: You have to use integers for the border size to avoid inconsistency. If you have a 1.5px border expand to a 3px border then what actually happens is that the border is first rendered as 1px and then as 3px, making the difference 2px instead of 1.5px. So just use whole numbers for this to avoid any problems.
23

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.

Comments

23

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/

3 Comments

Only this one worked for me. The margin and the border: transparent ones alter the content inside.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.