← All writing
Craft · · 6 min

Motion is not decoration

I had this filed under taste. It turned out to be a symptom.

Accessibility CSS

Last month I built a parallax hero. Client asked for it, the designer had drawn it, the background moved at half the speed of the foreground as you scrolled, and I was quite pleased with how smooth I’d got it.

I showed it to a colleague at their desk and after about four seconds they said “can you close that.” Not as a joke. They had a headache for the rest of the afternoon and went home early, and they were apologetic about it, which is the part that bothers me most in retrospect.

I’d been thinking about big scrolling motion as a matter of taste. Whether it’s tacky, whether it’s dated, whether it’s worth the JavaScript. Those are all real questions and they’re all the wrong conversation, because for some proportion of the people who load your page it isn’t a matter of taste at all, it’s a matter of their inner ear.

Your inner ear disagrees

The technical word is vestibular, and the short version is that your balance system takes cues from what your eyes see, and when a large area of the screen moves in a way that implies you’re moving and your body says you’re sitting still, some people get the same response they’d get on a boat.

Dizziness, nausea, disorientation, migraine. Not for the duration of the animation. For hours afterward. My colleague lost an afternoon to four seconds of a hero image, and the thing I keep coming back to is that they apologized to me.

The triggers are fairly consistent, and once you know them you start seeing them everywhere:

Large areas of the screen moving, especially at different speeds to each other, which is exactly what parallax is. Zooming or scaling, especially a full-bleed image that grows. Movement along the z-axis, things flying toward you. Spinning. Anything that hijacks the scroll so the page moves at a speed you didn’t choose, which is the one that gets me personally and I don’t have a vestibular condition, I’m just annoyed.

The numbers I’ve seen for how many adults have experienced some vestibular dysfunction are big enough that I stopped thinking of this as an edge case and started thinking of it as a couple of people in any given meeting.

I'd been treating motion as a question of taste. For some people it isn't taste, it's their inner ear, and the effect lasts hours after the tab is closed.

Reduce, not remove

The instinct once you’ve heard all that is to strip every animation out, and that overcorrects.

Motion often carries information. A panel that slides in from the right has told you where it came from and where it’ll go back to. A list item that fades as it’s removed has told you the removal happened rather than that the page reloaded. Kill all of that and you haven’t made the interface safer, you’ve made it harder to follow, particularly for people who rely on those cues.

The distinction that works for me is between motion that moves something a distance across the screen and motion that changes an appearance in place. A 600px slide is vestibular. A 150ms opacity change is not, and neither is a color transition on a hover state, and neither is a small nudge of a few pixels.

So the reduced-motion version of an interface usually keeps the timing and the sequence and swaps the travel for a fade. Same information, none of the provocation.

One setting, set years ago

There’s a media query for this now, and it reads a setting the person has already turned on at the operating system level, which is the part I find genuinely elegant. You aren’t asking anybody to find a toggle on your site. They set it once, years ago, on their laptop, because everything else was making them ill.

motion.css
.panel {
  transition: transform 300ms ease;
  transform: translateX(100%);
}

@media (prefers-reduced-motion: reduce) {
  .panel {
    transition: opacity 200ms ease;   /* same duration of change, no travel */
    transform: none;
    opacity: 0;
  }
}
CSS

The honest caveat is that as of this month it’s Safari and nothing else. Firefox is close, Chrome hasn’t shipped it. So if you write this today, most of the people it would help won’t get it yet.

I’d write it anyway, for two reasons. It costs almost nothing, and it’s the kind of thing that gets forgotten if you wait for the support to arrive first. And there’s a decent chance the person on macOS or iOS with the setting already on is disproportionately likely to be the person who needs it, because they went looking for that setting for a reason.

The blunt version, and its one gotcha

There’s a widely-passed-around snippet that nukes everything, and as a safety net underneath a large existing site with animation you didn’t write, it’s a defensible thing to drop in:

reduced.css
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
CSS

I’d use that as a floor rather than a plan. Doing it per-component is better, because the blunt version also removes the useful motion I was defending two sections ago.

What the query can’t reach

The media query only governs CSS and whatever JavaScript bothers to ask. Plenty of the worst offenders aren’t styled at all.

An autoplaying carousel is motion nobody asked for on a timer, and it’s also terrible for everyone else, and I have never seen analytics that justified one. If you can’t kill it, at minimum stop it on hover and focus and give it a real pause control.

Autoplaying video, same. matchMedia is the way to ask from script:

motion.js
const still = window.matchMedia('(prefers-reduced-motion: reduce)');
if (still.matches) { video.removeAttribute('autoplay'); carousel.pause(); }
still.addListener(e => e.matches && carousel.pause());
JavaScript

And scroll-jacking, where the page decides how fast you’re allowed to move through it, which the query doesn’t cover because there’s no animation to shorten. The only fix there is not doing it.

Specific beats principled

The parallax got cut. I explained why, and the client agreed within about a minute, which surprised me. I’d assumed I’d be arguing about aesthetics and instead I was telling them that a real customer might have to lie down, and nobody wants that on their homepage.

That turns out to be the useful move, actually. Not “this is bad practice” but “a person I work with lost an afternoon to it.” Specific beats principled, in a meeting, most of the time.

Read similar posts
7 min

Contrast ratios lie

A page I'd checked properly, that passed every automated tool I own, was unreadable on my own phone in a beer garden in June, and the number had nothing to say about why.

7 min

Dark mode is a data problem

A client asked how long a dark mode would take and I said half a day, because I was thinking about colors, and the colors were about an hour of it.