---
name: Animation & Motion
type: reference
status: anchor
depends_on: [aleris-tokens.css, foundation/constant-contextual]
propagates_to: [aleris-tokens.css, aleris-design-governance.md, aleris-design-system-open-questions.md, index.html]
open_questions: [OQ-18, OQ-19, OQ-20]
last_verified: 2026-03-21
---

# Animation & Motion — Aleris Baseline

## Status
Design system foundation. Covers motion principles, timing tokens, easing curves, and implementation guidance. Ready for token integration and implementation.

---

## The Position

Animation in Aleris Baseline has one job: confirm that the system is listening. Every movement responds to a user action or communicates a system state. Decorative animation — motion that exists because it looks good — does not belong.

This is the same principle as Tufte's data-ink ratio applied to motion: every animation that doesn't carry information or provide feedback is visual noise.

Aleris interfaces should feel alive and modern, not static or dated. But "alive" means responsive to the user, not performing for them. The difference is whether the motion happens because the user did something, or because the designer thought it would look nice.

---

## Timing: Three Levels

Effective micro-interactions last between 200-500ms. Below 150ms they're imperceptible. Above 500ms they feel sluggish.

```css
--duration-instant: 100ms;   /* State changes that should feel immediate: focus rings, colour shifts */
--duration-fast: 200ms;      /* Buttons, hover, toggles, small feedback */
--duration-moderate: 350ms;  /* Modals, expanding panels, dropdown menus */
--duration-slow: 500ms;      /* Page transitions, large layout changes, major state shifts */
```

### When to Use Each

**Instant (100ms):** Focus ring appearing, input border colour change, checkbox toggle. These are state indicators, not transitions — the user should perceive the change as immediate.

**Fast (200ms):** Button press response, hover state, tooltip appear/disappear, badge update. The user should feel the system reacting to their action without any perceived delay.

**Moderate (350ms):** Modal opening/closing, accordion expanding, sidebar sliding in, card flipping to detail view. These involve spatial change that the user needs to track — the animation shows where something came from and where it went.

**Slow (500ms):** Full page transitions, major layout reconfigurations, onboarding step changes. Used sparingly. Most Aleris interfaces should never need this duration — it's reserved for moments where the spatial transition is large enough that the user would lose context without animation.

---

## Easing: Two Curves

Linear animation (constant speed) feels mechanical. Natural motion accelerates and decelerates. Two easing curves cover all Baseline needs:

```css
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);      /* Elements arriving: fast start, gentle stop */
--ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);    /* Elements moving: gentle start and stop */
```

**ease-out** for things that appear: modals opening, dropdowns showing, elements fading in, tooltips arriving. The element enters quickly and settles into place — it feels responsive.

**ease-in-out** for things that move: panels sliding, elements repositioning, layout shifts. The motion is smooth at both ends — it feels natural.

Never use `ease-in` alone (slow start, fast end) for UI — it makes elements feel like they're accelerating away from the user, which reads as unresponsive.

---

## What Gets Animated

### Buttons
Subtle background-colour transition on hover. Slight scale-down on press (`transform: scale(0.98)`). Not bounce, not glow, not shadow change — just a clear confirmation that the button registered the interaction.

```css
.button {
  transition: background-color var(--duration-fast) var(--ease-out),
              transform var(--duration-instant) var(--ease-out);
}
.button:hover {
  background-color: var(--button-primary-hover-bg);
}
.button:active {
  transform: scale(0.98);
}
```

### Loading States
Skeleton screens with shimmer effect, not spinners. Skeleton communicates "content is coming in this shape" rather than "something is loading somewhere." Shimmer adds a subtle animated gradient that signals activity without demanding attention.

For processes under 2 seconds: skeleton shimmer only.
For processes over 2 seconds: skeleton shimmer + progress indication (percentage or contextual message).
For processes over 10 seconds: consider whether the UI should navigate away and notify when complete.

### View Transitions
Fade (opacity 0→1) or gentle slide for transitions between views within the same context. Duration: moderate (350ms). The user should understand "I moved from here to there" without the transition being a performance.

Page-to-page navigation: fade. Within-page state change (tab switch, filter change): content area crossfade. Panel opening (detail view, sidebar): slide from the relevant direction.

### Expanding/Collapsing
Accordions, detail panels, progressive disclosure — animate height and opacity together. The user needs to see content unfolding, not teleporting in. Duration: moderate (350ms).

Collapse is slightly faster than expand (300ms vs 350ms). Closing feels more decisive; opening feels more gradual. This asymmetry is subtle but contributes to the feeling that the interface responds naturally.

### Feedback: Success and Error
A check icon that draws itself (stroke-dashoffset animation) on form submission success. An input border that transitions to error colour with a single, subtle horizontal shake (2-3px, 2 cycles). These are momentary, purposeful, and then the interface is still again.

### Focus States
Focus rings appear instantly (100ms). They don't animate in — they're state indicators, not transitions. The ring uses `outline` or `box-shadow` with the focus token colour, and it appears the moment the element receives focus.

