Pseudo-elements in the Web Animations API

As of this writing, the features discussed are in the latest stable version of Firefox (75). They are expected to be in an upcoming Safari Technology Preview (possibly 106). They were enabled in Chrome/Edge 84 (current Canary) shortly after the launch of this article.

One of the few pieces that was readily available to CSS but not to the Web Animations API was animating pseudo-elements (such as ::before and ::after). However, this is starting to be supported in the latest rollout of Web Animations API functionality.

When you use the Web Animations API, you start by getting a reference to an element where you can apply an animation. This will be the original element by default.

const logo = document.getElementById('logo');

const main = logo.animate({ opacity: [0, 1] }, {
  duration: 100

The second parameter takes our timing options and a few other options (like an id and in the future, composite). This is where we can specify that we don’t want this animation applied to the main element, but instead a pseudo-element.

const logo = document.getElementById('logo');

const secondary = logo.animate({ opacity: [0, 1] }, {
  duration: 100,
  pseudoElement: '::after'

Expected Result:

Live Result:

See the Pen WAAPI pseudoElement by Dan Wilson (@danwilson) on CodePen.

By observation, it appears that Firefox supports ::after, ::before, and ::marker. Others (such as ::first-letter or ::selection) are not supported. If the browser supports usage of pseudoElement, but the specified pseudo-element is not valid or not supported, an error will be thrown and no animation will happen.

If you have a reference to an animation, you can check if it is running on a pseudo-element by checking inside the effect property. Using the animations from the previous examples:

// null

// "::after"