Skip to content

Motion

Duration, easing, and reduced-motion behavior. Patterns transition with semantic motion tokens — not raw 120ms or cubic-bezier(...) strings in feature CSS.

Two duration families:

FamilyForExamples
--af-duration-*CSS transitionsHover color, border, accordion height, drawer
--af-animation-duration-*CSS keyframe animationsSpinner, skeleton, entrance keyframes
TokenDefaultUse for
--af-duration-fast120msHover, color, border, opacity, focus chrome
--af-duration-md200msDefault layout motion (panels, accordion)
--af-duration-slow320msLonger panel / emphasis transitions
TokenDefaultUse for
--af-animation-duration-fast200msShort micro-motion
--af-animation-duration-md400msDefault keyframe length
--af-animation-duration-slow600msSpinners, short loops
--af-animation-duration-slower1500msSkeleton shimmer, long loops

Hover each swatch. Same property change; different --af-duration-*.

<button class="demo-motion-swatch" style="transition-duration: var(--af-duration-fast)">Fast</button>
<button class="demo-motion-swatch" style="transition-duration: var(--af-duration-md)">Md</button>
<button class="demo-motion-swatch" style="transition-duration: var(--af-duration-slow)">Slow</button>
TokenDefaultUse for
--af-ease-standardcubic-bezier(0.2, 0, 0.2, 1)Default UI transitions (buttons, fields)
--af-ease-emphasizedcubic-bezier(0.2, 0, 0, 1)Stronger decelerate / emphasis
--af-ease-outcubic-bezier(0, 0, 0.2, 1)Entering panels, drawer slide, accordion
--af-ease-incubic-bezier(0.4, 0, 1, 1)Exiting / accelerating away
--af-ease-in-outcubic-bezier(0.4, 0, 0.2, 1)Symmetric loops (skeleton)
--af-ease-linearlinearProgress, indeterminate spin

Same duration (--af-animation-duration-slower); each row uses a different --af-ease-*. Watch how the dots accelerate.

  • standard

  • emphasized

  • out

  • in

  • in-out

  • linear

animation: demo-ease-travel var(--af-animation-duration-slower) var(--af-ease-standard) infinite alternate;

Transitions (most pattern chrome):

.af-btn {
  transition:
  background-color var(--af-duration-fast) var(--af-ease-standard),
  border-color var(--af-duration-fast) var(--af-ease-standard),
  color var(--af-duration-fast) var(--af-ease-standard);
}

Keyframes (Spinner, Skeleton):

.af-spinner {
  animation: af-spin var(--af-animation-duration-slow) var(--af-ease-linear) infinite;
}

.af-skeleton {
  animation: af-skeleton-load var(--af-animation-duration-slower) var(--af-ease-in-out) infinite;
}

Layout motion (Drawer slide, Accordion):

transition:
transform var(--af-duration-md) var(--af-ease-out),
height var(--af-duration-md) var(--af-ease-out);

Airframe respects prefers-reduced-motion: reduce in two places:

  1. Tokens (@airframeui/tokens) — every --af-duration-* and --af-animation-duration-* becomes 0.01ms, including values you override in :root.
  2. Base (@airframeui/core) — transition-duration / animation-duration forced near zero on all elements; animation-iteration-count: 1; scroll-behavior: auto.

Override timing in :root when you need a different product feel — reduced-motion still collapses those overrides:

:root {
  --af-duration-fast: 80ms;
  --af-duration-md: 160ms;
  --af-animation-duration-slower: 2s;
}

Force reduced motion in a subtree (previews, demos, dense admin chrome) with af-reduce-motion:

Default

af-reduce-motion

<div class="af-reduce-motion">
  <span class="af-spinner" aria-hidden="true"></span>
</div>

Demos on this page: If your OS prefers reduced motion, the hover comparisons above will snap. Turn the preference off (or use a browser without it) to feel the curves.

  1. Tokens only. Product and pattern CSS references --af-duration-*, --af-animation-duration-*, and --af-ease-*. No hardcoded ms or cubic-bezier outside the token file.
  2. Pick the family. Transitions → --af-duration-*. Keyframes → --af-animation-duration-*.
  3. Default pair. Hover and control chrome: fast + standard. Entering panels: md + out.
  4. Do not disable reduced motion. Do not set long durations under @media (prefers-reduced-motion: reduce). The token collapse and base rules are the contract.