---

## What Does NOT Get Animated

**Scroll-triggered reveals.** Content that fades in as you scroll down is a cliché that slows the experience and irritates returning users. Show content immediately.

**Page load entrances.** Animated entrances on initial page load consume render time and delay Largest Contentful Paint. The page should appear complete, not perform an arrival sequence.

**Decorative loops.** Rotating icons, pulsing elements, waving hands — anything that moves without responding to an action. Exception: a loading shimmer or spinner during an active wait state.

**Large layout reflows.** Don't animate grid-column changes, responsive breakpoint transitions, or major structural shifts. These are discrete states, not continuous transitions.

**Anything behind the user's back.** If the user isn't looking at the element (it's below the fold, in a background tab, or outside the viewport), don't animate it. Motion that happens off-screen is wasted computation.

---

## Accessibility: prefers-reduced-motion

Non-negotiable. All animations must respect the user's motion preference:

```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;
  }
}
```

This is not optional. Users with vestibular disorders (vertigo, motion sickness, migraine triggers) enable this setting for medical reasons. In a healthcare product, respecting it is doubly important — Aleris's users may disproportionately include people with these conditions.

When reduced motion is active, state changes still happen — they just happen instantly instead of transitioning. The user sees the result without the journey.

---

## Performance: What You Animate Matters

### GPU-friendly Properties (animate freely)
- `transform` (translate, scale, rotate)
- `opacity`

These are composited on the GPU and don't trigger layout recalculation. They're effectively free in performance terms.

### CPU-expensive Properties (never animate)
- `width`, `height`
- `margin`, `padding`
- `top`, `left`, `right`, `bottom` (non-transform positioning)
- `border-width`
- `font-size`

These trigger layout reflow, forcing the browser to recalculate the position of potentially every element on the page. On a clinician's tablet running seven browser tabs, this matters.

### CSS over JavaScript

CSS transitions and `@keyframes` are more performant than JavaScript animation libraries for standard UI interactions. Reserve JS-based animation (GSAP, Framer Motion, Motion One) for complex, state-dependent sequences that CSS can't express.

For most Baseline components, CSS transitions are sufficient:

```css
.element {
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}
```

---

## Surface Temperature and Motion

Communicative surfaces can afford slightly longer, more expressive transitions. The rhythm is slower, the user is browsing, and a 350ms modal opening feels appropriate.

Instrumental surfaces keep motion tight. Fast (200ms) is the default for everything. The user is working, switching between tasks, and any animation longer than necessary is friction. Modals and panels may use moderate (350ms), but buttons, hovers, and state changes stay at fast or instant.

The tokens are the same. The application differs by context.

---

## Motion Tokens Summary

```css
/* Duration */
--duration-instant: 100ms;
--duration-fast: 200ms;
--duration-moderate: 350ms;
--duration-slow: 500ms;

/* Easing */
--ease-out: cubic-bezier(0.0, 0.0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0.0, 0.2, 1);
```

These six tokens, combined with the rule "animate only transform and opacity," cover every animation Aleris Baseline needs. The constraint is the feature.

---

## Design Decision Record

**Decision:** Animation serves feedback and state communication only, not decoration.
**Why:** Aleris's brand is "den nära experten" — calm, precise, professional. Motion that decorates competes with that positioning. Motion that responds to the user reinforces it. The interface should feel responsive and alive, not performative.

**Decision:** Four duration levels, two easing curves. No more.
**Why:** A constrained motion vocabulary creates consistency across products and teams. When every developer picks their own timing and easing, the interface feels incoherent — like an orchestra where everyone plays at different tempos. Six tokens (four durations, two easings) are enough for every interaction pattern.

**Decision:** prefers-reduced-motion support is mandatory, not recommended.
**Why:** Aleris builds healthcare products. A significant portion of users — patients with vestibular conditions, post-surgical patients, users on medication that affects balance — will have this preference active. Ignoring it is both an accessibility failure and a clinical insensitivity.

**Decision:** CSS transitions preferred over JavaScript animation libraries.
**Why:** CSS transitions are GPU-accelerated, declarative, and require no runtime library. They cover 95% of Baseline's animation needs. JavaScript libraries add bundle size, runtime cost, and framework dependency. Use them only when CSS genuinely cannot express the required behaviour.

**Decision:** Skeleton shimmer screens preferred over spinners for loading states.
**Why:** Skeletons communicate the shape and position of incoming content, giving the user a preview of the layout. Spinners communicate only "wait." Skeletons reduce perceived loading time and prevent layout shift when content arrives. They also align with progressive enhancement: the structure is there before the content.

---

## Open Questions

- Should Baseline include a standard skeleton component (generic shimmer rectangle/circle), or should each product define its own skeletons matching its specific content layout?
- How does animation behave in Aleris's email communications? Email clients have extremely limited CSS animation support — the answer is likely "no animation in email" but this should be documented explicitly.
- Should there be a "motion audit" as part of design review — checking that every animation has a stated purpose and uses Baseline tokens?
