Every designer has heard that buttons on mobile need to be “big enough”. The problem is that the three most quoted sources give three different numbers: 24 px, 44 px and 48 px. None of them are wrong. They simply measure different things for different reasons.
This guide is the practical reference we use internally at CSSMates when we audit interfaces: what the real minimums are, how much space you need between tappable elements, where thumbs actually reach on today’s phones, and the CSS patterns that fix mis-taps without redesigning your whole UI.
The short answer
- Absolute accessibility floor: 24 × 24 CSS pixels (WCAG 2.2, Success Criterion 2.5.8, Level AA).
- Safe practical minimum: 44 × 44 CSS pixels (Apple Human Interface Guidelines, WCAG 2.5.5 Level AAA).
- Recommended default: 48 × 48 CSS pixels (Google / Material Design, web.dev).
- Minimum gap between two targets: 8 px, ideally 12 to 16 px for dense interfaces.
If you only remember one rule: design your interactive elements at 48 × 48 px with 8 px of breathing room, and you satisfy every guideline at once.

The official numbers, side by side
| Source | Stated minimum | In CSS pixels | Status |
|---|---|---|---|
| Apple Human Interface Guidelines | 44 × 44 pt | 44 × 44 px | Platform guideline (iOS) |
| Material Design 3 / Android | 48 × 48 dp (7 to 10 mm physical) | 48 × 48 px | Platform guideline (Android) |
| WCAG 2.2 – SC 2.5.8 Target Size (Minimum) | 24 × 24 CSS px | 24 × 24 px | Level AA, legally referenced |
| WCAG 2.1 – SC 2.5.5 Target Size (Enhanced) | 44 × 44 CSS px | 44 × 44 px | Level AAA |
| Nielsen Norman Group | 1 cm × 1 cm (0.4 in) | ~38 × 38 px | Research-based recommendation |
| Microsoft Fluent (touch) | 40 to 44 px | 40 to 44 px | Platform guideline |
Why 44 and 48 are not the same number
The gap comes from the unit and the reference density, not from a disagreement about fingers.
- Apple counts points. One point equals one CSS pixel on the web. At the original iPhone density of 163 ppi, 44 pt lands at roughly 6.9 mm of glass. Apple also assumes a tightly controlled layout where the visible control and the hit area are the same rectangle.
- Google counts density-independent pixels. At the Android baseline of 160 dpi, 48 dp equals about 7.6 mm, and Google rounds the guidance up to “about 9 mm” because the target usually includes padding around a smaller visual icon. Material components frequently show a 24 px icon inside a 48 px invisible hit box.
- WCAG counts the legal floor, not the ideal. 24 × 24 CSS px at Level AA was chosen as an achievable baseline for existing content, especially data tables, inline links and dense editing tools. It is a compliance minimum, not a usability target. The AAA criterion (44 px) is what usability research actually supports.
Practical translation: 44 px is the minimum you should ship, 48 px is the size you should default to, and 24 px is the number you fall back on only when a control is genuinely inline with text.

