Search code examples
csscss-animationspseudo-class

Animation within :target pseudo-element triggers only on the first click


I want to highlight some HTML element when another element is clicked. The classic solution with CSS only seems to go as follow, with the following HTML,

<!DOCTYPE html>
<html>
  <body>
    <div>
      There are <a href="#fermions">Fermions</a> 
      and <a href="#bosons">Bosons</a>.
      <div class="highlightable" id="fermions">
        Bosons are very social particles!
      </div>
      <div class="highlightable" id="bosons">
        Fermions only goes out as a couple!
      </div>
    </div>
  </body>
</html>

and the following CSS

@keyframes highlight {
  0% {
    background: LightSkyBlue;
  }
  100% {
    background: none;
  }
}

.highlightable:target {
  animation: highlight 1s;
}

Here is a fiddle implementing this. When I click on "Fermions", the div "Fermions only goes out as a couple!" highlights. Good! When I click again on "Fermions", it does not highlight anymore. But if I click on "Bosons", thus highlighting the other div, and then again on Fermions, then the div with Fermions hightlights again.

Could someone explain what is going on? Is the only solution to always have a click highlight the corresponding div to use Javascript?


Solution

  • Explanation of what you are seeing:

    If your browser is currently pointing at this address:

    mysite.com/mypage/
    

    and you click on <a href="#fermions">, your browser will now point to:

    mysite.com/mypage/#fermions
    

    This will trigger the :target pseudo-class animation.

    If you now click on <a href="#fermions"> again... you won't go anywhere - because you're already there.

    So the animation won't be triggered.


    Achieving this effect (CSS only):

    I appreciate you probably want a CSS-only way to to produce this effect, but... you can only (sort-of) respond to user clicks via CSS using :focus and :target. In both cases, you'll see that once you have entered a given state (and the animation has run once) you will remain in that state (and the animation won't run again) until you pro-actively change the state.

    That said, you can produce the effect you want by responding to user mouse-overs via CSS, using the :hover pseudo-class.

    Working Example:

    [href="#fermions"]:hover ~ #fermions,
    [href="#bosons"]:hover ~ #bosons {
    animation: highlight 1.2s ease-out 0.15s;
    }
    
    @keyframes highlight {
      0% {background: LightSkyBlue;}
    100% {background: none;}
    }
    <div>
    There are <a href="#fermions">Fermions</a> and <a href="#bosons">Bosons</a>.
    
    <p class="highlightable" id="bosons">
    Bosons are very social particles!</p>
    
    <p class="highlightable" id="fermions">Fermions only goes out as a couple!</p>
    </div>