0

Is there a way to have display none on divs levelOne to levelFour when I hover one levelFive by just using CSS? My Html Structure is below:

<div class="dropDownMenus levelOne"></div>
<div class="dropDownMenus levelTwo"></div>
<div class="dropDownMenus levelThree"></div>
<div class="dropDownMenus levelFour"></div>
<div class="dropDownMenus levelFive"></div>

My CSS looks like this:

.levelFour {
  &:has(+ .levelFive) {
    display: none;
  }
}

This effectively hides the levelFour div right above levelFive, but is there a way to do so on hover.

  • 1
    `:has` is not supported on FireFox – Mister Jojo Jul 19 '23 at 14:15
  • Are those elements all in one parent element? – A Haworth Jul 19 '23 at 15:00
  • You could do this in CSS were it not for the fact that the instant you remove preceding elements with display none the mouse or finger etc will probably no longer be hovering over the element as it will have moved. Making preceding elements have eg opacity 0 is possible as the parent is also being hovered and the element won’t move. So, what do you actually want to happen? – A Haworth Jul 19 '23 at 15:25

4 Answers4

1

Unfortunately, CSS alone does not provide a way to select and style preceding siblings. However, you can achieve the desired effect using a combination of JavaScript and CSS. Here's a possible solution:

HTML:

<div class="dropDownMenus levelOne"></div>
<div class="dropDownMenus levelTwo"></div>
<div class="dropDownMenus levelThree"></div>
<div class="dropDownMenus levelFour"></div>
<div class="dropDownMenus levelFive" onmouseover="hidePrecedingSiblings(this)"></div>

CSS:

.dropDownMenus {
/* Your styles for dropDownMenus class here */
}

JavaScript:

function hidePrecedingSiblings(element) {
const siblings = element.previousElementSibling;
while (siblings) {
if (siblings.classList.contains('dropDownMenus')) {
  siblings.style.display = 'none';
}
siblings = siblings.previousElementSibling;
}}

With this solution, when you hover over the levelFive element, the JavaScript function hidePrecedingSiblings() will be triggered, which will hide all preceding siblings with the class dropDownMenus. This gives you the desired effect of hiding the levelFour, levelThree, levelTwo, and levelOne divs when you hover over the levelFive div.

Remember to adjust the CSS styles and class names according to your specific design requirements.

1

This won't work without the wrapper, but with the wrapper and the reasonable modern :has selector, you could easily use something like this:

main:has(.levelFive:hover) *:not(.levelFive)

Snippet:

main .dropDownMenus {
  width: 100%;
  font-size: 3em;
  padding: .5em;
  background: red; 
  margin-bottom: 2px;
  color: white;
  transition: all .4s;
}
main .levelFive {
  cursor: pointer;
}
main:has(.levelFive:hover) *:not(.levelFive){
  opacity: .5;
}
<main>
  <div class="dropDownMenus levelFive">5</div>
  <div class="dropDownMenus levelOne">1</div>
  <div class="dropDownMenus levelTwo">2</div>
  <div class="dropDownMenus levelThree">3</div>
  <div class="dropDownMenus levelFour">4</div>
</main>
somethinghere
  • 16,311
  • 2
  • 28
  • 42
1

This matches any elements having in the next siblings any element with .levelFour class:

.dropDownMenus:has(~.levelFive:hover){
  display:none;
}

.dropDownMenus{
  background: lightgray;
  width: 100px;
  padding: 3px 10px;
  cursor:pointer;
  margin: 2px;
}
.dropDownMenus:hover{
  background: #bbb;
}
<div class="dropDownMenus levelOne">1</div>
<div class="dropDownMenus levelTwo">2</div>
<div class="dropDownMenus levelThree">3</div>
<div class="dropDownMenus levelFour">4</div>
<div class="dropDownMenus levelFive">5</div>
Alexander Nenashev
  • 8,775
  • 2
  • 6
  • 17
1

unfortunately with only css you will not be able to do it as :has is not yet support by all browser

At the date of this message (07/2023) the near bad solution in pure css can be to hide with a blank square other top value

.wrapper .levelFive:hover {
  position: absolute;
  top: 0;
  height: 120%;
  width: 100%;
  background: white;
  z-index: 9;
}

.wrapper {
  position: relative;
  width: fit-content;
}
<div class="wrapper">
  <div class="dropDownMenus levelOne">one</div>
  <div class="dropDownMenus levelTwo">two</div>
  <div class="dropDownMenus levelThree">three</div>
  <div class="dropDownMenus levelFour">four</div>
  <div class="dropDownMenus levelFive">five</div>
</div>

or if you want to guard 5 item at same place

.wrapper .levelFive:hover {
  position:absolute;
  top: 0;
  height: 125%;
  width: 100%;
  background: white;
  display: flex;
  align-items: end;
}

.wrapper {
  position: relative;
  width: fit-content;
}
<div class="wrapper">
  <div class="dropDownMenus levelOne">one</div>
  <div class="dropDownMenus levelTwo">two</div>
  <div class="dropDownMenus levelThree">three</div>
  <div class="dropDownMenus levelFour">four</div>
  <div class="dropDownMenus levelFive">five</div>
</div>
jeremy-denis
  • 6,368
  • 3
  • 18
  • 35