The rule everyone forgets: spacing between targets
A 48 px button surrounded by three other 48 px buttons with zero gap is still a mis-tap machine. Finger contact patches are 8 to 10 mm wide, far bigger than the pixel you think you are aiming at, and the visual center of a fingertip is not where the touch is registered. Touch Targets on Touchscreens tackles the same question from another angle.
- Minimum gap: 8 px between any two independent actions.
- Comfortable gap: 12 to 16 px for lists, toolbars and icon rows.
- Destructive actions: 24 px or more, or move them out of the row entirely.
WCAG 2.2 explicitly allows an undersized target to pass SC 2.5.8 through the spacing exception: if you can draw a 24 px diameter circle centered on the target and it does not overlap the circle of any neighbouring target, the control passes even if it is visually smaller. This is exactly how a 16 px close icon with generous padding around it stays compliant.
Quick sizing cheat sheet by component
| Component | Target size | Spacing |
|---|---|---|
| Primary CTA | 48 to 56 px height, full width or 60% min | 16 px from anything |
| Secondary button | 44 to 48 px height | 12 px |
| Icon button (menu, close, share) | 48 × 48 px hit area, 24 px glyph | 8 px |
| Bottom navigation item | 48 px height minimum, 56 px bar | Equal flex division |
| Form input and select | 48 px height, 16 px font size | 16 px vertical rhythm |
| Checkbox / radio | 24 px control inside a 48 px tappable label | 8 px between options |
| Inline text link in a paragraph | Exempt from 2.5.8, but keep line-height ≥ 1.6 | Avoid stacked links |
| Table row action | 40 px minimum with spacing exception | 12 px between icons |
Thumb reach zones on modern phone screens
Screen sizes have stopped growing but they have not shrunk. The mainstream range in 2026 sits between 6.1 and 6.9 inches, which means a one-handed user physically cannot reach the top third of the display without shifting grip. Around three quarters of interactions are still one-handed or thumb-driven.
Divide the viewport into three horizontal bands:
- Bottom third (easy): natural thumb arc. Put primary actions, navigation, submit buttons and sticky CTAs here.
- Middle third (stretch): reachable with a small hand shift. Good for content and secondary controls.
- Top third (hard): requires a grip change. Reserve for titles, back links, and rarely used utilities. If you must place an action there, make it 48 px and duplicate it lower in the flow.
Two extra details that break real layouts:
- The gesture bar. The bottom 20 to 34 px of the screen is owned by the operating system. Use
env(safe-area-inset-bottom)so your sticky bar is not swallowed by it. - Screen corners. The extreme bottom corners are awkward on tall devices. Full-width buttons dodge the problem entirely.
.sticky-cta {
position: sticky;
bottom: 0;
padding-block: 12px;
padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}

CSS patterns that make targets big without breaking your design
1. Size with min-height, not height
Fixed heights break when text wraps or when a user increases the font size. Use logical minimums plus padding.
.btn {
min-block-size: 48px;
min-inline-size: 48px;
padding: 12px 20px;
display: inline-flex;
align-items: center;
justify-content: center;
touch-action: manipulation; /* removes the legacy tap delay */
}
2. Expand the hit area without changing the visual size
When the design calls for a small 24 px icon, keep the visual and grow the invisible target with a pseudo-element.
.icon-btn {
position: relative;
inline-size: 24px;
block-size: 24px;
}
.icon-btn::after {
content: "";
position: absolute;
inset: -12px; /* 24 + 12 + 12 = 48px hit area */
}
Watch out for one trap: if two of these overlap, the last one in the DOM wins. Always confirm the expanded areas do not collide.
3. Adapt to the input device with pointer media queries
Desktop with a mouse does not need 48 px rows. Let the input type decide.
:root {
--tap: 36px; /* fine pointer default */
}
@media (pointer: coarse) {
:root { --tap: 48px; }
}
.btn,
.nav-link,
.form-control {
min-block-size: var(--tap);
}
This single token is the cheapest accessibility upgrade you can ship on an existing design system. It is argued more carefully on material.io.
4. Make the whole label tappable for form controls
.field {
display: flex;
align-items: center;
gap: 12px;
min-block-size: 48px;
cursor: pointer;
}
.field input[type="checkbox"] {
inline-size: 24px;
block-size: 24px;
flex: none;
}
5. Never let inputs trigger iOS auto-zoom
Any input with a font size under 16 px makes Safari zoom the page on focus, which throws off every other target on screen. Set font-size: 16px on all form fields.

