0

I am unable to get the background color of the li tags to change to red when my mouse hovers over them.

excerpt from javascript.info

Can use pseudo-classes as well: Pseudo-classes in the CSS selector like :hover and :active are also supported. For instance, document.querySelectorAll(':hover') will return the collection with elements that the pointer is over now (in nesting order: from the outermost to the most nested one).

let hover = document.querySelectorAll('li:hover');

for (let elem of hover) {
  elem.style.background = 'red';
};
<div>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <ul>
    <li>a</li>
    <li>b</li>
    <li>c</li>
    <li>d</li>
  </ul>
</div>
Matt Croak
  • 2,788
  • 2
  • 17
  • 35
Brandon
  • 377
  • 3
  • 11
  • 3
    From the site you cited: "document.querySelectorAll(':hover') will return the collection with elements that the pointer is over now". When your JS runs, nothing is being hovered. If you just want the li background to change when you hover over it, forget the JS and just use CSS. `li:hover {background: red}` – j08691 Nov 18 '19 at 20:42
  • 1
    check out this [solution](https://stackoverflow.com/a/11371599/4760460). – Anthony Nov 18 '19 at 20:47
  • Oh. lol im so dumb. Then there's no way for the method to work! I suppose the only way to achieve the result is to addEventListener and mouseenter/mouseover ? – Brandon Nov 18 '19 at 20:48
  • 1
    @Brandon I think that's your best bet. See my answer below. – Matt Croak Nov 18 '19 at 20:49
  • 1
    @Brandon I'd argue that the best way, objectively, is to do this in CSS. JavaScript should never be used for that which is easily accomplished by CSS. `li:hover { background: red; }` – Tyler Roper Nov 18 '19 at 20:51

3 Answers3

1

You might be better off adding a mouseenter and mouseleave event listener to the li tags themselves rather than trying to select them based on the :hover selector. When the document loads, none of them are being hovered over so the collection is empty.

let hover = document.querySelectorAll('li');

for (let elem of hover) {
  elem.addEventListener('mouseenter', () => {
    elem.style.backgroundColor = 'red'
  })
  elem.addEventListener('mouseleave', () => {
    elem.style.backgroundColor = ''
  })
};
<div>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <ul>
    <li>a</li>
    <li>b</li>
    <li>c</li>
    <li>d</li>
  </ul>
</div>
Matt Croak
  • 2,788
  • 2
  • 17
  • 35
1

The problem is that you are not calculating that hover event in real-time. I mean, that way you are not subscribing to any event and querySelectorAll is just executed once. To do so you can try for example the event "onmousemove" so every time it fires it will calculate what you need.

This works:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>Document</title>
  </head>
  <body>
    <div>
      <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
      </ul>
      <ul>
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
      </ul>
    </div>
  </body>
  <script>
    window.onmousemove = () => {
      let hover = document.querySelectorAll("li:hover");
      console.log(hover);

      for (let elem of hover) {
        elem.style.background = "red";
      }
    };
  </script>
</html>
1

You could use mouseover and mouseout events for each li element.

document.querySelectorAll('li').forEach((v) => {
  v.addEventListener('mouseover', (e) => {
    e.target.style.background = 'red';
  });
  v.addEventListener('mouseout', (e) => {
    e.target.style.background = 'white';
  });
});
<div>
  <ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
  </ul>
  <ul>
    <li>a</li>
    <li>b</li>
    <li>c</li>
    <li>d</li>
  </ul>
</div>