Motion
Six easing curves and six durations, paired so that a thing enters decelerating and leaves accelerating.
Easing & duration
Easing
--gd-ease-standardcubic-bezier(.2, 0, 0, 1)the default, for anything that both enters and moves--gd-ease-standard-decelcubic-bezier(0, 0, 0, 1)small chrome ENTERING — pills, dropdowns, chips--gd-ease-standard-accelcubic-bezier(.3, 0, 1, 1)small chrome LEAVING--gd-ease-emphasizedcubic-bezier(.2, 0, 0, 1)big surfaces — sheets, side panels--gd-ease-emphasized-decelcubic-bezier(.05, .7, .1, 1)a big surface ENTERING--gd-ease-emphasized-accelcubic-bezier(.3, 0, .8, .15)a big surface LEAVINGDuration
--gd-dur-instant100msa state swap the eye should not track--gd-dur-fast150msTHE default for hover and press feedback--gd-dur-normal200msa popover, a chip--gd-dur-slow300msa dropdown, an accordion--gd-dur-slower400msa side sheet or bottom sheet--gd-dur-long500mslarge-surface TRAVEL — a ~600px side sheet crossing the viewport. Distance sets duration: at 400ms that much travel reads as a jump-cut rather than an arrival--gd-ease-standard-decelLeaving--gd-ease-standard-accelCode
/* small chrome — a dropdown, a chip */
transition: opacity var(--gd-dur-normal) var(--gd-ease-standard-decel);
/* leaving */
transition: opacity var(--gd-dur-fast) var(--gd-ease-standard-accel);
/* a big surface — a side sheet crossing the viewport */
transition: transform var(--gd-dur-long) var(--gd-ease-emphasized-decel);Reduced motion
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }Rules
- Enter slow, exit fast. Always asymmetric: entering takes a
-decelcurve, leaving takes an-accelone. - Use
emphasizedfor big surfaces andstandardfor small chrome. A side sheet and a dropdown on the same curve makes the sheet feel flighty. - Animate transform and opacity only. Never width, height or a colour ramp.
- Let distance set the duration. A ~600px side sheet crossing the viewport takes
--gd-dur-long; a hover state takes--gd-dur-fast. - Never animate the verdict's wording. An icon joins or leaves the approval stack instantly.
- Never animate anything decorative. If the motion is not carrying a state change, it is not carrying anything.
- Do not add a reduced-motion query to a component. It is already covered.
Behavior & Anatomy
What motion is for
Motion exists to keep the subject — the parcel — anchored while everything else rearranges around it. Nothing decorative moves.
Enter and exit are always asymmetric, because a thing that arrives and departs at the same speed reads as a glitch. Transform and opacity are the only properties on the table: anything that animates width, height or a colour ramp is asking the compositor to re-layout sixty times a second, on a page that is also drawing a map. And the verdict never animates its wording — an icon joins or leaves the approval stack instantly, so a changing answer reads as a change of state rather than a loading state.
Why long exists at 500ms
Distance sets duration. A ~600px side sheet crossing the viewport at 400ms reads as a jump-cut rather than an arrival, so the ladder has a step above slower for large-surface travel and nothing else uses it.
Why 0.01ms and not 0
0.01ms rather than 0 is deliberate: a zero-duration transition never fires transitionend, so a component waiting on it would hang forever. Setting it to zero would turn a preference into a broken dialog.
It is honoured once rather than per component, so a new animation is covered the moment it is written.