How to test tap targets in the browser
Do not eyeball it. Four methods, in order of speed:
- Chrome DevTools device mode. Toggle the device toolbar, pick a mid-range phone profile, then hover any element. The overlay shows the exact box in CSS pixels including padding. Anything under 44 × 44 goes on the fix list.
- A debug CSS outline. Paste this into DevTools and undersized targets light up immediately:
a, button, [role="button"], input, select, summary { outline: 2px dashed rgba(255,0,0,.6); outline-offset: 2px; } - A measuring snippet. Run this in the console to list every offender:
document.querySelectorAll('a, button, [role="button"], input, select, summary') .forEach(el => { const r = el.getBoundingClientRect(); if (r.width < 44 || r.height < 44) { el.style.outline = '3px solid red'; console.log(Math.round(r.width) + 'x' + Math.round(r.height), el); } }); - An accessibility extension. axe DevTools and similar tools now flag WCAG 2.2 SC 2.5.8 violations including the spacing exception, which is much more reliable than the old Lighthouse tap target audit that has since been retired from the SEO category. Finish with a real device test: emulators do not have thumbs.
The seven mobile button mistakes that cause mis-taps
- Icon-only buttons at their glyph size. A 20 px SVG in a 20 px anchor is the single most common failure. Wrap it in padding.
- Stacked links with tight line-height. Footer link columns at
line-height: 1.2leave roughly 19 px of vertical target. Use 1.6 or add block padding. - Adjacent destructive and safe actions. “Save” next to “Delete” with a 4 px gap. Separate them, or move the destructive action into a menu.
- Close buttons jammed into a corner. Modal and cookie banner close icons pushed to the screen edge collide with system gesture areas and browser chrome.
- Carousel dots and pagination. 8 px dots with 4 px gaps look elegant and are unusable. Keep the dot visual small, but give each one a 44 px hit box.
- Desktop tables shrunk to mobile. Row action icons inherit desktop density. Switch to a card layout under 768 px.
- Sticky bars without safe-area padding. The bottom 30 px of your CTA sits under the gesture bar and every tap either misses or exits your app.

A pre-launch checklist
- Every interactive element measures at least 44 × 44 px, 48 px for primary actions.
- No two independent targets are closer than 8 px.
- Inline text links pass through the WCAG inline exception, not by accident.
- Form fields are 48 px tall with 16 px text.
- Primary actions live in the bottom third of the viewport.
- Sticky elements respect
env(safe-area-inset-bottom). - Targets still pass when the browser text size is set to 200%.
- Tested on a real phone with one hand, not just in device emulation.
FAQ
What is the recommended size for mobile buttons?
48 × 48 CSS pixels is the recommended default because it satisfies Google’s Material guidance, Apple’s 44 pt minimum and WCAG’s Level AAA criterion simultaneously. For primary calls to action, 56 px tall and full width performs best on tall screens.
Is 44px enough for a touch target?
Yes, 44 × 44 px meets Apple’s guideline and WCAG 2.5.5 Level AAA. It is a valid minimum. But if the control is used frequently, sits near other targets, or is a primary action, use 48 px or more.
Does WCAG apply to mobile apps?
WCAG was written for web content, but it is the reference standard used by mobile accessibility guidance worldwide, and regulators routinely apply it to native apps. WCAG 2.2 target size criteria map cleanly onto native controls, and both Apple and Google build their own accessibility documentation on the same principles. In practice: apply it.
What is the WCAG AAA target size?
SC 2.5.5 Target Size (Enhanced), Level AAA, requires targets of at least 44 × 44 CSS pixels, with exceptions for inline links, user-agent controls, and cases where a particular presentation is essential.
Do inline links in a paragraph need to be 24px tall?
No. Targets in a sentence or block of text are explicitly exempt from SC 2.5.8. That said, generous line-height and avoiding two links on consecutive lines still reduce mis-taps significantly.
Are CSS pixels the same as device pixels?
No. A CSS pixel is a density-independent unit. On a phone with a device pixel ratio of 3, one CSS pixel renders across three physical pixels. As long as your page has a correct viewport meta tag, 48 CSS pixels stays roughly the same physical size on every device, which is exactly why guidelines are written in CSS pixels and dp rather than hardware pixels. dequeuniversity.com has covered this at length.
How do I fix targets that are too small without a redesign?
Three low-risk moves: add block padding rather than changing heights, expand hit areas with an ::after pseudo-element, and introduce a --tap custom property gated behind @media (pointer: coarse). Most sites clear the 44 px bar with under 50 lines of CSS.
Need an audit?
Touch target problems rarely show up in analytics as errors. They show up as abandoned forms, rage taps and lower mobile conversion. If you want a second pair of eyes on your interface, the CSSMates team runs tap target and mobile usability audits that come back with a prioritised list of CSS fixes, not a 60 page PDF.