본문 바로가기
Converter

PX REM 변환기

루트 폰트 크기 기준으로 px와 rem을 양방향 변환

1rem

html 요소의 font-size

16px = 1rem(base 16px)

자주 쓰는 값 변환표

base 16px 기준

pxrem복사
1px0.0625rem
2px0.125rem
4px0.25rem
8px0.5rem
10px0.625rem
12px0.75rem
14px0.875rem
16px1rem
18px1.125rem
20px1.25rem
24px1.5rem
28px1.75rem
32px2rem
40px2.5rem
48px3rem
64px4rem
80px5rem
96px6rem

px 대신 rem을 쓰는 진짜 이유

rem을 쓰라는 말은 흔한데, 이유가 “반응형이니까” 정도로 뭉뚱그려질 때가 많습니다. 실제 이유는 접근성에 가깝습니다.

브라우저에는 글꼴 크기 설정이 있습니다. 크롬이라면 설정 → 모양 → 글꼴 크기입니다. 이걸 ‘크게’로 바꾸면 <html>의 font-size가 16px에서 20px로 바뀝니다. 시력이 좋지 않은 사용자에게는 이게 사이트를 읽을 수 있느냐 없느냐를 가르는 설정입니다.

이때 font-size: 14px로 고정한 글자는 아무 반응도 하지 않습니다. 사용자가 설정을 바꿨는데 화면은 그대로입니다. 반면 font-size: 0.875rem은 17.5px이 됩니다. 같은 크기를 다르게 적었을 뿐인데 한쪽만 사용자의 요청을 듣습니다.

여기서 자주 오해하는 게 있습니다. 브라우저 확대(Ctrl +)는 px도 같이 커집니다.확대는 화면 전체를 배율로 늘리는 것이라 단위와 무관합니다. 그래서 “확대해 보니 px도 커지던데?”라고 결론 내리기 쉬운데, 확대와 글꼴 크기 설정은 다른 기능이고 rem이 대응하는 쪽은 후자입니다.

16으로 나누기 전에 확인할 것

px을 rem으로 바꾸는 계산 자체는 나눗셈 한 번입니다. 실수는 계산이 아니라 무엇으로 나눌지에서 나옵니다.

16은 브라우저 기본값이지 CSS 명세가 정한 상수가 아닙니다. 프로젝트에 이런 줄이 하나라도 있으면 기준이 달라집니다:

html { font-size: 62.5%; }   /* 1rem = 10px */
html { font-size: 14px; }    /* 1rem = 14px */
:root { font-size: 100%; }   /* 1rem = 브라우저 설정값 */

그래서 변환하기 전에 프로젝트의 루트 font-size를 먼저 확인해야 합니다. 개발자 도구에서 <html>을 선택하고 Computed 탭의 font-size를 보면 실제 적용된 값이 나옵니다. 위 변환기의 base를 그 값으로 바꿔 놓고 쓰면 됩니다.

62.5% 트릭이 남긴 함정

font-size: 62.5%는 16 × 0.625 = 10px이라, 1.6rem = 16px처럼 암산이 쉬워집니다. 오래된 코드베이스에서 흔히 보입니다.

문제는 이게 루트 크기를 줄인다는 점입니다. rem을 쓰지 않은 요소, 폼 컨트롤의 기본 크기, 서드파티 위젯은 여전히 16px 기준으로 그려집니다. 그리고 아래에서 설명할 미디어쿼리는 이 설정을 아예 무시합니다. 암산 편의를 얻는 대신 “여기서는 1rem이 10px”이라는 규칙을 팀 전체가 기억해야 합니다.

미디어쿼리의 rem은 다르게 동작한다

이 부분은 알고 나면 당연하지만, 모르면 한참 헤맵니다.

html { font-size: 62.5%; }        /* 1rem = 10px 로 만들었다 */

.card { padding: 2rem; }          /* → 20px  (루트를 따른다) */

@media (min-width: 48rem) { }     /* → 768px (루트를 무시한다!) */

미디어쿼리는 <html>에 어떤 스타일이 적용되기 전에 평가됩니다. 아직 루트 font-size가 정해지지 않은 시점이라, 명세는 미디어쿼리 안의 rem을 브라우저 초기 font-size(대개 16px)로 해석하도록 정했습니다. 62.5%를 쓰든 말든 48rem은 768px입니다.

그래서 62.5% 프로젝트에서 “480px에서 레이아웃이 바뀌게 하려고 48rem이라고 썼는데 왜 768px에서 바뀌지?”라는 버그가 나옵니다. 미디어쿼리 값을 변환할 때는 base를 항상 16으로 두고 계산하세요.

어디에 rem을 쓰고 어디에 px을 쓸까

