Icon sizing looks like a solved problem until you actually build an interface. Then you find that the search icon in your header looks fat next to the text, the same icon in a table row looks like a smudge, and the one you scaled up for an empty state looks like it was drawn with a marker pen. Nothing is broken. The SVG is perfectly sharp at every size. It is the design that stopped working.
This guide covers the numbers you need, and, more usefully, the reasons behind them.
If you only take three things
Draw or choose icons on a 24 by 24 grid. Ship three sizes at most in a project, typically 16, 20 and 24. Keep stroke weight constant across the set, and adjust it deliberately when you jump size, rather than letting the browser scale it for you.
- An icon has two sizes, not one
- Why 24 by 24 became the standard
- The UI size scale: what to use where
- Stroke weight and optical sizing
- Sizing SVG icons in CSS
- Tap targets: the icon is not the button
- Favicon, app and social image sizes
- Why icons at the same size still look mismatched
- The sizing checklist
- Frequently asked questions
An icon has two sizes, not one
This is the confusion underneath most icon sizing questions, and it is worth clearing up before any numbers.
Every SVG icon has a design size, expressed in its viewBox, and a rendered size, set by CSS or the width and height attributes. A viewBox="0 0 24 24" does not mean the icon appears at 24 pixels. It means the artwork was drawn inside a 24 by 24 coordinate box. You can render that same file at 12 pixels or 200 pixels and the shape will remain mathematically exact, because an SVG is a set of instructions, not a grid of pixels.
So the file never "gets blurry". What changes as you scale is proportion. Every measurement inside the icon, including the stroke, scales with it. An icon drawn with a 2 pixel stroke on a 24 pixel grid has a stroke that is one twelfth of its width. Render it at 96 pixels and that stroke is now 8 pixels thick, still one twelfth, and it looks clumsy. Render it at 12 pixels and the stroke is 1 pixel, sitting right on the edge of legibility.
Hold that idea. It explains almost everything else on this page.
Why 24 by 24 became the standard
The 24 pixel canvas is not arbitrary and it is not a fashion. It won for structural reasons.
- It divides well. 24 is cleanly divisible by 2, 3, 4, 6, 8 and 12. That means you can centre a shape, halve it, or place it on a third without ever landing on a half-pixel, which is exactly where crisp edges go to die.
- It scales cleanly. Double it and you get 48. Halve it and you get 12. Two thirds is 16, the other size everyone uses. The whole common scale falls out of one number.
- It holds enough detail. A 16 pixel canvas is too tight for anything with internal structure. A 32 pixel canvas invites detail that vanishes the moment the icon is used at its real size. 24 is the size at which an icon can be specific without being fussy.
- Everyone else uses it. Google's Material Symbols, Lucide, Tabler and Phosphor are all drawn on a 24 by 24 canvas. That is why you can mix icons across those sets, at the same size, and mostly get away with it. Mostly. See the consistency section for the ways it still goes wrong.
Inside that 24 pixel canvas, well-designed sets keep a padding zone, usually 1 to 2 pixels of clear space at every edge, so the live artwork sits in roughly a 20 by 20 area. That padding is what stops icons from touching each other in a toolbar and what keeps a square icon and a round icon looking the same size. If you draw your own icons, respect it. Every icon in the five sets in the ICON OOP library already does.
The UI size scale: what to use where
You do not need a size for every situation. You need a small scale, applied consistently. This is the one that most design systems converge on:
| Size | Where it belongs | Notes |
|---|---|---|
| 12px | Micro-indicators, sort arrows, badge dots | Only for simple shapes. Anything with internal detail turns to mush. |
| 16px | Table rows, inline text, dense lists, form field affixes | The workhorse for dense UI. Pairs with 14px body text. |
| 20px | Compact toolbars, menu items, secondary buttons | The in-between size. Useful, but do not use it and 24px in the same component. |
| 24px | Primary buttons, navigation, headers, most icon buttons | The default. If you are unsure, this is the answer. |
| 32px | Feature lists, card headers, mobile tab bars | Increase stroke visually here or the icon starts to look thin. |
| 48px | Empty states, onboarding, pricing tiers | Consider a filled or duotone variant instead of an outline. |
| 64px+ | Marketing pages, hero sections, illustration | An outline icon drawn for 24px will look crude here. Use an icon designed for the size. |
The important discipline is not which numbers you pick. It is picking three of them and refusing to add a fourth. A project with 16, 20 and 24 pixel icons looks systematic. A project with 15, 18, 22 and 26 pixel icons looks like four people built it in different weeks, because that is what happened.
Stroke weight and optical sizing
Now the part that separates an icon set that looks professional from one that does not.
On a 24 pixel grid, 2 pixels is the standard stroke width. It is the default in Lucide and Tabler, and it reads clearly at every UI size without shouting. 1.5 pixels gives a lighter, more refined feel, popular in dense data interfaces, but it can vanish against low-contrast backgrounds and it will fail the WCAG non-text contrast requirement more easily. Below 1 pixel, strokes look broken on standard-density displays.
Here is the trap. Scale a 24 pixel icon with a 2 pixel stroke up to 48 pixels, and you get a 4 pixel stroke. Technically correct, visually wrong: the icon now looks bold and clumsy compared to the 24 pixel version beside it. Scale it down to 16 pixels and the stroke becomes 1.33 pixels, which is a slightly fuzzy, slightly weak line.
Serious icon systems solve this with optical sizing: separate drawings for separate size ranges, with the stroke adjusted so the icon looks the same weight at every size, rather than being mathematically the same weight. Material Symbols exposes this directly as an opsz axis. It is the same principle that makes a well-designed typeface use different letterform proportions for captions and headlines.
You have three practical options, in order of how much you care:
- Use a set with optical sizes. Best result, no effort, if the set you have chosen offers them.
- Adjust
stroke-widthper size. Because ICON OOP icons keepstrokeattributes intact, you can simply override it: usestroke-width:2at 24px, andstroke-width:1.5at 48px, so the visual weight holds. Two lines of CSS. - Use
vector-effect: non-scaling-stroke. This keeps the stroke at a constant device width no matter how the shape scales. It is the right tool for zoomable graphics and maps, and usually the wrong tool for icons, because at large sizes it gives you a giant shape drawn with a hairline. The MDN documentation forvector-effectis worth reading before you reach for it.
One more weight rule that matters at small sizes: filled icons read better than outline icons below 16 pixels. There is simply not enough room for an outline to describe a shape at 12 or 14 pixels. This is why so many mobile tab bars use filled icons for the active state and outline for the inactive one, and it is a legibility decision dressed up as a style decision.
Sizing SVG icons in CSS
Get the markup right and sizing becomes trivial. Get it wrong and you will spend an afternoon on it.
Always keep the viewBox. Usually drop the width and height. An SVG with a viewBox and no fixed dimensions is fully controllable from CSS. An SVG with hard-coded width="24" height="24" will fight you, and one with a width but no viewBox cannot scale at all. Stripping the fixed dimensions while preserving the viewBox is one of the things SVG optimisation should be doing for you.
Set both dimensions.
.icon { width: 24px; height: 24px; }
Setting only one is a common cause of icons that render at some strange default size, because browsers fall back to a 300 by 150 replaced-element box when they cannot work out an intrinsic size.
Size in em when the icon sits with text. This is the trick most people find late and then use forever:
.icon { width: 1.25em; height: 1.25em; vertical-align: -0.125em; }
Now the icon scales with its parent's font size automatically. An icon in a small button shrinks, an icon in a large heading grows, and you never write a media query for it. The vertical-align nudge pulls the icon down so its optical centre lines up with the text baseline, which is the difference between an icon that sits in a button and one that floats above it.
Define the sizes as tokens. If you take nothing else from this section:
:root {
--icon-sm: 16px;
--icon-md: 20px;
--icon-lg: 24px;
}
Three variables, used everywhere, and your icon sizing is now a decision made once rather than a decision made two hundred times. If you are also building an SVG sprite, this pairs naturally with it: one definition per icon, one token per size.
Tap targets: the icon is not the button
A 16 pixel icon is a perfectly good icon and a terrible tap target. These are different measurements and conflating them is one of the most common accessibility failures in shipped interfaces.
WCAG 2.5.8, Target Size (Minimum) asks for at least 24 by 24 CSS pixels of clickable area at level AA. The stricter 2.5.5 at AAA asks for 44 by 44, which is also roughly what Apple's Human Interface Guidelines have long recommended for touch.
The fix is padding, not a bigger icon:
.icon-btn {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 10px; /* 20px icon + 20px padding = 40px target */
}
The icon stays visually correct and the hit area grows around it invisibly. Everything else about making icon buttons usable, labels, focus states, and why an unlabelled icon button announces as nothing at all, is covered in the accessible icons guide.
Favicon, app and social image sizes
Outside the interface, icon sizes are dictated by platforms rather than by taste. The current sensible set:
| Use | Size | Format |
|---|---|---|
| Favicon, modern browsers | Any (scalable) | SVG |
| Favicon fallback | 32 × 32 | PNG or ICO |
| Apple touch icon | 180 × 180 | PNG, no transparency |
| Android / PWA manifest | 192 × 192 and 512 × 512 | PNG |
| Open Graph / social preview | 1200 × 630 | PNG or JPG |
The favicon deserves its own warning: a 24 pixel UI icon will not work as a favicon. At 16 to 32 pixels, in a busy tab strip, an outline icon with fine internal detail becomes an unreadable grey smear. A favicon needs to be a bolder, simpler, higher-contrast mark, usually a single strong shape. The full setup, including the four link tags and the reasons a favicon refuses to update, is in how to add a favicon. If you need to produce the PNG fallbacks from a vector source, the SVG to PNG converter will export them at exact pixel dimensions.
Why icons at the same size still look mismatched
You set every icon to 24 pixels and they still do not look like a family. This is normal, and it has four usual causes.
- Different stroke weights. A 2px-stroke icon next to a 1.5px-stroke icon looks like a mistake even when the sizes match. This is the number one giveaway of icons pulled from two different sets.
- Different corner radii. Phosphor's rounded joins and Material's squarer terminals do not sit comfortably beside each other. It is subtle, and it is why sets have a house style.
- Different padding. If one set draws to the edge of the 24px canvas and another keeps a 2px margin, the first set will look 10 percent larger even at identical dimensions.
- Optical area, not bounding box. A solid square at 24px looks noticeably heavier than a circle at 24px, because it covers more area. Good designers shrink squares slightly and grow circles slightly so they look equal. The bounding box is a lie your eyes do not believe.
The practical rule: use one icon set per interface. Mixing is nearly always a mistake, and the exception is a genuinely different category of graphic, such as a full-colour brand logo or a emoji, where nobody expects visual consistency with your UI icons anyway. If your chosen set is missing an icon, it is usually better to draw one in the same style than to import a stranger. The icon set comparison will help you commit to one before you build.
The sizing checklist
- Icons drawn on a 24 by 24 grid with a consistent 1 to 2 pixel padding zone.
- Three sizes maximum in the project, defined as CSS tokens, not typed in per component.
- One stroke weight across the whole set, adjusted deliberately when the icon jumps size range.
viewBoxpresent, fixedwidthandheightstripped from the SVG source.- Icons sized in em wherever they sit alongside text.
- Clickable area of at least 24 by 24 pixels, achieved with padding, not by inflating the icon.
- Filled icons below 16 pixels, outline icons above.
- Meaningful icons clearing 3 to 1 contrast against their background.
- One icon set throughout, with logos and emoji as the only exceptions.
Nine items. Work through them once at the start of a project and icon sizing stops being something you argue about in code review.
Frequently asked questions
Put it to work: browse 23,000+ icons drawn on a consistent grid, resize and recolour one in the tool, build an SVG sprite so each icon is defined once, or check the accessibility rules before you ship.