Avoiding Jumpy Layouts with Hover and Focus States
Interactive states like hover and focus are essential for accessibility and good user experience. They help users understand what’s clickable, where their cursor is, or which element currently has keyboard focus.
But if you’ve ever added a border on :hover or :focus and noticed your button (or even the whole layout) shift around, you’ve seen the jumpiness problem. That reflow happens because the border changes the element’s box size, forcing the browser to recalculate layout.
Luckily, there are strategies to create smooth, predictable states without introducing these jumps. Let’s explore some common approaches.
1. Keep Border Width Consistent
The simplest solution is to ensure your element always has a border of the same width.
For example, if you want a 2px border on hover, give it a 2px border in the resting state—but make it transparent until hover or focus:
That way, the border is already factored into the element’s box model, and the hover/focus effect is just a color change—no layout jump.
2. Use outline Instead of Border
The outline property is similar to a border, but it doesn’t affect the element’s box size. It paints outside the element’s dimensions, so you won’t get reflow when it appears:
Outlines are especially handy for accessibility because they’re the default focus indicator in most browsers. You can style them, move them outward with outline-offset, and avoid disturbing your layout.
3. Add Emphasis with Shadows
Another approach is to use box-shadow. Like outlines, shadows don’t change the box model—they’re just visual effects painted around the element.
You can make subtle glows, bold outlines, or even inner shadows (inset) depending on the design.
Note: inner shadows (inset) eat into the inside of the element, so they may make buttons feel “smaller.” Outer shadows, on the other hand, can sometimes be clipped by overflow: hidden on parent containers.
4. Account for Visual vs. Actual Space
Even if you avoid reflow, you still need to think about visual space. For example:
- A big outline might overlap nearby text.
- An outer shadow might get cut off by a parent’s
overflow: hidden. - An inset shadow might make the text inside feel cramped.
Test your states in real layouts, not just isolated components, to ensure they behave consistently.
Other Things to Watch Out For
- Focus Rings and Accessibility: Don’t remove focus styles entirely. If you customize them, make sure they remain visible enough for keyboard and assistive technology users.
- Transitions: Adding a transition to your hover/focus styles (
transition: border-color 0.2s ease;) can make state changes feel smoother and less abrupt. - Pseudo-elements: You can simulate borders with
::beforeor::afterpseudo-elements, giving you more control over positioning without changing the element’s box size. - High Contrast Modes: Test your chosen styles in system high contrast modes or forced-colors environments—sometimes outlines/shadows are suppressed, so fallbacks matter.
Conclusion
Hover and focus states shouldn’t come at the cost of jumpy layouts. By keeping border widths consistent, leveraging outlines, or using shadows, you can provide clear interactive feedback without disrupting the flow of your design.
The key is to separate visual emphasis from box model changes. Do that, and your UI will feel both polished and stable.