Pseudo-elements in the Web Animations API

As of September 2020, the features discussed are now in the latest versions of Firefox, Safari, Edge, and Chrome.

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 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:

console.log(main.effect.pseudoElement);
// null

console.log(secondary.effect.pseudoElement);
// "::after"