1

no jquery please

I have the following menu with class=menu-list, I want that on hover of nested/child ul li item, to change background color to white of parent li element

Code and working demo:

   nav .menu-list{
        background: white;
        position: absolute;
        margin-top: 60px;
        padding: 12px 0;
        display: none;
        width: 68vw;
        height: 100vh;

    }

    nav .menu-list li{
        background: white;
        display: block;
        color: #000000;
        position: relative;
        padding: 0;
        border-left: 24px white solid;
    }

    nav .menu-list li:hover{
        background: #eee;
        border-left: 24px #eee solid;
    }

    nav ul li:focus {
        background: white;
    }

    nav ul li:focus ul {
        display: block;
        position: relative;
        left: 0;
        margin-left: -24px;
    }

    nav ul li ul li:hover  {
        background: white;
    }
<nav>
  <ul class="menu-list" style="display: block;">
    <li tabindex="1" onclick="location.href='#/work'; dimScreen()">Work</li>
    <li tabindex="2" onclick="dimScreen()">About
      <ul>
        <li onclick="location.href='#/about/what-we-do'">What we do</li>
        <li onclick="location.href='#/about/how-we-work'">How we work</li>
        <li onclick="location.href='#/about/leadership'">Leadership</li>
      </ul>
    </li>
  </ul>
</nav>

Lame paint screenshot to explain better: enter image description here

Jeka
  • 1,370
  • 3
  • 15
  • 32
  • 1
    As a short rundown of what you can do, you want to bind a mouseover event on your child element. In that event, you want to find the parent, in some form of `var parent = evt.parentNode`, and then you can manipulate the style by `parent.style.background='some hex color'` – David Li Oct 11 '15 at 22:33
  • I wrote out a javascript solution for your reference – David Li Oct 11 '15 at 22:43

4 Answers4

2

First thing, you can't do this with CSS. CSS has no concept of what it's parent element is.

As for javascript, you can use mouse events. Here's an example:

var parentOn = function(e) {
    e.target.parentNode.style.backgroundColor = '#9d7';
}
var parentOff = function(e) {
    e.target.parentNode.style.backgroundColor = '#97a';
}

var children = document.querySelectorAll('.child');    
for (var x = 0; x < children.length; x ++) {
    children[x].addEventListener('mouseover', parentOn);
    children[x].addEventListener('mouseout', parentOff);
};

A few things to note:

  • Any JavaScript DOM query will return an array of nodes, so you must iterate over them to avoid error. JQuery hides this nicely so it can be confusing.

  • the mouseenter and mouseleave combination is subtley different from mouseover and mouseout, you can find out more here

  • Working out how to use JavaScript to add and remove classes would be better than using inline styles. This answer will help. You'll be able to re-use the styles and it'll be easier to maintain - I'd such creating a utility function to handle this, like JQuery's addClass().

  • Using named function variables is a bit clearer than anonymous functions, and more re-usable.

https://jsfiddle.net/chwbuvum/6/

Community
  • 1
  • 1
Toni Leigh
  • 4,357
  • 3
  • 18
  • 34
2

Here's a pure CSS solution

As Tony Leigh pointed out, you cannot do exactly what you asked using pure CSS, but you can make it look like you want.

The changed lines in the CSS are commented in the snippet, and the main change in the HTML is the addition of the span tag in the top-level list elements.

The main idea is that each top-level li remains white, while the enclosed span turns gray on hover. That way, hovering over a sub-list doesn't change color of the parent li.

Code Snippet

    nav .menu-list{
        background: white;
        position: absolute;
        margin-top: 60px;
        padding: 12px 0;
        display: none;
        width: 68vw;
        height: 100vh;

    }

    nav .menu-list li{
        background: white;
        display: block;
        color: #000000;
        position: relative;
        padding: 0;
        /* changed from border to background color
        border-left: 24px white solid;
        */
        padding-left:24px; /* added to put back the "border-left" area */
    }

    nav .menu-list li:hover{
        background: white; /*changed from #eee to white */
        /* changed from border to background color
        border-left: 24px #eee solid;
        */
    }

    /* start added blocks */
    nav .menu-list li span {
        width: 100%;
        display:block;
        position:relative;
        left:-24px;
        padding-left:24px;
    }

    nav .menu-list li span:hover{
        background: #eee;
    }
    /* end added blocks */

    nav ul li:focus {
        background: white;
    }

    nav ul li:focus ul {
        display: block;
        position: relative;
        left: 0;
        margin-left: -24px;
    }

    nav .menu-list li ul li:hover  {
        background: #eee;
    }
<nav>
  <ul class="menu-list" style="display: block;">
    <li tabindex="1" onclick="location.href='#/work'; dimScreen()"><span>Work</span></li>
    <li tabindex="2" onclick="dimScreen()"><span>About</span>
      <ul>
        <li onclick="location.href='#/about/what-we-do'">What we do</li>
        <li onclick="location.href='#/about/how-we-work'">How we work</li>
        <li onclick="location.href='#/about/leadership'">Leadership</li>
      </ul>
    </li>
  </ul>
</nav>
AlexPogue
  • 677
  • 7
  • 12
2

Thanks everyone for trying but I only needed to add this to make it work

  .menu-list li:hover {
        background: #eee;
    }

    .menu-list li:focus {
        background: white;
    }
Jeka
  • 1,370
  • 3
  • 15
  • 32
1

Here's a code based solution:

JS

var listElements = document.getElementsByClassName('submenu');
for (var i = 0; i < listElements.length; i++) {
    listElements[i].addEventListener("mouseenter", function(evt) {   
        evt.target.parentNode.style.background = "red";
    });
    listElements[i].addEventListener("mouseleave", function(evt) {   
        evt.target.parentNode.style.background = "black";
    });
}

HTML CHANGE

<ul class="menu-list" style="display: block;">
  <li tabindex="1" onclick="location.href='#/work'; dimScreen()">Work</li>
  <li tabindex="2" onclick="dimScreen()">About
    <ul class='submenu'>
      <li onclick="location.href='#/about/what-we-do'">What we do</li>
      <li onclick="location.href='#/about/how-we-work'">How we work</li>
      <li onclick="location.href='#/about/leadership'">Leadership</li>
    </ul>
  </li>
</ul>

As you can see, for each of your submenus you will have, I added an additional submenu class to differentiate between the main menu and submenu. When you leave each element, it will change the background of the parent to black. When you enter, it will change it to red, based on the mouseenter and mouseleave events.

What it does is find the parent node and then manipulate the styling of that element.

David Li
  • 1,122
  • 6
  • 16