CSS hover on neighbour to toggle properties

Viewed 385

This is what I am trying to achieve - demo below.

Working:

  • Hover on red div will set the background to red
  • Hover on red div will set the background of the green div to green
  • Hover on blue divs will set the background of the blue divs to blue

Not Working:

  • Hover on blue divs will set/leave the background of the green div to white

Is there a CSS only solution that I have overlooked ? or do I have to resort to using JS for that ?

.root {
  border: 1px solid red;
  width: 300px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.main {
  border: 1px solid green;
  width: 50px;
  height: 50px;
  background: white;
}

.secondary {
  border: 1px solid blue;
  width: 50px;
  height: 50px;
  background: white;
}

.root:hover {
  background: red;
}

.root:hover .main,
.main:hover {
  background: green;
}

.secondary:hover {
  background: blue;
}
<div class="root">
  <div class="main"></div>
  <div class="secondary"></div>
  <div class="secondary"></div>
</div>

2 Answers

For the example provided, you can use the general sibling combinator ~ to target all .main elements after any blue (.secondary) divs. This means that you would need to change the mark-up so that .main appears after your .secondary. You can then change the flex-direction of your divs so that the green div appears first like so:

.root {
  border: 1px solid red;
  width: 300px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: space-around;
  flex-direction: row-reverse;
}

.main {
  border: 1px solid green;
  width: 50px;
  height: 50px;
  background: white;
}

.secondary {
  border: 1px solid blue;
  width: 50px;
  height: 50px;
  background: white;
}

.root:hover {
  background: red;
}

.root:hover .main,
.main:hover {
  background: green;
}

.secondary:hover {
  background: blue;
}

.secondary:hover ~ .main {
  background: white;
}
<div class="root">
  <div class="secondary"></div>
  <div class="secondary"></div>
  <div class="main"></div>
</div>

If the order of the blue divs is important, you can set order: -1 on your .main div rather than reversing the entire row order:

.root {
  border: 1px solid red;
  width: 300px;
  height: 100px;
  display: flex;
  align-items: center;
  justify-content: space-around;
}

.main {
  border: 1px solid green;
  width: 50px;
  height: 50px;
  background: white;
  order: -1;
}

.secondary {
  border: 1px solid blue;
  width: 50px;
  height: 50px;
  background: white;
}

.root:hover {
  background: red;
}

.root:hover .main,
.main:hover {
  background: green;
}

.secondary:hover {
  background: blue;
}

.secondary:hover ~ .main {
  background: white;
}
<div class="root">
  <div class="secondary">1</div>
  <div class="secondary">2</div>
  <div class="main"></div>
</div>

By using only css, this assignment will has some problems in terms of grid and sequencing elements. you can just put main class element into the secondary class element and use position style, you know, this way have special difficulties i don't propose it. But you can use jquery or javascript easily. i wrote jquery code which rise this issues. Please follow this way:

// add this jquery cdn to your html

<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>

// add this code to your script.js

$( document ).ready(function() {
    $(".secondary").hover(function () {
        $(this).parents('.root').find(".main").css({'backgroundColor':'white'});
    },function () {
        $(this).parents('.root').find(".main").removeAttr('style');
    });
});
Related