Expanding Hit Areas in CSS
Hover states flicker across the dead gaps between elements. Extend the hit area with padding or a ::before pseudo-element to fix it and meet WCAG 2.5.8.
There's a gap between interactive elements - a few dead pixels where nothing reacts to your pointer. Usually invisible. You don't notice it until something animates: hover states flicker off, transitions reset, things feel broken.
The fix is to extend the hit area - the clickable box - beyond the visible bounds of the element.
Hit areas also have a formal floor. WCAG 2.5.8 requires interactive targets to be at least 24×24 CSS pixels (Level AA). The stronger Level AAA criterion raises that to 44×44 - the threshold most often cited in practice. Apple recommends 44×44; Google 48×48.
Padding
When the element has no visible background or border, padding is the simplest fix: it grows the clickable box without changing how the element looks.
The scroll indicators on the left of this page are 3px-tall dots stacked with 10px gaps between them.The video and live example below show scroll indicators - 3px-tall dots stacked with 10px gaps between them. Move the cursor from one dot to the next and it briefly crosses dead space - the active dot's expand animation snaps back before the next one takes over. Five pixels of vertical padding on each button stretches its clickable box into the gap, so the hit areas tile edge-to-edge and the active state hands off cleanly.
Scroll indicators - live example
py-[5px]::before pseudo-element
Padding doesn't work when the visible box has its own background or border - like a nav menu item that highlights on hover. Extending the box would extend the highlight too. There, an invisible ::before pseudo-element extends the hit area without disturbing the design. It's visually empty by default but still receives hover events.
Let's take a look at the navigation menu from our Direction Aware Navigation article.
Navigation bar - live example
before:absolute before:inset-x-[-8px] before:inset-y-0 before:content-['']One rule: the element needs position: relative so the absolutely-positioned pseudo-element is contained. In Tailwind that's just relative on the parent.
Negative margin + padding
Section headings on this site use padding to extend their hit area left, into where the copy icon floats -ml-6 shifts the heading's box, pl-6 keeps the visible text in its original spot, and the 24px of left padding becomes the bridge to the icon. Hover slowly from the icon into the heading, or try disabling it.
Section heading - live example
Below the nav bar sits a small white arrow that slides left and right to point at whichever trigger is open.
Below the nav bar sits a small white arrow that slides left and right to point at whichever trigger is open.
-ml-6 pl-6Which technique when
- Padding - the element has no visible background or border, so a bigger box looks the same.
::beforepseudo-element - the element has a background, border or hover highlight that must keep its size.- Negative margin + padding - the hit area has to reach toward a neighbour (like a copy icon) without moving the visible content.
Newsletter
Stay updated with my latest articles and projects. No spam, no nonsense.