Interaction effects with :hover and transitions
:hover matches an element while a pointing device is over it. Paired with transition, it turns an abrupt state change into feedback that feels connected to the visitor's action. The strongest effects clarify what is interactive; decoration is secondary.
Hover is only one input state. A production component must also expose a visible :focus-visible state, remain understandable on touch screens, and avoid moving neighboring content. This guide builds that complete interaction model.
Put the transition on the resting state
Declare transition on the base selector so the browser can animate both entering and leaving the state. If it exists only inside :hover, the return trip has no transition after the pointer leaves.
List the properties you intend to animate instead of using transition: all. Explicit lists document the behavior and prevent a future layout property from becoming animated by accident.
- transform
- Moves or scales the visual layer without changing the space reserved in layout.
- opacity
- Useful for overlays and labels, but never hide essential information only until hover.
- box-shadow
- Effective in moderation; large animated blurs can require expensive repainting.
.card {
border: 1px solid rgb(148 163 184 / 18%);
box-shadow: 0 8px 24px rgb(2 6 23 / 18%);
transition: transform 180ms ease, border-color 180ms ease,
box-shadow 180ms ease;
}
.card:hover {
transform: translateY(-4px);
border-color: rgb(96 165 250 / 45%);
box-shadow: 0 16px 36px rgb(2 6 23 / 30%);
}Mirror intent with :focus-visible
A link or button reached with a keyboard needs feedback at least as clear as hover. :focus-visible lets browsers show a strong ring for keyboard-like navigation without forcing it on every pointer click.
Do not remove outlines unless you replace them with an equally visible indicator. Use outline-offset so the ring remains distinct from the component border and survives high-contrast themes better than a shadow alone.
.action:hover,
.action:focus-visible {
color: white;
background: #2563eb;
}
.action:focus-visible {
outline: 3px solid #93c5fd;
outline-offset: 3px;
}Treat hover as an enhancement on touch
Many touch devices emulate hover after a tap, while hybrid laptops can switch between coarse and precise pointers. Essential controls, labels, and instructions must exist without hover. Use capability media queries only when the effect genuinely depends on a precise hovering pointer.
For cards, avoid making an overlay the only route to the content. Keep the title or primary action visible, then add richer movement under (hover: hover) and (pointer: fine).
@media (hover: hover) and (pointer: fine) {
.card:hover .card__art {
transform: scale(1.04) rotate(.5deg);
}
}Keep the page stable
Changing width, padding, or border thickness can push surrounding elements and make the target move away from the pointer. Reserve border space in the resting state and use transforms for visual growth.
Pseudo-elements are useful for underlines, glows, and directional fills because they can animate independently without changing the component's dimensions. See the pseudo-element guide for robust layering patterns.
Live catalog examples
These production examples use :hover. Open any effect to inspect its complete source and experiment in the browser editor.
Browser support
Support notes refer to stable, unprefixed behavior unless a prefix is explicitly listed.
| Feature | Browsers | Note |
|---|---|---|
| :hover / transition | All modern browsers | Behavior varies on devices without persistent hover. |
| :focus-visible | All modern browsers | Provide an ordinary focus fallback only for legacy browser requirements. |
| hover and pointer media queries | All modern browsers | Capabilities can change during a session on hybrid hardware. |
Common pitfalls
transition is declared only on :hover
Move it to the resting selector so entering and leaving both animate.
transition: all hides unintended work
Name only the properties that form the interaction.
The focus ring is removed
Never use
outline: nonewithout an accessible replacement.Critical information appears only on hover
Keep it visible or reveal it through a control that works with keyboard and touch input.
Frequently asked questions
- How long should a hover transition be?
- Roughly 120–220ms suits most direct feedback. Larger scene changes may need more time, but the interface should never feel delayed.
- Should hover and focus look identical?
- They can share color or movement, but focus also needs a persistent, high-contrast indicator such as an outline.
- Why does my card jump on hover?
- You are probably changing layout dimensions. Reserve the space beforehand or use transform for the visual change.
- Does :hover work on mobile?
- It may be emulated, but not consistently. Design the component to work without it.
Related guides
- @keyframesCSS animations with @keyframesBuild reliable CSS animation timelines, combine multiple motions, and keep them smooth and accessible.
- ::before / ::afterLayering with ::before and ::afterCreate independent decorative layers with predictable positioning, stacking, clipping, and pointer behavior.
- perspective / transformPerspective and CSS 3D transformsConstruct stable 3D scenes, preserve depth across children, and avoid flattening, clipping, and unreadable text.
- backdrop-filterFrosted glass with backdrop-filterBlur and adjust the scene behind translucent surfaces without sacrificing contrast, fallback quality, or scrolling performance.
Last updated:
All guides