12

here is a fiddle.

http://jsfiddle.net/86juF/1/

how do I prevent the elements from appearing to shift on click?

The elements normally have a 1px border but go to a 2px border on click.

In the fiddle you will see this css

.o {
    height: 50px;
    width: 100px;
    border: 1px solid red;
    margin-bottom: 10px;
    font-weight: bold;
    font-size: 16px;
}

.selected {
    border: 2px solid blue;
}
hvgotcodes
  • 118,147
  • 33
  • 203
  • 236

6 Answers6

42

While you've already accepted an answer, which works, it seems rather more complicated than it needs to be, having to calculate and adjust margins and such; my own suggestion would be to make the border itself transparent, and use a fake 'border', using box-shadow (which doesn't cause any movement since it's not part of the 'flow' as such):

.o {
    /* no changes here */
}

.o.selected {
    border-color: transparent; /* remove the border's colour */
    box-shadow: 0 0 0 2px blue; /* emulate the border */
}

JS Fiddle demo.

David Thomas
  • 249,100
  • 51
  • 377
  • 410
  • to be clear, the unselected item has a 1px border. should i do the same trick there? – hvgotcodes Oct 08 '13 at 18:13
  • I'm sorry, but I don't understand the question you're asking. In this approach it doesn't matter how wide the border of the unselected (`.o`) element is, we're making it transparent when we add the `selected` class to it (so it's still there, unchanged except for its colour). – David Thomas Oct 08 '13 at 18:18
  • Ah, I see. I like this solution better; however, I'm going to keep the checkmark with the first answer since that is the one that helped me at the time. – hvgotcodes Oct 08 '13 at 18:24
  • Don't take this the wrong way, but you should always choose the answer that best answers, and solves, the problem you have (or had). If that's the existing answer, then that's absolutely fine (and I'm trying my best not to appear jealous of @j0691's accepted-answer, because I'm really not), if not, however, you should consider changing. It is, of course, entirely your call (and I'm honestly not trying to persuade you to change your mind, just trying to explain the point of the 'accepted answer' is all). :) – David Thomas Oct 08 '13 at 18:32
  • 2
    yeah i had an opportunity to go back to this, and I made the change. I got to delete a lot of css; this is just so superior i had to change the check. – hvgotcodes Oct 11 '13 at 14:06
5

You'll need to modify the position to account for the change in border width. Use:

.selected {
    border: 2px solid blue;
    position:relative;
    left:-1px;
    top:-1px;
}

jsFiddle example

j08691
  • 204,283
  • 31
  • 260
  • 272
  • danggit, I just got done coding up the js for that, and didn't even consider just putting it in css. facepalm and thanx – hvgotcodes Oct 08 '13 at 13:32
  • It might be better not to use negative left and top. Just preserving the pixel with padding should do the trick. – Anthony Claeys Oct 08 '13 at 13:36
  • @AnthonyClaeys - true, modifying the padding is another possibility. Either way, to compensate for the border width change, another property will need to be changed to compensate. – j08691 Oct 08 '13 at 13:40
5

If you don't want to work with positioning (can get messy sometimes, or collide with current styles) you can use a negative margin:

.selected {
    border: 2px solid blue;
    position:relative;
    margin: -1px;
}
Stephan Muller
  • 27,018
  • 16
  • 85
  • 126
4

Add padding when not selected. And remove the padding when selected. This will replace the 1pixel that is used for the 2px border.

.o {
    height: 50px;
    width: 100px;
    border: 1px solid red;
    margin-bottom: 10px;
    font-weight: bold;
    font-size: 16px;
    padding: 1px;
}

.selected {
    border: 2px solid blue;
    padding: 0px;
}
Anthony Claeys
  • 231
  • 1
  • 9
4

Other options:

box-sizing: border-box;

This will include the border width as part of the total width, you will notice a shift of the content though

wrap with another div

You could wrap the content, the content div will have 1px border white the outer div will be 1px blue. On select both div change to red.

David Nguyen
  • 8,368
  • 2
  • 33
  • 49
0

You can give them position absolute.

.o {
height: 50px;
width: 100px;
border: 1px solid red;
margin-bottom: 10px;
font-weight: bold;
font-size: 16px;
position: absolute;
}

.o1 {
    top: 10px;
}

.o2 {
    top: 100px;
}

.selected {
    border: 2px solid blue;
}
Vladislav Stanic
  • 795
  • 8
  • 13