전부 rem으로 바꾸는 게 목표가 아닙니다. 기준은 하나입니다 — 글자가 커질 때 이것도 같이 커져야 하는가?

  • rem이 맞는 것: font-size, 글자를 감싸는 padding·margin, 텍스트 컨테이너의 max-width, line-height를 px로 준 경우. 글자가 20px이 됐는데 버튼 높이가 그대로면 글자가 버튼을 뚫고 나옵니다.
  • px이 맞는 것: border, box-shadow의 확산 거리, 1px 구분선, 아이콘 크기를 픽셀 단위로 맞춰야 하는 경우. 테두리가 사용자 설정에 따라 1.25px이 되면 브라우저마다 다르게 반올림해서 어떤 화면에서는 사라집니다.
  • 둘 다 아닌 것: 뷰포트 기준으로 움직여야 하는 값은 vw, vh, 또는 clamp()가 맞습니다. 유동적인 타이포그래피는 clamp(1rem, 2.5vw, 1.5rem)처럼 rem과 vw를 섞습니다.

요약하면 rem은 “더 좋은 단위”가 아니라 사용자 설정에 연결된 단위입니다. 연결되면 안 되는 값까지 rem으로 바꾸면 오히려 깨집니다.

나누어떨어지지 않는 값

13px을 16으로 나누면 0.8125rem으로 딱 떨어집니다. 16의 배수가 아니어도 2의 거듭제곱으로 나누는 것이라 대부분 4자리 안에서 끝납니다.

문제가 되는 건 base가 16이 아닐 때입니다. base 14에서 10px은 0.714285...rem이 됩니다. 이때 반올림한 값을 그대로 쓰면 됩니다. 0.7143rem은 10.0002px이고, 이 차이는 어떤 화면에서도 같은 픽셀로 반올림됩니다. 소수점을 더 늘려도 얻는 게 없습니다.

오히려 이런 값이 자주 나온다면 그건 계산의 문제가 아니라 디자인 시스템에 스케일이 없다는 신호입니다. 간격을 4의 배수(4·8·12·16·24)로 정해 두면 어떤 base에서도 값이 깔끔하게 떨어지고, 애초에 변환할 일 자체가 줄어듭니다.

자주 묻는 질문

1rem은 항상 16px인가요?
아닙니다. 1rem은 <html> 요소의 font-size이고, 16px은 그 브라우저 기본값일 뿐입니다. 프로젝트에서 html { font-size: 62.5% }처럼 루트 크기를 바꿨다면 1rem은 10px이 됩니다. 그리고 사용자가 브라우저 글꼴 크기 설정을 '크게'로 바꾸면 개발자가 아무것도 하지 않아도 1rem이 20px이 될 수 있습니다. 이 변환기의 base 값을 프로젝트에 맞게 바꿔서 쓰세요.
rem과 em은 뭐가 다른가요?
기준이 다릅니다. rem은 항상 루트(<html>)를 보고, em은 자기 자신 또는 부모의 font-size를 봅니다. 그래서 em은 중첩되면 곱해집니다 — 0.9em인 요소 안에 0.9em인 요소를 넣으면 0.81em이 되고, 이게 몇 단계 쌓이면 글자가 눈에 띄게 작아집니다. 기준이 하나로 고정되는 rem이 예측하기 쉬운 이유입니다.
62.5% 트릭을 써도 되나요?
html { font-size: 62.5% }로 1rem을 10px로 만들면 암산이 쉬워집니다(1.6rem = 16px). 다만 루트 크기를 줄이는 것이므로 rem을 쓰지 않은 다른 요소들과 어긋날 수 있고, 팀에 새로 온 사람은 1rem이 16px이라고 가정합니다. 요즘은 이 변환기 같은 도구나 CSS clamp()가 있어 암산 편의를 위해 감수할 이유가 크지 않습니다.
border나 그림자에도 rem을 써야 하나요?
보통은 px이 낫습니다. 1px 테두리는 글자가 커진다고 같이 두꺼워질 이유가 없고, rem으로 두면 사용자 설정에 따라 0.5px 같은 값이 되어 브라우저마다 다르게 렌더됩니다. rem은 '글자와 함께 커져야 하는 것'(폰트 크기, 여백, 컨테이너 폭)에 쓰고, '물리적으로 얇아야 하는 것'(테두리, 헤어라인)에는 px을 쓰는 편이 안전합니다.
미디어쿼리에는 어떤 단위를 쓰나요?
미디어쿼리 안의 rem은 루트 font-size를 따르지 않고 항상 브라우저 초기값(대개 16px)을 씁니다. 명세가 그렇게 정해져 있습니다. 그래서 62.5% 트릭을 쓰는 프로젝트에서 @media (min-width: 48rem)은 480px이 아니라 768px입니다. 여기서 어긋나는 버그가 자주 나옵니다.