Ambient and Background Motion Guidelines
Part of Vestibular-Safe Motion Patterns in Accessible Motion Architecture.
The problem
A landing page has a slowly drifting gradient behind the hero, a field of floating shapes in the features section, and an illustration that breathes continuously in the pricing table. Each was designed to add life. Together they mean something on the page is always moving, wherever the user is reading. Feedback ranges from “distracting” to “I couldn’t finish reading” — and the page’s battery and CPU cost is the highest of any page on the site.
Ambient motion is the only category of animation that runs while the user is trying to do something else.
Root cause analysis: peripheral, persistent and unrequested
It is peripheral. Users are not looking at ambient motion; they are reading next to it. Peripheral vision is especially sensitive to movement, which is why a small drifting shape can pull attention repeatedly even when it is “subtle”.
It is persistent. Interaction motion lasts a few hundred milliseconds. Ambient motion runs for the whole visit, so every one of its costs — attention, discomfort, CPU, GPU, battery — is paid continuously.
It is unrequested. The user did not trigger it and often cannot stop it. WCAG 2.2.2 requires a mechanism to pause, stop or hide any moving content that starts automatically and lasts more than five seconds, which most ambient effects do, as covered in providing pause controls for autoplay motion.
Three variables decide how disruptive it is: speed, area and contrast. Slow, small and low-contrast motion is usually tolerable; fast, large or high-contrast motion is not. The three multiply rather than add — a fast, full-width, high-contrast effect is far worse than the sum of its parts.
It is also the most expensive motion per session. Infinite animations keep layers alive and, if they animate paint properties, repaint continuously. Costs that would be trivial for a 200ms interaction are significant over ten minutes.
Step-by-step resolution
Production code pattern
.ambient {
--ambient-duration: 40s; /* slow: a full cycle takes most of a minute */
animation: drift var(--ambient-duration) ease-in-out infinite alternate;
opacity: 0.35; /* low contrast against the background */
will-change: auto; /* no permanent promotion */
}
@keyframes drift {
to { translate: 3% -1%; } /* small displacement */
}
/* Paused when off-screen, when the tab is hidden, or by user request. */
[data-paused] .ambient,
:root[data-tab-hidden] .ambient,
:root[data-motion-paused] .ambient {
animation-play-state: paused;
}
@media (prefers-reduced-motion: reduce) {
.ambient { animation: none; } /* static decoration remains */
}
<button type="button" class="motion-pause" aria-pressed="false" data-motion-toggle>
Pause background motion
</button>
const root = document.documentElement;
document.querySelector('[data-motion-toggle]').addEventListener('click', (e) => {
const paused = root.toggleAttribute('data-motion-paused');
e.currentTarget.setAttribute('aria-pressed', String(paused));
e.currentTarget.textContent = paused ? 'Resume background motion' : 'Pause background motion';
try { localStorage.setItem('motion-paused', String(paused)); } catch {}
});
// Off-screen ambient effects stop; see the pausing guide for the full observer.
new IntersectionObserver((entries) => {
for (const entry of entries) entry.target.toggleAttribute('data-paused', !entry.isIntersecting);
}, { rootMargin: '100px' }).observe(document.querySelector('.hero'));
Rendering Impact: composite while running, nothing while paused. Keeping the effect to
translateandopacitymeans the continuous cost is compositor work rather than per-frame paint, which matters most for effects that run for minutes.
Persisting the pause choice matters: a user who paused the motion once should not have to do it again on every page. Treat it as a preference, not a per-page control.
The cost of decoration
Ambient motion is worth measuring before shipping, because its cost is per-session rather than per-interaction. An infinite compositor animation on a promoted layer is cheap per frame but never stops; an effect that animates a gradient or a filter repaints continuously and can consume a noticeable share of a phone’s battery over a ten-minute visit, the profile described in pausing off-screen and background-tab animations.
The design question that usually resolves it: if this effect were removed entirely, would anyone notice or miss it? For most ambient motion the honest answer is no — which makes a strong case for slower, smaller and stoppable versions rather than none at all.
Verification checklist
Constraints and trade-offs
- Slower, subtler effects deliver less of the visual impact designers intend.
- A pause control adds interface that most users will not use but some need.
- Persisting a pause preference requires storage and a decision about scope.
- Static fallbacks must still look finished, not like a broken animation.
- Individual sensitivity varies; guidance here is a starting point, not a guarantee.
Frequently asked questions
How slow should background motion be?
Slow enough that it is barely perceptible at a glance — under roughly 2% of viewport width per second for the fastest visible element.
Does ambient motion need a pause control?
If it starts automatically and lasts more than five seconds, yes, under WCAG 2.2.2.
Should ambient motion run when scrolled out of view?
No. Pause it when off-screen and when the tab is hidden; it costs battery and CPU for nothing.
Is it enough to remove ambient motion under reduced motion?
It is necessary but not sufficient. Users without the preference set can still be distracted, so speed, area and contrast limits and a pause control still apply.
Related
- Vestibular-Safe Motion Patterns — the parent topic
- Providing Pause Controls for Autoplay Motion — the conformance requirement
- Pausing Off-Screen and Background-Tab Animations — the implementation for stopping unseen motion