Search code examples
htmlcsssafaricss-animationspointer-events

A link that receives pointer-events after animating isn't clickable in Safari


I'm animating text with CSS where elements appear one after the other. Try it out first to see what I mean:

.wrapper {
  pointer-events: none; /* remove pointer events from elements before they animate */
}

.text {
  position: absolute;
}

/* The first element starts off visible and fades out after 2s */
.first {
  opacity: 1;
  animation: fade 500ms reverse forwards 2000ms;
}

/* The second element starts off hidden and fades in after 3s */
.second {
  opacity: 0;
  animation: fade 500ms forwards 3000ms;
}

@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
    pointer-events: all; /* add pointer events to elements after they finish animating */
  }
}
<div class="wrapper">
  <h1 class="text first">Wait 2 seconds...</h1>
  <h1 class="text second">Now <a href="https://example.com">click</a></h1>
<div>

As you can see in the snippet, the second element has a link. By default, it would be clickable throughout the animation, even while its opacity is still 0.

I want the link to become clickable only when it appears, so I'm setting pointer-events: none; on the parent element, and pointer-events: all; on children after they finished animating (in @keyframes).

This works great in Chrome and Firefox, but it doesn't in Safari: the link doesn't become clickable at the end of the animation. The parent's pointer-event: none; rule somehow doesn't get overridden by the more specific pointer-events: all; rule that should apply to the element itself at the end of the animation.

(you can reproduce the issue or fork it in this CodeSandbox)

Here are my questions:

  • Is this a Safari bug? I went through Webkit's issue tracker but couldn't find anything that seems related (there are plenty of other pointer-events bugs though).
  • Is there a way to make this work in Safari without resorting to JavaScript?

Thanks in advance!

Edit

I found a solution for Safari by using visibility: hidden; instead of disabling pointer-events, posted below.

Something else I noticed is that when I test my code with Playwright (a test automation tool that can spin up a headless webkit browser), I can't reproduce the pointer-events bug, so I wonder if this is only an issue with Safari and not webkit itself. I'm still interested in knowing whether this is a known behavior!


Solution

  • Here's the solution I went for that also works on Safari:

    .text {
      position: absolute;
    }
    
    /* The first element starts off visible and fades out after 2s */
    .first {
      opacity: 1;
      visibility: visible;
      animation: fade 500ms reverse forwards 2000ms;
    }
    
    /* The second element starts off hidden and fades in after 3s */
    .second {
      opacity: 0;
      visibility: hidden;
      animation: fade 500ms forwards 3000ms;
    }
    
    @keyframes fade {
      from {
        opacity: 0; /* We still need opacity to animate on */
        visibility: hidden;
      }
      to {
        opacity: 1;
        visibility: visible;
      }
    }
    <div>
      <h1 class="text first">Wait 2 seconds...</h1>
      <h1 class="text second">Now <a href="https://example.com">click</a></h1>
    <div>

    Instead of disabling pointer-events, we can use visibility: hidden; to ensure that the link isn't clickable before it should be.