Why centered icons look off-center
Sep 18, 2026 · Interface · 3 min read
Design tools are built on boxes. Every shape has a bounding box, and alignment tools center those boxes perfectly. The trouble is that people do not see boxes. They see mass, and mass is rarely centered in its box.
This piece covers three spots where a mathematically correct layout looks wrong, and how to fix each one without turning your codebase into a pile of random nudges.
1. Center by weight, not by box
The classic case is a play button. A triangle pointing right has most of its area on the left, near its flat side. Center its bounding box inside a circle and the triangle looks shoved to the left.
The fix is to move it toward its point until it looks centered. For a play icon that usually lands somewhere around a tenth of the icon width. Treat that as a starting point and then check it at the real size, because the right amount depends on the icon and the container.
.play-button svg {
/* Optical offset: the triangle's mass sits left of its box. */
translate: 8% 0;
}Put the correction in the component, with a comment that says why. A nudge without a comment gets reverted by the next person who notices the icon is not centered in the inspector.
The same thinking applies elsewhere: arrows in circular buttons, text next to a large initial capital, a logo whose mark is heavier on one side. Anything asymmetric needs an eye, not a snap.
2. Match the icon stroke to the text
An icon beside a label is read as part of the same line of type. If the icon's stroke is thinner than the text's strokes, it looks faded and slightly broken, like it belongs to another interface.
A good default: a 1.5px stroke for icons sitting next to 13 to 15px text at regular or medium weight. Go to 2px next to semibold text or at 24px and up. If your icon set supports variable stroke width, set it once in the icon wrapper so every call site gets it for free.
// One place decides stroke weight for the whole product.
export function Icon({ size = 16, ...props }) {
const strokeWidth = size >= 24 ? 2 : 1.5;
return <Glyph size={size} strokeWidth={strokeWidth} {...props} />;
}3. Trim padding on the icon side
A button with a leading icon and equal padding on both sides looks lopsided: heavier on the text side. Icons are drawn with built-in air inside their box, so the icon side already has extra visual padding before you add any.
Take a few pixels off the icon side. With 14px of horizontal padding, 10 or 11px on the icon side usually balances it.
.button {
padding-inline: 14px;
}
.button:has(> svg:first-child) {
padding-inline-start: 10px;
}
.button:has(> svg:last-child) {
padding-inline-end: 10px;
}The :has() selector keeps this automatic. Nobody has to remember a special class for icon buttons.
When to trust the numbers
Optical corrections are for shapes. Grids, spacing scales and text baselines should stay on the numbers, because consistency there is what makes the whole page feel calm. The skill is knowing which kind of alignment you are looking at.
Checklist
- Asymmetric icons (play, arrows, chevrons) are checked by eye in their containers.
- Every optical nudge lives in the component, with a comment.
- Icon stroke weight matches the weight of the text beside it.
- Buttons with icons have less padding on the icon side.
- Spacing scales and grids stay mathematical.
This piece expands on the Interface rules in my cheat sheet, where every rule has a live example.
Keep readingShadows vs borders for depthWhy a stacked box-shadow beats a 1px border, and the tiny outline that keeps images from melting into the page.