Search code examples
javascripthtmlmouseover

Mouse over event only working on one card


enter image description here

I'm using a mouse over event to have the shadows change from black to pink. However, when I add the mosue over event onto the other cards they only change the first card. How to I get each indivual card to change colour when hovered?

JS

<script>
    function mouseOver() {
        document.getElementById("CardHover").style.boxShadow = "-6px 6px 0px 0px #FF8A88";
    }
    
    function mouseOut() {
        document.getElementById("CardHover").style.boxShadow = "-6px 6px 0px 0px #000";
    }
    </script>

HTML

<div class="report" id="CardHover" onclick="location.href='#';" onmouseover="mouseOver()" onmouseout="mouseOut()">
            <img style="width: 100%; height: 100%; border-radius: 10px;" src="#.png" alt="">
            <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 8px;">
                <h6>#ServiceDesign  #DesignThinking  #Ethnography</h6>
                <h4>Title</h4>
                <p>Body Copy</p>
                <a href="#" class="tertiary">Explore</a>
            </div>
        </div>

<div class="report" id="CardHover" onclick="location.href='#';" onmouseover="mouseOver()" onmouseout="mouseOut()">
            <img style="width: 100%; height: 100%; border-radius: 10px;" src="#.png" alt="">
            <div style="display: flex; flex-direction: column; align-items: flex-start; gap: 6px; padding: 8px;">
                <h6>#ServiceDesign  #DesignThinking  #Ethnography</h6>
                <h4>Title</h4>
                <p>Body Copy</p>
                <a href="#" class="tertiary">Explore</a>
            </div>
        </div>

Expectng to have each card have it's own hover using mosue over events.


Solution

  • The main issue in your code is because you're repating the same id attribute value on all the card elements. This is invalid as id must be unique. To fix that problem change the id to a class.

    That being said, there's quite a few other problems in the code which need addressing:

    • Use unobtrusive event handlers created in JS, not inline onX attributes in your HTML. The former allow you to get a reference to the element that raised the event from the Event object, so that you can update it as required.
    • Use mouseenter/mouseleave and not mouseover. The latter fires once for every pixel the mouse moves over the target element, which is overkill in this use case.
    • Put your CSS in an external stylesheet, not in the HTML.
    • Don't put click event handlers that cause page redirects on elements which cannot accept a click event by default - eg. a div. This is because it's very poor for accessibility.

    With all that said, here's an updated working implementation:

    const cards = document.querySelectorAll('.CardHover');
    cards.forEach(card => {
      card.addEventListener('mouseenter', e => {
        e.target.style.boxShadow = '-6px 6px 0px 0px #FF8A88';
      });
    
      card.addEventListener('mouseleave', e => {
        e.target.style.boxShadow = '-6px 6px 0px 0px #000';
      });
    });
    .report {
      box-shadow: -6px 6px 0px 0px #000;
    }
    
    .report>img {
      width: 100%;
      height: 100%;
      border-radius: 10px;
    }
    
    .report>div {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 6px;
      padding: 8px;
    }
    <div class="report CardHover">
      <img src="#.png" alt="">
      <div>
        <h6>#ServiceDesign #DesignThinking #Ethnography</h6>
        <h4>Title</h4>
        <p>Body Copy</p>
        <a href="#" class="tertiary">Explore</a>
      </div>
    </div>
    
    <div class="report CardHover">
      <img src="#.png" alt="">
      <div>
        <h6>#ServiceDesign #DesignThinking #Ethnography</h6>
        <h4>Title</h4>
        <p>Body Copy</p>
        <a href="#" class="tertiary">Explore</a>
      </div>
    </div>

    However, the above is almost entirely moot because you should be using CSS to update the UI, not JS. Here's how to do that using the :hover pseudo-selector:

    .report {
      box-shadow: -6px 6px 0px 0px #000;
    }
    
    .report:hover {
      box-shadow: -6px 6px 0px 0px #FF8A88;
    }
    
    .report>img {
      width: 100%;
      height: 100%;
      border-radius: 10px;
    }
    
    .report>div {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      gap: 6px;
      padding: 8px;
    }
    <div class="report CardHover">
      <img src="#.png" alt="">
      <div>
        <h6>#ServiceDesign #DesignThinking #Ethnography</h6>
        <h4>Title</h4>
        <p>Body Copy</p>
        <a href="#" class="tertiary">Explore</a>
      </div>
    </div>
    
    <div class="report CardHover">
      <img src="#.png" alt="">
      <div>
        <h6>#ServiceDesign #DesignThinking #Ethnography</h6>
        <h4>Title</h4>
        <p>Body Copy</p>
        <a href="#" class="tertiary">Explore</a>
      </div>
    </div>