Skip to content

Search pages

Jump to any page on the site.

Lift

Rises on hover while a shadow fades in.

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.

22 frames336 ms · drawn 4.0×
22 frames at 60 fps. Settles in 336 ms, no overshoot.

When to use

Cards, tiles, and list rows that open something on click. On hover the card rises distance.sm and a shadow layer fades in. It tells the user "this is clickable" before they click.

Use it on pointer hover and keyboard focus only. Touch screens have no hover, so the CSS export wraps it in @media (hover: hover). Pair it with press for the click itself.

Recipe

Hoverable cards and tiles. The card rises distance.sm on hover and its shadow fades in. It settles back when the pointer leaves.

States of the lift recipe
StatePropertyTokenNow
restyliteral0
shadowliteral0
hovery-{distance.sm}-5
shadowliteral1
transitionMovement (spring){spring.fast}stiffness 715 · damping 53
transitionFade duration{duration.fast}132ms
transitionFade easing{easing.standard}cubic-bezier(0.2, 0, 0, 1)

Tokens used

  • spring.fast stiffness 715 · damping 53
  • duration.fast 132ms
  • easing.standard cubic-bezier(0.2, 0, 0, 1)
  • distance.sm 5px

Code

/* lift: Hoverable cards and tiles. The card rises distance.sm on hover and its shadow fades in. It settles back when the pointer leaves.
   Use: <a class="motif-lift">. The shadow is a layer that fades, so only opacity and transform animate. */
.motif-lift {
  position: relative;
  transition: transform var(--motif-spring-fast-duration) var(--motif-spring-fast);
}
.motif-lift::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: 0 8px 24px -6px rgb(0 0 0 / 0.25);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motif-duration-fast) var(--motif-ease-standard);
}
@media (hover: hover) {
  .motif-lift:hover {
    transform: translateY(calc(-1 * var(--motif-distance-sm)));
  }
  .motif-lift:hover::after {
    opacity: 1;
  }
}
.motif-lift:focus-visible {
  transform: translateY(calc(-1 * var(--motif-distance-sm)));
}
.motif-lift:focus-visible::after {
  opacity: 1;
}

/* 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. The shadow still fades in, so the card still answers the pointer.
  • 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.