Scale with Pseudo-elements


When a user hovers over something actionable, like a button or a link, it can be useful to indicate to the user that the item can be interacted with. Typically this is done with a color change or an underline, but we can be more creative than that!

A favourite trick of mine is to scale up the item on hover, and add a brief transition. That way, it appears to grow under the cursor:

The problem with this effect is that text sometimes looks wonky when scaled up, especially on non-retina monitors. The effect isn't always crisp.

A fancier way to do this would be to only scale the background when we hover:

This effect is a bit more quirky and eye-catching, and you get to avoid all the funkiness with text crispness.

Link to this heading
With vanilla HTML/CSS


We can create a utility component for this effect:


We add display: inline-block to the Wrapper so that the container shrinks down to cover the children, without expanding to fill the available horizontal space.

The trick to this effect is animating the pseudo-element.

We definitely want to use a transform: scale transition, since it's both more performant and more smooth than trying to animate width or height, or fussing with background-size.

If we wanted, we could also add a blank <div> instead of using a pseudo-element… but it feels way nicer to use a pseudo-element, since it means a style concern is encapsulated entirely within our CSS.

Link to this heading
Additional Exploration

There's so much more you can do with this concept. Here are some suggestions:

  • Experiment with other transforms (rotation, skew, translate…).
  • Use opacity to pronounce the hover even further (say, going from 0.8 opacity to 1).
  • Give other easing timing functions a shot.
  • Use a keyframe animation to include several "steps" in the transition.
  • Use :active (on a button or link) to have a different effect when the user is interacting with the element.
  • Apply a slightly different transition to the element itself, so that both the element and the ::after pseudo-element move independently (but in a synchronized way).
  • Use spring physics to produce a more natural effect.

Have fun!