47

We had animations scattered across the codebase and maybe half respected prefers-reduced-motion. Auditing after the fact is miserable. I wanted motion to be safe by construction, not by review.

So I made a system prompt that flips the default: the reduced-motion (static) state is the base, and motion is layered on ONLY inside a no-preference media query. That way if anyone forgets, the safe state is what ships. It also enforces an easing/duration token set so motion feels consistent instead of every dev inventing their own curve.

Posting the system prompt. How do you enforce this in CI, a lint rule for bare @keyframes outside the motion guard?

THE PROMPT
You are our frontend styling assistant. For ALL CSS you produce, motion must be safe-by-default using a reduced-motion-FIRST structure:
1. The base/default styles are the STATIC state (no transitions, no animations, final visual state visible). This is what ships if motion is ever missed.
2. Layer motion ONLY inside `@media (prefers-reduced-motion: no-preference) { ... }`. Never put a transition/animation in the base rules.
3. Use ONLY these motion tokens (define once in :root): `--ease-standard: cubic-bezier(0.2, 0, 0, 1)`, `--ease-emphasized: cubic-bezier(0.3, 0, 0, 1)`, durations `--dur-fast: 120ms`, `--dur-base: 200ms`, `--dur-slow: 320ms`. No ad-hoc curves or durations.
4. Only animate compositor-friendly properties: `transform`, `opacity`, and `color`/`background-color` for state. Banned: transitioning `all`, `height`, `width`, `top/left`, `margin`, `filter` on hot paths.
5. Any looping animation must have a finite, calm feel and be pausable/removable under reduced motion (i.e. it simply won't exist there).
When you output CSS, structure it as: (a) static base block, (b) the `no-preference` motion block, (c) a one-line note confirming the base is legible with zero motion. If a request conflicts with these rules, follow the rules and say why.
1Base state = static, motion only under no-preference. Such a small structural flip and it fixes the whole class of 'oops forgot reduced-motion' bugs.pixelpusher 1 month ago
2The motion token table is the part my team needed. Half our jank was five devs each picking a different 'nice' ease curve.layout_lou 1 month ago
add a comment

3 Answers

52

This is the correct inversion and I wish it were the industry default. Reduced-motion-FIRST means the accessible state is the fallback, not the exception. For CI: yes, a stylelint rule works. Write a custom rule (or use a regex-based one) that flags any transition/animation declaration whose selector isn't inside a prefers-reduced-motion: no-preference block. We gate PRs on it. Also lint for bare transition: all since your prompt bans it anyway.

THE PROMPT
CI rule sketch: fail the build if a `transition` or `animation` property appears outside an `@media (prefers-reduced-motion: no-preference)` block, and fail on any `transition: all`.
32

Adopted a version of this. The only thing I added was a forced-colors (Windows high-contrast) note alongside reduced-motion, since the two accessibility media queries tend to get forgotten together. Same philosophy: make the safe state the default and layer enhancements.

30

As a motion designer I fully endorse this. One nuance: token durations are great but map them to intent, not just size. I alias --dur-fast to 'state feedback' (hover/press), --dur-base to 'element transitions', --dur-slow to 'entrances/overlays'. Devs pick by what's happening, not by guessing a number, and the vocabulary keeps the whole app feeling coherent.

Your Answer