CSS course menu
CSS Transitions: Smooth Hover Effects with transition-duration and Timing Functions
Learn CSS transitions: transition-property, duration, timing functions (ease, linear, cubic-bezier, steps) and delay, the transition shorthand, which properties can be animated smoothly, performance tips, and reduced motion.
On this page
Without transitions, a style change happens instantly: hover a button and its colour snaps. A transition animates the change smoothly over a period of time.
A first transition#
.btn {
padding: 10px 18px;
border: none;
border-radius: 8px;
background: #2f5fe0;
color: white;
font-size: 16px;
transition: background-color 0.3s ease;
}
.btn:hover,
.btn:focus-visible {
background-color: #e8590c;
}<button class="btn">Hover over me</button>The transition is declared on the normal state, so it runs both when the hover starts and when it ends.
The four parts#
The shorthand lists them in this order (duration before delay): transition: transform 0.2s ease-out 0.1s;. To animate several properties, separate them with commas:
transition: background-color 0.2s, transform 0.2s ease-out;Avoid transition: all in real projects: it animates properties you did not intend and can hurt performance.
Timing functions#
.track { position: relative; height: 34px; margin-bottom: 6px; background: #f1f3f5; border-radius: 6px; }
.dot {
position: absolute; left: 4px; top: 4px;
width: 110px; height: 26px; border-radius: 13px;
background: #2f5fe0; color: white; font: 12px/26px monospace; text-align: center;
transition: left 1.2s;
}
.demo:hover .dot { left: calc(100% - 114px); }<div class="demo">
<p>Hover over this box to race:</p>
<div class="track"><div class="dot" style="transition-timing-function: linear">linear</div></div>
<div class="track"><div class="dot" style="transition-timing-function: ease">ease</div></div>
<div class="track"><div class="dot" style="transition-timing-function: ease-in">ease-in</div></div>
<div class="track"><div class="dot" style="transition-timing-function: ease-out">ease-out</div></div>
<div class="track"><div class="dot" style="transition-timing-function: steps(5)">steps(5)</div></div>
</div>What can be transitioned#
Properties with values in between two states can be animated: colours, lengths, opacity, transform, box-shadow and many more. Properties like display (block or none) switch instantly.
For smooth animation, prefer transform and opacity. Browsers can usually animate them without recalculating layout, while animating width, height, top or margin makes the browser redo the layout on every frame, which can stutter.
/* Smooth */
.card { transition: transform 0.2s ease-out; }
.card:hover { transform: translateY(-4px); }
/* Can be janky */
.card { transition: margin-top 0.2s; }
.card:hover { margin-top: -4px; }Duration guidelines#
Small interface changes such as hover colours feel best around 150 to 300 milliseconds. Longer transitions make an interface feel slow. Larger movements across the screen may need a little more time.
Respect reduced motion#
Some people get dizzy or distracted by movement and turn on "reduce motion" in their operating system. Respect it:
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
transition-duration: 0.01ms !important;
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
}
}Colour and opacity fades are usually fine to keep; it is large movement, zooming and parallax that cause problems.
Practice#
Practice exercise
Make a link whose underline grows from the left on hover and focus, using a ::after element that transitions its transform: scaleX() from 0 to 1 over 0.25s with ease-out.
Show solution
.fancy { position: relative; color: #2f5fe0; text-decoration: none; font: 600 18px system-ui, sans-serif; }
.fancy::after {
content: "";
position: absolute;
left: 0;
bottom: -3px;
width: 100%;
height: 2px;
background: currentColor;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.25s ease-out;
}
.fancy:hover::after,
.fancy:focus-visible::after { transform: scaleX(1); }<a class="fancy" href="#">Hover or focus me</a>Key takeaway#
Finished this lesson?