Skip to content

Search pages

Jump to any page on the site.

Reveal

Children fade and rise, one after another.

Live demo

The preset here changes the whole site. Slow motion and reduced motion change this stage only.

Frame by frame

Every frame of the movement, on top of each other. Wide gaps are fast. Ghosts past the dashed outline are overshoot. It updates with the preset.

24 frames383 ms · drawn 2.7×
24 frames at 60 fps. Settles in 383 ms, overshoots 0.3%.

When to use

Lists, grids, and search results: groups of items that appear together. Each child fades in and rises distance.md, one after another. The stagger stops at stagger.cap children, so a long list does not keep the last item waiting.

Use it when content first appears, not on every scroll.

Recipe

Lists, grids, search results. Children fade in and rise distance.md, one after another, up to stagger.cap.

States of the reveal recipe
StatePropertyTokenNow
initialopacityliteral0
y{distance.md}15
animateopacityliteral1
yliteral0
exitopacityliteral0
yliteral0
transitionMovement (spring){spring.default}stiffness 511 · damping 40
transitionFade duration{duration.base}188ms
transitionFade easing{easing.enter}cubic-bezier(0, 0, 0, 1)
transitionExit duration{duration.fast}132ms
transitionExit easing{easing.exit}cubic-bezier(0.3, 0, 1, 1)
transitionStagger delay{stagger.list}32ms
transitionStagger cap{stagger.cap}8

Tokens used

  • spring.default stiffness 511 · damping 40
  • duration.base 188ms
  • easing.enter cubic-bezier(0, 0, 0, 1)
  • duration.fast 132ms
  • easing.exit cubic-bezier(0.3, 0, 1, 1)
  • stagger.list 32ms
  • stagger.cap 8
  • distance.md 15px

Code

/* reveal: Lists, grids, search results. Children fade in and rise distance.md, one after another, up to stagger.cap.
   Use: <ul class="motif-reveal">. Children enter when mounted. */
.motif-reveal > * {
  transition:
    opacity var(--motif-duration-base) var(--motif-ease-enter),
    transform var(--motif-spring-default-duration) var(--motif-spring-default),
    filter var(--motif-duration-base) var(--motif-ease-enter),
    clip-path var(--motif-spring-default-duration) var(--motif-spring-default);
}
@starting-style {
  .motif-reveal > * {
    opacity: 0;
    transform: translateY(var(--motif-distance-md));
    filter: none;
    clip-path: none;
  }
}
.motif-reveal > * {
  transition-delay: calc(var(--motif-stagger-step) * var(--motif-stagger-n, 0));
}
.motif-reveal > :nth-child(2) {
  --motif-stagger-n: 1;
}
.motif-reveal > :nth-child(3) {
  --motif-stagger-n: 2;
}
.motif-reveal > :nth-child(4) {
  --motif-stagger-n: 3;
}
.motif-reveal > :nth-child(5) {
  --motif-stagger-n: 4;
}
.motif-reveal > :nth-child(6) {
  --motif-stagger-n: 5;
}
.motif-reveal > :nth-child(7) {
  --motif-stagger-n: 6;
}
.motif-reveal > :nth-child(8) {
  --motif-stagger-n: 7;
}
/* Children past stagger.cap (8) enter with the last staggered child. */
.motif-reveal > :nth-child(n + 9) {
  --motif-stagger-n: 7;
}

/* Reduced motion: the variable overrides at the end of motif.css set
   travel to 0, scale to 1, and blur to 0, so this recipe needs no extra rule. */

Reduced motion

  • No rise and no stagger. All children fade in together at duration.fast.
  • Fades take 132ms (duration.fast), so the state change stays visible.
  • Turn on the Reduced motion box under the demo to preview it, or set your system to reduce motion.