Skip to main content

Accessible Animation

Quick Start - gsap.matchMedia()

Example usage

// create a matchMedia object
let mm = gsap.matchMedia()

// only add animations if the user is ok with motion!
mm.add("(prefers-reduced-motion: no-preference)", (context) => {
// This animation will not run if the user has opted out of animation at the OS level
gsap.to(".box", {
rotation: 360,
repeat: -1,
});

});

Animation can really elevate a website, but it can also cause a real headache for some users. With great power comes great responsibility, and the fun "motion design" part of animation is only one part of our job.

Video Explainer

Prefers reduced motion

Did you know that some people have physical reactions to motion? People with vestibular (inner ear) disorders can experience dizziness, headaches, or even nausea from animated content. Sounds horrible right? With this in mind, it's important that our animations are safe for people with motion sensitivities.

Luckily, we can tap into operating system settings with the prefers-reduced-motion media query. This media query detects whether the user has requested the operating system to minimize the amount of animation or motion it uses.

We can listen to this user preference and adjust our animations accordingly with gsap.matchMedia().

In the following code snippet we are animating the box differently depending on the user's preference. We can animate more if the user has no preference set, but if someone has asked for 'reduced' animations, we should be more mindful - either by removing animations or by reducing them.


let mm = gsap.matchMedia()
// this user has no preference set, so it's safe to animate!
mm.add("(prefers-reduced-motion: no-preference)", (context) => {
gsap.from(".box", {
opacity: 0,
rotation: 360,
ease: "back.out"
})
});

// this user has specified "reduced motion", so either remove the animations or simplify them down
mm.add("(prefers-reduced-motion: reduce)", (context) => {
gsap.from(".box", { opacity: 0})
});

Try it out

It's easiest to understand in action! adjust your reduced motion preference and watch how the animation changes.

loading...

Reduce or Remove?

Whether to reduce or remove depends on the animation and should be approached on a case-by-case basis. There are two good questions to ask when trying to assess how to handle an animation.

Is this animation particularly triggering?

Flashing animations with fast, hard cuts between colors can trigger seizures in epileptic users, and animations with large swiping movements on the x or y axis can make users with vestibular disorders dizzy or nauseated. Small areas of change, like micro-interactions, or simple opacity changes are usually ok.

Is the animation decorative or functional?

Some animations are decorative whereas others provide important visual context or feedback on an action. If an animation provides important information, like a progress bar or a download indicator, consider keeping it, but simplifying the animation down. If it's just decorative, removing it entirely is the best option.

Apple's UI

Take a look at how Apple handles their screen transitions with and without reduced motion enabled. Big swiping motions on the x axis can be triggering, but the animation is important for spacial context, so rather than removing it entirely they chose to provide an alternate animation that gently crossfades the opacity.

Providing an animation toggle

Tapping into system preferences isn't bulletproof. After all, there's no guarantee that everyone affected by motion knows how to change their settings. To be extra safe, it's a good idea to add a reduced motion toggle in the UI and put the power back in the user's hands to decide.

Here's a more involved example, using the conditions syntax, showing how you could implement a toggle using gsap.matchMedia().

loading...

SplitText & Screenreaders

People who are blind or partially-sighted might use a screen reader to help them navigate a website. Screenreaders analyze the content of a site and convert it into speech. A screenreader would see the following heading tag and read it out loud to the user.

<h1>Heading</h1>

Most text splitting libraries simply divide the text into divs which screenreaders struggle to read, announcing the content painfully slowly, letter by letter...

<h1>
<div>H</div>
<div>e</div>
<div>a</div>
<div>d</div>
<div>i</div>
<div>n</div>
<div>g</div>
</h1>

Built-in aria

To get around this issue, since v3.13.0 - SplitText adds an aria-label to the parent element and then hides the child elements with aria-hidden. This ensures that when visually impaired people navigate your site, screenreaders will read the aria-label instead of the contents of the split elements.🥳 This approach works for the majority of use-cases and is enabled by default.

<h2 aria-label="My Accessible Heading">
<div aria-hidden="true">My</div>
<div aria-hidden="true">Accessible</div>
<div aria-hidden="true">Heading</div>
</h2>

Screenreader-only duplicate

warning

SplitText's built in aria solution won't surface the functionality and meaning of nested elements (like links) to screenreaders. If you have complex nested text, we recommend using this duplication approach. Exercise restraint here as duplicating lots of DOM elements can lead to performance lags.

Treat text splitting with care and ensure you test thoroughly!

As the aria-label created by SplitText just contains text content, if there are nested elements their functionality will be lost to screenreaders.

<h2 aria-label="This link isn't accessible">
<div aria-hidden="true">This</div>
<div aria-hidden="true"><a href="#">link</a></div>
<div aria-hidden="true">isn't</div>
<div aria-hidden="true">accessible</div>
</h2>

Should you need to preserve the semantics and functionality of nested elements - like links, <strong/> tags or <em/> tags - we recommend disabling the default aria settings with aria:false, and creating a screenreader-only duplicate of your element instead. This way, sighted users will see the animated text, while visually impaired people will get the screenreader-only content announced to them.

loading...

info

A11y expert? Got some advice or feedback? Reach out, We'd love to hear from you!

references

The a11y project

Nielsen Norman Group