CSS Unit Converter

Every unit here except px is a ratio against something else, and the something else is editable. rem measures against the root font size, em and percent against the parent, vw and vh against the viewport — set those four fields to whatever your stylesheet and target screen actually use.

Whatever html { font-size } resolves to. 16 is the browser default, not a guarantee.
Used for em and percent
CSS Unit Converter — px to rem, em, pt, Percent, vw and vhBuildFigure

Every unit is measured against something

px in CSS is a reference pixel, not a device pixel. On a high density screen one CSS pixel is painted with two or three physical pixels, and on a phone the viewport is scaled so that a CSS pixel stays roughly the same apparent size as it is on a laptop. That is why a 16px font does not become microscopic on a 3x display.

rem is a multiple of the root element's font size. em is a multiple of the current element's font size, except when you use it on font-size, where it resolves against the parent instead. % means something different for every property — the parent font size for font-size, the containing block's width for width, and the containing block's width for padding and margin even in the vertical direction. This tool treats percent as a font-size percentage, because that is the only reading where it converts cleanly to the other units here. vw and vh are one hundredth of the viewport width and height. pt is a print unit that CSS pins to exactly 1.3333px.

The root font size is not yours to assume

The default is 16px in every mainstream browser, and almost every conversion table on the internet is built on that number as though it were a constant. It is a default, not a constant. A user who turns their browser's default text size up to 20px has changed what 1rem means on your site, and that is the mechanism WCAG 1.4.4 relies on. Text sized in rem grows with them. Text sized in px does not move at all.

Page zoom is a separate mechanism that scales px too, which is why the problem is easy to miss during testing — you zoom, everything grows, and you conclude the page is fine. Try it the other way: set the browser's default font size to 24px without zooming and reload. Whatever stays exactly the same size is hardcoded in px.

Because of that, treat the root field above as a project setting you have to look up, not as 16. If your stylesheet sets html { font-size: 62.5% } to make 1rem equal 10px, put 10 in the field — but note that the trick only holds while the user's default is 16px. At a 20px default that same rule yields 12.5px, and every rem value on the page shifts with it.

Where em earns its place, and where it hurts

em compounds. Three nested elements each set to font-size: 1.2em end up at 1.728 times the original, and the fourth level is where someone files a bug about the text being huge. Sizing type in rem removes the nesting entirely, since rem never looks at the parent.

What em is genuinely good at is anything that should scale with the text it sits next to: button padding, icon sizing, the width of a form field measured in characters, the offset of a badge. Write those in em and they stay proportional when you change the component's font size once, at the top.

Viewport units and pt

Fluid type built purely from vw ignores the user's text size setting completely, because vw has nothing to do with fonts. The usual fix is to keep a rem term in the expression — clamp(1rem, 2vw + 0.5rem, 2rem) scales with the viewport but still responds to the root font size. Also be aware that vh on mobile has historically meant the viewport with the browser chrome collapsed, which is why full-height sections jump when the address bar hides; svh, lvh and dvh exist to name those states explicitly.

The pt column assumes 96 CSS pixels per inch. That is what the CSS specification defines, so the conversion is exact within CSS, but it is not a claim about your physical monitor — a print driver, a design tool set to 72 DPI, or an image exported at 300 DPI will all disagree. Use pt for print stylesheets and for carrying values across from a word processor, and stay in rem or px on screen.

The values here are rounded to four decimal places. Browsers accept more precision than that and then rasterise to roughly 1/64 of a pixel anyway, so the rounding is not what will cost you a subpixel.

Questions people ask

What is 16px in rem?

One rem, if the root font size is 16px. That qualifier is the whole answer. The conversion is value divided by root font size, so 16px is 1rem at a 16px root, 0.8rem at a 20px root, and 1.6rem under the 62.5% trick. If you are writing a conversion into a stylesheet rather than reading one off, prefer writing the rem value and letting the browser do the multiplication, because then it stays correct when the root changes.

Should I use rem or px for media query breakpoints?

Breakpoints in em or rem respond to the user's default font size, so a person reading at 24px gets the smaller-screen layout sooner — usually what they want, since their text needs more room. Note that media query em units always resolve against the initial font size, not against your html rule, so the 62.5% trick does not affect them. px breakpoints are simpler to reason about and are still extremely common. Either is defensible; mixing the two in one stylesheet is not.

Why does percent give a different answer than I expected for width?

Because this tool computes percent against the parent font size, which is the correct base only for font-size. For width, percent is a share of the containing block's width; for padding and margin, it is a share of the containing block's width in both directions, which is how the padding-bottom aspect ratio hack used to work. There is no single conversion from a width percentage to px without knowing the container, so the tool does not pretend to offer one.

Are the decimals safe to paste into CSS?

Yes. Browsers parse arbitrary decimal precision and round internally during layout, typically to 1/64 px. The visible risk is not precision but accumulation: a column set to 33.3333% three times leaves a fraction of a pixel of gap. Grid, flexbox and calc() avoid that by dividing the space once instead of multiplying a rounded share.

Related