PX to REM Converter
Convert px to rem both ways, or paste a whole CSS block and convert every px value at once. Adjustable root font size, quick-reference table, and it leaves the rest of your CSS untouched.
- Free, no account
- No watermark
- No usage limit
About the PX to REM Converter
You inherited a stylesheet specced entirely in pixels, or a designer handed you a Figma export where every value is px, and now you have to move it to rem for accessibility. Most px to rem converters make you retype one number at a time. Paste 16, copy 1rem, paste 24, copy 1.5rem, forty more times, losing your place. This one takes the whole block. Drop your CSS in, and every px value becomes rem in a single pass, selectors, colors, comments, and every other unit left exactly where they were.
There's a single-value mode too, for when you just need to know what 18px is in rem mid-thought. Both directions work, px to rem and rem back to px, against whatever root font size you set. Default base is 16px, what every browser ships, so 16px = 1rem from the start. Your CSS is never uploaded, it all runs in your own browser. Press Share and the address carries the root size and the pixel value you are converting, so a colleague opens the same conversion.
How to use
- Pick a mode. Single value for a one-off lookup, Whole CSS block to convert a stylesheet.
- Set your root font size or tap a preset. Leave it at 16 unless your project sets
html { font-size }to something else. The 10px and 62.5% options each get a button. - Single value: type in either box. A number in Pixels gives you rem, a number in REM gives you pixels, live as you type. Copy either with its unit.
- CSS block: paste your CSS, drag a
.cssfile onto the box, or load one from your machine. Choose px to rem or rem to px. The converted stylesheet appears beside it, ready to copy back in one click. - Leave borders alone if you want. Flip on "Leave 1px alone" and any
1pxvalue stays put, so your hairline borders don't get scaled.
Type units if you like. In single mode "16", "16px", even a stray "1.5rem" all parse, the tool strips the unit and reads the number. Empty or nonsense input shows a blank, never a NaN, and a base of 0 gets a fix-it nudge instead of a silent divide by zero.
Convert a whole stylesheet, not one number at a time
This is the part that saves a real afternoon. A batch converter has to be careful here, because a stylesheet is full of numbers that are NOT lengths, and a lazy find-and-replace wrecks them.
It only touches numbers carrying the unit you're converting. 24px becomes 1.5rem. But line-height: 1.5 stays 1.5, z-index: 100 stays 100, and a color like #e5e7eb is never read as a value. Percentages, vw, vh, seconds, all left alone, because they were already doing their job. Your selectors and property names don't change. A 16px sitting inside a comment, a content: string, or a filename in url() is skipped, so nothing outside the real declarations gets rewritten. You get your stylesheet back, same shape, just in rem.
A couple of small niceties. 0px collapses to a plain 0, since zero is zero in any unit. A 768px in a media query converts too, usually right for breakpoints that should respond to a reader's font setting, and it converts at 16 whatever base you typed in. That is not us being stubborn, it is what browsers do: a media condition is tested before any element exists, so it ignores the root font size your stylesheet sets and reads rem as 16 regardless. Which means the 62.5% people can set the base to 10, get the scaling they came for, and still watch 768px come out as 48rem rather than the 76.8rem that would shove the breakpoint 460 pixels out and stop the tablet layout firing on a tablet. Container queries do read your root font size, so those convert against your base like everything else. And the "Leave 1px alone" switch is there because borders are the one place you almost never want scaling, a 1px hairline that fattens to 1.25px when someone bumps their text just looks wrong. To read someone else's rem-based code, flip to rem to px and the whole block goes back.
Why convert px to rem at all
Every browser lets a person change their default font size, and that's the whole reason rem matters. It's buried in settings, but it's there, and people with low vision use it, bumping 16px up to 20 or 24 so text is comfortable. That preference is the root font size, the number rem is measured against.
Write font-size: 1rem and a reader who set their browser to 20px gets 20px text, with your layout scaling up to match. Hardcode font-size: 16px and you've overridden their choice, so the text stays at 16px no matter what they picked. Someone who needs bigger text simply doesn't get it on your page.
This matters, because accessibility guidelines require text to resize up to 200% without the page breaking, and pixel font sizes make that hard, which rem solves. One note so you don't over-worry, browser zoom scales everything including px. It's the default-font-size preference specifically that px ignores.
px, rem, and em: which goes where
The pros don't convert every pixel. They convert the values that should scale and leave the rest fixed.
Reach for rem on font sizes (the non-negotiable one), and on margins, padding, max-width, gaps, and border-radius, anything you want moving in sympathy with the type. Because they all point at the same root, your spacing stays consistent and scales as one.
Keep px on borders, hairlines, and shadows. Those are structural or decorative, fixed on purpose, and scaling them looks off.
Consider em for padding inside a component that should track its own text, since em is relative to the element's font size. A button whose padding is set in em grows that padding when you bump the button's font size, one change, everything proportional. The catch with em is that it compounds when nested on font-size: 1.2em inside 1.2em is 1.44 times the root, not 1.2, and it snowballs the deeper you nest. rem never does that, it always points at the root. So the rule that keeps you out of trouble, rem for font sizes, em only for component-internal spacing.
The 62.5% / 10px shortcut, and the catch
You'll run into this one constantly. Set html { font-size: 62.5% }, and since 62.5% of 16px is exactly 10px, you've made 1rem = 10px. Now the mental math is effortless, 2.4rem is obviously 24px, and you keep the accessibility benefit because you set a percentage, not a hardcoded pixel.
The catch is that you just made the default text on the page 10px, too small to read, so you have to set body text back up to 1.6rem for a readable 16px. Forget that line and every unstyled bit of text renders tiny. Worse, any third-party component built against a normal 16px root comes in shrunk. On a greenfield project you fully control, fine. On anything with outside CSS in it, I'd leave the root at the default. The 62.5% preset is here either way.
Frequently asked questions
Can it convert a whole CSS file, not just one value?
Yes, that's the point of the CSS block mode. Paste a full stylesheet, drag a .css file straight onto the box, or load one from your machine, and every pixel length turns into rem in one pass, with no copying value by value. When you're done, one button lifts the whole converted block back out. For a quick single lookup, switch to single-value mode instead.
Will it break my selectors, colors, or media queries?
No. Only numbers carrying the unit you're converting change. Class names, IDs, property names, hex and rgb colors, and any value in a different unit like % or vh are untouched. Unitless numbers, think line-height: 1.4 or flex: 1, stay put because they aren't lengths. Media query widths do convert, usually what you want so breakpoints follow a reader's font size, but if you'd rather keep one specific breakpoint, convert the block and edit that single line back.
Should I keep my 1px borders in pixels?
Usually, yes. A border is meant to be a crisp fixed line, and converting it to rem makes it scale with font size, so it thickens and thins as the reader changes their text, which on a hairline just looks like a mistake. Turn on "Leave 1px alone" and the converter skips every 1px value while still converting the rest. Thin separators and shadows follow the same logic, fixed detail, not type.
What happens to 0px, negatives, and long decimals?
A 0px collapses to a plain 0, since zero is the same in any unit and that's the tidy form. Negatives convert normally, -8px becomes -0.5rem at a 16px base. And a value like 15px gives 0.9375rem, which looks like a lot of digits and is exactly correct rather than a rounding bug. The tool caps at four decimals and trims trailing zeros, plenty for CSS. If long decimals bug you, that's part of why the 10px base exists, it makes almost everything short and round.
What root font size should I set?
Leave it at 16 unless your project deliberately changes it, since 16 is the browser default and what third-party components assume. The cleanest declaration is html { font-size: 100% }, which keeps the 16px default and respects a reader who's changed their preference. Some developers set 10px through the 62.5% trick purely for easier math, but that has side effects on anything built against a 16px root, so weigh it first.
Is anything uploaded when I convert a stylesheet?
Nothing. The conversion runs as plain JavaScript in your own browser, so your CSS never leaves the machine, no server, no upload, no account. Disconnect from the internet after the page loads and it keeps working, and a whole proprietary stylesheet stays entirely on your side.