transition-timing-function
Controlling how a transition progresses through time.
Overview
| Class | Declarations |
|---|---|
transition-timing-function-smooth | transition-timing-function: var(--easing-smooth);
|
transition-timing-function-soft | transition-timing-function: var(--easing-soft);
|
transition-timing-function-crisp | transition-timing-function: var(--easing-crisp);
|
transition-timing-function-snap | transition-timing-function: var(--easing-snap);
|
transition-timing-function-accelerate | transition-timing-function: var(--easing-accelerate);
|
transition-timing-function-decelerate | transition-timing-function: var(--easing-decelerate);
|
transition-timing-function-overshoot | transition-timing-function: var(--easing-overshoot);
|
transition-timing-function-rewind | transition-timing-function: var(--easing-rewind);
|
transition-timing-function-spring | transition-timing-function: var(--easing-spring);
|
transition-timing-function:ease | transition-timing-function: ease;
|
transition-timing-function:ease-in | transition-timing-function: ease-in;
|
transition-timing-function:ease-out | transition-timing-function: ease-out;
|
transition-timing-function:ease-in-out | transition-timing-function: ease-in-out;
|
transition-timing-function:linear | transition-timing-function: linear;
|
transition-timing-function:step-start | transition-timing-function: step-start;
|
transition-timing-function:step-end | transition-timing-function: step-end;
|
transition-timing-function:<function>,<…> | transition-timing-function: <function>,<…>;
|
transition-timing-function:steps(<stop>,<direction>) | transition-timing-function: steps(<stop>,<direction>);
|
transition-timing-function:cubic-bezier(<value>,<value>,<value>,<value>) | transition-timing-function: cubic-bezier(<value>,<value>,<value>,<value>);
|
Examples
Choose an easing curve
Toggle each layer to compare linear, ease-in and ease-out over the same 800ms and 96px. The endpoints and total duration stay identical.
<!-- Linear · constant progress --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition-property:transform transition-timing-function:linear transition:none@print transition-duration-slowest@screen@motion"> Layer 01 </span> </span></label><!-- Ease in · slower at the beginning --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition-property:transform transition-timing-function:ease-in transition:none@print transition-duration-slowest@screen@motion"> Layer 01 </span> </span></label><!-- Ease out · slower at the end --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition-property:transform transition-timing-function:ease-out transition:none@print transition-duration-slowest@screen@motion"> Layer 01 </span> </span></label>Generated CSS
@layer utilities { .transition-timing-function\:ease-out { transition-timing-function: ease-out }}An easing function maps elapsed progress to the interpolated value. It changes the distribution of movement through time, not the declared duration or destination.
Use linear timing for continuous motion
Compare steady movement with four discrete steps. Both travel 96px over one second; steps(4,end) waits until each step boundary before advancing.
<!-- Linear · continuous progress --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition:none@print transition:transform|1s|linear@screen@motion"> Layer 01 </span> </span></label><!-- Four steps · 24px per step --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition:none@print transition:transform|1s|steps(4,end)@screen@motion"> Layer 01 </span> </span></label>Linear timing gives constant progress between these numeric endpoints. Steps creates intentional jumps. Use steps() for stepped timing; it is distinct from a continuously interpolated curve.
Keep entrance and exit curves intentional
Check to move the layer out with ease-out. After it arrives, uncheck to return with ease-in. Each direction keeps the same duration.
<!-- Ease out → ease in on return --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen transition-timing-function:ease-out:has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition:none@print transition:transform|var(--duration-slowest)|ease-in@screen@motion"> Layer 01 </span> </span></label>A transition uses the timing function selected for its new state. The checked rule supplies ease-out for the outward move, and the resting rule supplies ease-in for the return. Reversing an unfinished transition can shorten its return interval.
Apply conditionally
Resize before toggling. Below sm, the layer uses ease-out; at sm, it uses linear timing. Duration and distance remain fixed.
<!-- Ease out → linear at sm --><label class="block w:280px max-w:100% font-sm transform:translateX(96px):has(input:checked)>span>span@screen"> <input type="checkbox" aria-label="Move layer" class="mr-xs accent-color-blue outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible"> Move layer <span aria-hidden="true" class="block h:64px mt-md p-xs outline:1px|dashed|var(--color-line-muted)"> <span id="target" class="grid place-items:center h:48px w:128px b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 opacity:1 transform:none transition:none@print transition:transform|var(--duration-slowest)|ease-out@screen@motion transition-timing-function:linear@screen@sm"> Layer 01 </span> </span></label>The easing value follows the real iframe viewport. Reduced motion and print remove the interpolation, so a reported curve does not imply visible motion when the duration is zero.