Aswin Ramakrishnan
Aswin Ramakrishnan

Reputation: 3213

CSS Only: Apply style only on non-hovered siblings

I have 3 boxes which look like the one in the example. I want to apply a certain style on the non-hovered boxes when a user hovers over a certain box (The boxes are always siblings).

Here is how it should work -

.test {
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
.test:hover ~ .test {
  width: 100px;
  background-color: #ddd;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
<div class="test">
  Box 1
</div>
<div class="test">
  Box 2
</div>
<div class="test">
  Box 3
</div>

I can get it working for Box 1. Can somebody help me how I can do it elegantly for Box 2 and 3.

Note: No jQuery or Javascript should be used (which would be a cakewalk in this case).

Upvotes: 0

Views: 263

Answers (3)

C3roe
C3roe

Reputation: 96383

You can not select “upwards” with current CSS selectors, so 2 and 3 are not possible – not directly. You could put all elements into a common container element, and when that is hovered make all boxes gray, and then the actual box hovered blue again:

.test {
    width: 100px;
    background-color: #009AFD;
    height: 100px;
    display: inline-block;
    margin-right: 5px;
    text-align: center;
}
.container:hover .test {
    background:#ddd;
}
.container .test:hover {
    background-color: #009AFD;
}
<div class="container">
    <div class="test">Box 1</div>
    <div class="test">Box 2</div>
    <div class="test">Box 3</div>
</div>

(No need btw. to repeat all those properties that stay the same in the hovered state.)

This however will also apply the hover effect when you are not directly hovering one of the boxes, but also when the container element is hovered in the margin between the boxes – so when in between the boxes, all three of them will become gray.

To fight that effect, you need to get a little creative: By not having the boxes laid out in normal flow, but positioning them absolutely instead, you can make the container element take up no space at all, so it won’t be hovered in the “margins” between the boxes. Hovering the boxes themselves however still triggers :hover for the container element, since the boxes are its children and therefor hovering them means hovering the parent element as well, even if the parent element is not “present” in that space where the mouse cursor is hovering over.

.container {
  position: relative;
}
.test {
  position: absolute;
  top: 0;
  left: 0;
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  text-align: center;
}
#box2 {
  left: 110px;
}
#box3 {
  left: 220px;
}
.container:hover .test {
  background: #ddd;
}
.container .test:hover {
  background-color: #009AFD;
}
<div class="container">
  <div class="test" id="box1">Box 1</div>
  <div class="test" id="box2">Box 2</div>
  <div class="test" id="box3">Box 3</div>
</div>

Of course then you might have to use some additional trickery to keep following elements in normal flow at the same positions they would take, had the absolute positioning not taken the boxes out of flow (like giving the next element a margin-top or something).

And of course the whole thing only works this “simple”, because you want the color for the siblings of the hovered boxes to be the same. Would you wish for different colors for them, then additional trickery of sorts might be needed.

Upvotes: 3

Michael Dziedzic
Michael Dziedzic

Reputation: 543

This will do it:

.test {
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
.parent:hover > div {
  width: 100px;
  background-color: #ddd;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
.parent:hover > div:hover {
  background-color: #009AFD;
}
<div class="parent">
  <div class="test">Box 1</div>
  <div class="test">Box 2</div>
  <div class="test">Box 3</div>
</div>

Enclose the divs in a parent div. Use this selector to change all the children: .parent:hover > div. And this selector to exempt the child that is being hovered: .parent:hover > div:hover.

Upvotes: 1

Oriol
Oriol

Reputation: 288500

.test:hover ~ .test selects .test elements which are following siblings of a hovered .test element.

Instead, you can try :not(). The selector below will match all .test elements which are not hovered:

.test:not(:hover)

.test {
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
.test:not(:hover) {
  background-color: #ddd;
}
<div class="test">
  Box 1
</div>
<div class="test">
  Box 2
</div>
<div class="test">
  Box 3
</div>

If you only want to match the non-hovered elements when one is hovered, you can use

:hover > .test:not(:hover)

.test {
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
:hover > .test:not(:hover) {
  background-color: #ddd;
}
<div class="test">
  Box 1
</div>
<div class="test">
  Box 2
</div>
<div class="test">
  Box 3
</div>

Alternatively, if you want it to work on old browsers that don't support :not(), you can apply the style to all elements, and reset in in the hovered element.

.test {
  /* Set styles for non-hovered */
}
.test:hover {
  /* Set styles for hovered */
}

.test {
  width: 100px;
  background-color: #ddd;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
.test:hover {
  background-color: #009AFD;
}
<div class="test">
  Box 1
</div>
<div class="test">
  Box 2
</div>
<div class="test">
  Box 3
</div>

.test {
  /* Set styles for non-hovered */
}
:hover > .test:hover {
  /* Set styles for non-hovered when another is hovered */
}
.test:hover {
  /* Set styles for hovered */
}

.test {
  width: 100px;
  background-color: #009AFD;
  height: 100px;
  display: inline-block;
  margin-right: 5px;
  text-align: center;
}
:hover > .test {
  background-color: #ddd;
}
.test:hover {
  background-color: #009AFD;
}
<div class="test">
  Box 1
</div>
<div class="test">
  Box 2
</div>
<div class="test">
  Box 3
</div>

Upvotes: 0

Related Questions