ICON OOP
Icons & Logos
Guide

Icon sizes: pixels, grids and stroke weight

"What size should this icon be?" has a boring answer and an interesting one. The boring answer is 24 pixels. The interesting one is why 24, why your icon looks wrong at 64, and why two icons at the same size can still look mismatched.

HomeGuidesIcon sizes

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

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:

SizeWhere it belongsNotes
12pxMicro-indicators, sort arrows, badge dotsOnly for simple shapes. Anything with internal detail turns to mush.
16pxTable rows, inline text, dense lists, form field affixesThe workhorse for dense UI. Pairs with 14px body text.
20pxCompact toolbars, menu items, secondary buttonsThe in-between size. Useful, but do not use it and 24px in the same component.
24pxPrimary buttons, navigation, headers, most icon buttonsThe default. If you are unsure, this is the answer.
32pxFeature lists, card headers, mobile tab barsIncrease stroke visually here or the icon starts to look thin.
48pxEmpty states, onboarding, pricing tiersConsider a filled or duotone variant instead of an outline.
64px+Marketing pages, hero sections, illustrationAn 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-width per size. Because ICON OOP icons keep stroke attributes intact, you can simply override it: use stroke-width:2 at 24px, and stroke-width:1.5 at 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 for vector-effect is 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:

UseSizeFormat
Favicon, modern browsersAny (scalable)SVG
Favicon fallback32 × 32PNG or ICO
Apple touch icon180 × 180PNG, no transparency
Android / PWA manifest192 × 192 and 512 × 512PNG
Open Graph / social preview1200 × 630PNG 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.
  • viewBox present, fixed width and height stripped 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

For interface icons, 24 by 24 CSS pixels is the safe default and the size most icon libraries are drawn for. Use 16px for dense contexts like table rows and inline text, 20px for compact toolbars, 24px for standard buttons and navigation, 32px to 48px for feature cards and empty states, and 64px or larger for illustrative use. Pick three sizes for a project and stick to them rather than inventing a new one per component.
24 divides cleanly by 2, 3, 4, 6, 8 and 12, so shapes can be centred and halved without landing on half-pixels, and it doubles neatly to 48. It is also large enough to hold real detail while staying legible when scaled down to 16px. Material Symbols, Lucide, Tabler and Phosphor are all drawn on a 24 by 24 canvas, which is why icons from different sets can usually be used at the same size without looking obviously wrong.
No. SVG is vector, so the shape stays mathematically sharp at any size. What breaks down is the design intent: an icon drawn with a 2px stroke on a 24px grid becomes a heavy 8px stroke at 96px, and a hairline at 12px. The file is not degraded, but the visual weight is wrong, which is why proper icon systems provide optical sizes rather than scaling one drawing across the whole range.
On a 24 by 24 grid, 1.5px to 2px is the standard range. 2px is the default in Lucide and Tabler and reads as confident and clear at small sizes. 1.5px feels lighter and more refined but can disappear against low-contrast backgrounds. Below 1px a stroke looks broken on standard-density screens. Whatever you pick, use the same weight across every icon in the set, because mismatched stroke weights are the most obvious sign of a mixed-source icon system.
Set both width and height on the svg element and let the viewBox do the scaling: width 24px, height 24px. Setting only one dimension can make the browser fall back to a default replaced-element size. For icons that sit inside text or buttons, size them in em instead of px, for example 1.25em, so they scale with the surrounding font size and stay balanced at every breakpoint.
The icon itself can stay 16px or 24px, but the clickable area around it must be larger. WCAG 2.5.8 Target Size at level AA asks for a minimum of 24 by 24 CSS pixels, and the stricter 2.5.5 at AAA asks for 44 by 44. Add padding to the button rather than enlarging the icon: a 20px icon inside a button with 12px of padding gives a 44px target while keeping the icon visually correct.

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.

Resize any icon in seconds

Search 23,000+ icons, set the exact size and stroke weight you need, and download clean SVG or PNG.

Open the ICON OOP tool