변환 공식
99%의 경우 이 공식 하나로 끝납니다.
rem = px / 16
px = rem × 16
16은 브라우저의 기본 루트 폰트 크기입니다. 모든 브라우저가 html { font-size: 16px }로 출발하고, 1rem은 그 루트 크기와 같습니다. 그래서 16px은 1rem, 24px은 1.5rem, 8px은 0.5rem이 됩니다.
전체 환산표
| 픽셀 | REM | 흔한 용도 |
|---|---|---|
| 1px | 0.0625rem | 얇은 테두리 (보통 px로 유지) |
| 2px | 0.125rem | 테두리, 아웃라인 |
| 4px | 0.25rem | 좁은 간격 |
| 8px | 0.5rem | 기본 작은 간격 단위 |
| 12px | 0.75rem | 작은 텍스트, 배지 |
| 14px | 0.875rem | 보조 본문 |
| 16px | 1rem | 기본 본문 (기준선) |
| 18px | 1.125rem | 큰 본문, 리드 문단 |
| 20px | 1.25rem | 소제목 |
| 24px | 1.5rem | H3, 넉넉한 패딩 |
| 32px | 2rem | H2, 섹션 간격 |
| 40px | 2.5rem | 모바일 H1 |
| 48px | 3rem | 데스크톱 H1 |
| 56px | 3.5rem | 히어로 헤드라인 |
| 64px | 4rem | 큰 히어로, 디스플레이 |
| 96px | 6rem | 초대형 디스플레이 |
rem이 존재하는 이유: 접근성
타이포그래피에 px 대신 rem을 쓰는 진짜 이유는 하나입니다. 사용자가 브라우저 기본 폰트 크기를 바꿀 수 있기 때문입니다. Chrome이라면 설정 → 모양 → 글꼴 크기에서 "크게"나 "매우 크게"로 바꿀 수 있고, 그러면 루트 폰트 크기가 16px에서 20px, 24px, 심지어 32px이 됩니다.
rem 기반 타이포그래피라면 전체가 비례해서 커집니다. 시력이 약한 사용자가 실제로 더 큰 화면을 보게 됩니다. px 기반이라면 그 설정이 아무 일도 하지 않고, 그 사람은 편하게 읽을 수 없는 사이트를 만나게 됩니다.
이것은 WCAG 1.4.4(텍스트 크기 조정)의 요구사항이기도 합니다. 콘텐츠나 기능의 손실 없이 텍스트를 200%까지 확대할 수 있어야 합니다. rem이면 자동으로 충족되고, px 전용 CSS는 대개 위반합니다.
rem과 em의 결정적 차이
둘 다 상대 단위지만 기준이 다릅니다.
- rem은 루트 요소(
<html>) 기준입니다. 페이지 어디에서든1rem은 항상 같은 크기입니다. - em은 현재 요소의 폰트 크기 기준입니다. 24px 제목 안의
1em은 24px이고, 12px 캡션 안에서는 12px입니다.
이 차이가 중요한 이유는 em이 누적되기 때문입니다. font-size: 1.2em을 세 번 중첩하면 가장 안쪽 텍스트는 1.2배가 아니라 1.728배가 됩니다. 중첩 메뉴와 중첩 목록이 깨지는 전형적인 버그입니다.
어떤 단위를 언제 쓰나
| 용도 | 권장 단위 | 이유 |
|---|---|---|
| 폰트 크기 | rem | 접근성. 사용자 확대 설정을 존중합니다 |
| 패딩과 마진 | rem | 텍스트 크기에 비례해 함께 커집니다 |
| 컴포넌트 내부 간격 | em | 그 컴포넌트 자체 폰트 크기를 따라갑니다 |
| 테두리 (1~2px) | px | rem 반올림으로 선이 사라질 수 있습니다 |
| 박스 섀도 | px | 확대되면 어색해집니다 |
| 미디어 쿼리 | em | 브라우저 간 동작이 가장 일관적입니다 |
62.5% 트릭과 그 문제점
html { font-size: 62.5% }로 루트를 10px로 만들어 계산을 쉽게 하는 방법이 널리 퍼져 있습니다. 그러면 1.6rem이 16px, 2.4rem이 24px이 되어 암산이 편해집니다.
문제는 이렇게 하면 기본 본문 크기를 10px로 떨어뜨린다는 점입니다. 모든 요소에 크기를 다시 지정하는 것을 잊으면 텍스트가 읽을 수 없게 작아집니다. 폰트 크기를 명시하지 않은 서드파티 위젯이나 삽입 콘텐츠도 함께 축소됩니다.
계산이 번거롭다면 트릭 대신 CSS 변수나 변환 도구를 쓰는 편이 안전합니다.
더 현대적인 대안: clamp()
고정된 rem 값 대신 뷰포트에 따라 부드럽게 변하는 크기를 쓸 수 있습니다.
h1 {
/* 최소 2rem, 최대 4rem, 그 사이는 뷰포트에 비례 */
font-size: clamp(2rem, 1.5rem + 2.5vw, 4rem);
}
중요한 점은 vw만 단독으로 쓰지 않는 것입니다. clamp(2rem, 5vw, 4rem)처럼 중간값이 순수 vw면 사용자가 확대해도 크기가 바뀌지 않아 WCAG 1.4.4를 위반합니다. 위 예시처럼 rem을 더해 두면 확대에도 반응합니다.
자주 묻는 질문
- 1rem은 항상 16px인가요?
- 기본값일 때만 그렇습니다. 사용자가 브라우저 폰트 크기를 바꾸거나
html에 다른font-size를 지정하면 달라집니다. 바로 그 유연함이 rem을 쓰는 이유입니다. - 테두리에 rem을 쓰면 왜 안 되나요?
- 1px은 0.0625rem인데, 브라우저 확대나 소수점 반올림에 따라 0으로 처리되어 선이 사라질 수 있습니다. 얇은 선은 px로 두는 편이 안전합니다.
- 미디어 쿼리에 px 대신 em을 쓰는 이유는?
- 미디어 쿼리의 em은 항상 브라우저 기본 폰트 크기를 기준으로 하며 루트 설정의 영향을 받지 않습니다. 그래서 사용자가 폰트를 키웠을 때 중단점도 함께 움직여 의도한 레이아웃이 유지됩니다.
- Tailwind를 쓰면 신경 쓸 필요가 없나요?
- Tailwind의 기본 스케일은 이미 rem 기반입니다.
text-base가 1rem,text-xl이 1.25rem입니다. 다만text-[14px]처럼 임의 값에 px를 넣는 순간 접근성 이점이 사라지므로, 임의 값에도 rem을 쓰세요.