CSS 단위 완벽 가이드 - px, rem, em, vh, vw 등
CSS 단위 완벽 가이드 - px, rem, em, vh, vw 등
CSS의 모든 단위를 체계적으로 설명하는 완벽 가이드입니다. px, rem, em, vh, vw, %, ch, vmin, vmax, dvh 등 절대 단위와 상대 단위의 차이, 각각의 사용 시기, 반응형 디자인 적용법, 실용적 예제를 포함합니다.
CSS 단위 완벽 가이드 - px, rem, em, vh, vw 등
CSS에서 올바른 단위를 선택하는 것은 반응형 디자인, 접근성, 유지보수성에 직접적인 영향을 미칩니다. 2026년 현재 CSS에는 수십 가지의 단위가 존재하며, 각각 고유한 특성과 적합한 사용 사례가 있습니다. 이 가이드에서는 CSS의 모든 주요 단위를 체계적으로 분류하고, 각 단위의 동작 원리, 적절한 사용 시기, 그리고 실무에서의 활용 방법을 상세히 설명합니다.
CSS 단위의 분류
CSS 단위는 크게 절대 단위와 상대 단위로 나뉩니다.
| 분류 | 단위 | 기준 |
|---|---|---|
| 절대 단위 | px, cm, mm, in, pt, pc | 고정된 물리적 크기 |
| 글꼴 상대 단위 | em, rem, ch, ex, cap, ic, lh, rlh | 글꼴 크기 기준 |
| 뷰포트 상대 단위 | vw, vh, vmin, vmax, svh, lvh, dvh | 뷰포트 크기 기준 |
| 컨테이너 상대 단위 | cqw, cqh, cqi, cqb | 컨테이너 크기 기준 |
| 백분율 | % | 부모 요소 기준 |
절대 단위
px (픽셀)
px는 CSS에서 가장 기본적이고 널리 사용되는 절대 단위입니다. 그러나 CSS의 px는 물리적 화면 픽셀과 반드시 1:1로 대응하지는 않습니다. CSS px는 "참조 픽셀"로, 96dpi 해상도에서의 1/96인치에 해당하는 각도 크기를 기준으로 합니다.
/* px 사용이 적절한 경우 */
.border {
border: 1px solid #e0e0e0; /* 테두리 */
}
.shadow {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); /* 그림자 */
}
.icon {
width: 24px; /* 아이콘 크기 */
height: 24px;
}
.divider {
height: 1px; /* 구분선 */
background: #ddd;
}
px 사용 권장 사례:
- 테두리(border) 두께
- 그림자(box-shadow) 오프셋
- 아이콘 고정 크기
- 1px 구분선
- 미디어 쿼리 브레이크포인트
px 사용을 피해야 하는 경우:
- 글꼴 크기 (접근성 문제)
- 여백과 패딩 (반응형 어려움)
- 너비와 높이 (유연성 부족)
기타 절대 단위
| 단위 | 설명 | px 환산 | 사용 상황 |
|---|---|---|---|
| cm | 센티미터 | 1cm = 37.8px | 인쇄용 스타일 |
| mm | 밀리미터 | 1mm = 3.78px | 인쇄용 스타일 |
| in | 인치 | 1in = 96px | 인쇄용 스타일 |
| pt | 포인트 | 1pt = 1.33px | 인쇄용 글꼴 크기 |
| pc | 파이카 | 1pc = 16px | 인쇄용 레이아웃 |
/* 인쇄 스타일시트에서의 절대 단위 사용 */
@media print {
body {
font-size: 12pt;
line-height: 1.5;
}
.page {
width: 210mm; /* A4 너비 */
height: 297mm; /* A4 높이 */
margin: 2cm;
}
h1 { font-size: 18pt; }
h2 { font-size: 14pt; }
}
글꼴 상대 단위
rem (Root EM)
rem은 루트 요소(<html>)의 글꼴 크기를 기준으로 하는 단위입니다. 일관성과 예측 가능성이 뛰어나 2026년 현재 가장 권장되는 단위 중 하나입니다.
/* 기본 설정 */
html {
font-size: 16px; /* 브라우저 기본값 */
/* 또는 font-size: 100%; 으로 사용자 설정 존중 */
}
/* rem 사용 예시 */
body {
font-size: 1rem; /* 16px */
line-height: 1.5; /* 24px (1rem * 1.5) */
}
h1 {
font-size: 2.5rem; /* 40px */
margin-bottom: 1rem; /* 16px */
}
h2 {
font-size: 2rem; /* 32px */
margin-bottom: 0.75rem; /* 12px */
}
h3 {
font-size: 1.5rem; /* 24px */
margin-bottom: 0.5rem; /* 8px */
}
p {
font-size: 1rem; /* 16px */
margin-bottom: 1rem; /* 16px */
}
.container {
max-width: 75rem; /* 1200px */
padding: 2rem; /* 32px */
margin: 0 auto;
}
.card {
padding: 1.5rem; /* 24px */
border-radius: 0.5rem; /* 8px */
margin-bottom: 1.5rem; /* 24px */
}
.button {
padding: 0.75rem 1.5rem; /* 12px 24px */
font-size: 1rem; /* 16px */
border-radius: 0.375rem; /* 6px */
}
rem의 장점:
- 일관된 크기 체계 유지
- 사용자의 브라우저 글꼴 크기 설정 존중 (접근성)
- 전체 사이트의 크기를 한 곳에서 조절 가능
- 중첩에 의한 크기 변화 없음
em (EM)
em은 현재 요소의 글꼴 크기를 기준으로 하는 단위입니다. 글꼴 크기(font-size)에 사용되면 부모 요소의 글꼴 크기를 기준으로 합니다.
/* em의 동작 방식 */
.parent {
font-size: 20px;
}
.child {
font-size: 0.8em; /* 20px * 0.8 = 16px */
padding: 1em; /* 16px (현재 요소의 font-size 기준) */
margin-bottom: 1.5em; /* 24px */
}
.grandchild {
font-size: 0.8em; /* 16px * 0.8 = 12.8px (중첩 효과!) */
}
em의 중첩 문제:
/* 문제: em이 중첩되면 크기가 누적됨 */
ul { font-size: 0.9em; }
/* 중첩된 목록 */
/* <ul> → 0.9em = 14.4px (16px * 0.9) */
/* <ul> → 0.9em = 12.96px (14.4px * 0.9) */
/* <ul> → 0.9em = 11.66px (12.96px * 0.9) */
/* <ul> → 0.9em = 10.5px (점점 작아짐!) */
/* 해결: rem 사용 */
ul { font-size: 0.9rem; }
/* 모든 수준에서 동일하게 14.4px */
em이 적합한 경우:
/* 컴포넌트 내부에서 비례적 크기를 원할 때 */
.button {
font-size: 1rem;
padding: 0.5em 1em; /* 글꼴 크기에 비례하는 패딩 */
border-radius: 0.25em; /* 글꼴 크기에 비례하는 둥글기 */
}
.button--small {
font-size: 0.875rem;
/* padding과 border-radius가 자동으로 비례 축소 */
}
.button--large {
font-size: 1.25rem;
/* padding과 border-radius가 자동으로 비례 확대 */
}
/* 아이콘이 텍스트와 비례해야 할 때 */
.icon-text {
display: inline-flex;
align-items: center;
gap: 0.25em;
}
.icon-text svg {
width: 1em; /* 텍스트 크기와 동일 */
height: 1em;
}
rem vs em - 언제 어떤 것을 사용할까?
| 속성 | 권장 단위 | 이유 |
|---|---|---|
| font-size | rem | 중첩 문제 방지, 일관성 |
| padding (컴포넌트 내) | em | 글꼴 크기에 비례하는 여백 |
| padding (레이아웃) | rem | 일관된 간격 |
| margin | rem | 일관된 간격 |
| width/max-width | rem 또는 % | 상황에 따라 |
| border-radius | em 또는 px | 컴포넌트 내 비례 또는 고정 |
| gap | rem | 일관된 간격 |
ch (Character Width)
ch는 현재 글꼴에서 문자 "0"의 너비를 기준으로 하는 단위입니다. 텍스트 콘텐츠의 최적 너비를 설정할 때 매우 유용합니다.
/* 가독성을 위한 최적 줄 길이 설정 */
.article {
max-width: 65ch; /* 한 줄에 약 65자 */
/* 서양 타이포그래피에서 권장하는 줄 길이는 45-75자 */
}
/* 입력 필드 너비를 예상 문자 수에 맞추기 */
input[type="tel"] {
width: 15ch; /* 전화번호 길이 */
}
input[type="text"].zip-code {
width: 7ch; /* 우편번호 길이 */
}
input[type="text"].year {
width: 6ch; /* 연도 (2026) */
}
ex, cap, ic, lh, rlh
| 단위 | 기준 | 설명 |
|---|---|---|
| ex | 현재 글꼴의 x-height | 소문자 'x'의 높이 |
| cap | 현재 글꼴의 Cap Height | 대문자의 높이 |
| ic | 현재 글꼴의 ideographic character | CJK(한중일) 문자 '水'의 너비 |
| lh | 현재 요소의 line-height | 줄 높이 |
| rlh | 루트 요소의 line-height | 루트 줄 높이 |
/* ic 단위 - 한글 텍스트에 유용 */
.korean-text {
max-width: 35ic; /* 한글 약 35자 너비 */
}
/* lh 단위 - 줄 높이 기반 간격 */
.paragraph {
margin-bottom: 1lh; /* 정확히 1줄 높이만큼의 여백 */
}
.drop-cap {
float: left;
font-size: 3lh; /* 3줄 높이의 드롭캡 */
line-height: 1;
}
뷰포트 상대 단위
vw와 vh
vw(viewport width)와 vh(viewport height)는 뷰포트의 크기를 기준으로 하는 단위입니다.
/* 1vw = 뷰포트 너비의 1% */
/* 1vh = 뷰포트 높이의 1% */
/* 전체 화면 히어로 섹션 */
.hero {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
/* 반응형 타이포그래피 */
.hero-title {
font-size: 5vw; /* 뷰포트 너비에 비례 */
}
/* 문제: 모바일에서 너무 작아지거나 데스크톱에서 너무 커질 수 있음 */
/* 해결: clamp() 함수 사용 */
.hero-title {
font-size: clamp(2rem, 5vw, 4rem);
/* 최소 2rem, 기본 5vw, 최대 4rem */
}
vmin과 vmax
/* vmin = vw와 vh 중 작은 값 */
/* vmax = vw와 vh 중 큰 값 */
/* 가로/세로 모드에 관계없이 일관된 크기 */
.square-element {
width: 50vmin; /* 작은 쪽 기준 50% */
height: 50vmin;
/* 세로 모드(portrait)에서는 너비 기준 */
/* 가로 모드(landscape)에서는 높이 기준 */
}
/* 정사각형 카드 */
.profile-card {
width: 80vmin;
height: 80vmin;
max-width: 400px;
max-height: 400px;
}
새로운 뷰포트 단위: svh, lvh, dvh
모바일 브라우저에서 주소창의 표시/숨김에 따라 뷰포트 높이가 변하는 문제를 해결하기 위해 도입된 단위들입니다.
/*
svh (Small Viewport Height): 주소창이 표시된 상태의 뷰포트 높이
lvh (Large Viewport Height): 주소창이 숨겨진 상태의 뷰포트 높이
dvh (Dynamic Viewport Height): 현재 실제 뷰포트 높이 (동적 변화)
*/
/* 모바일에서 100vh 문제 해결 */
.fullscreen-section {
/* 기존: 모바일에서 콘텐츠가 잘릴 수 있음 */
/* height: 100vh; */
/* 권장: 동적 뷰포트 높이 사용 */
height: 100dvh;
/* 폴백 */
height: 100vh; /* dvh 미지원 브라우저용 */
height: 100dvh;
}
/* 최소 높이에 svh 사용 (안전한 최소 크기) */
.hero-section {
min-height: 100svh; /* 주소창이 보여도 최소한 전체 화면 */
}
/* 사이드바에 lvh 사용 (최대 크기) */
.sidebar {
height: 100lvh; /* 최대 뷰포트 높이에 맞춤 */
position: fixed;
}
뷰포트 단위 비교표
| 단위 | 설명 | 모바일 주소창 | 사용 사례 |
|---|---|---|---|
| vh | 기존 뷰포트 높이 | 일관성 없음 | 데스크톱 전용 |
| svh | Small viewport height | 표시 상태 기준 | 안전한 최소 크기 |
| lvh | Large viewport height | 숨김 상태 기준 | 고정 요소 |
| dvh | Dynamic viewport height | 실시간 반영 | 전체 화면 섹션 |
| vw | 뷰포트 너비 | 영향 없음 | 가로 크기 |
| svw/lvw/dvw | Small/Large/Dynamic 너비 | 대부분 동일 | 특수 상황 |
| vi | 인라인 축 뷰포트 | 쓰기 방향에 따라 | 국제화 |
| vb | 블록 축 뷰포트 | 쓰기 방향에 따라 | 국제화 |
컨테이너 상대 단위
2026년에 Container Queries와 함께 도입된 컨테이너 상대 단위는 컴포넌트 기반 반응형 디자인의 핵심입니다.
/* 컨테이너 쿼리 단위 */
.card-container {
container-type: inline-size;
container-name: card;
}
.card-title {
/* cqw: 컨테이너 너비의 1% */
font-size: clamp(1rem, 4cqw, 2rem);
}
.card-body {
/* cqi: 컨테이너 인라인 크기의 1% */
padding: 2cqi;
}
@container card (min-width: 400px) {
.card {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 2cqi;
}
}
| 단위 | 설명 |
|---|---|
| cqw | 쿼리 컨테이너 너비의 1% |
| cqh | 쿼리 컨테이너 높이의 1% |
| cqi | 쿼리 컨테이너 인라인 크기의 1% |
| cqb | 쿼리 컨테이너 블록 크기의 1% |
| cqmin | cqi와 cqb 중 작은 값 |
| cqmax | cqi와 cqb 중 큰 값 |
백분율 (%)
백분율은 부모 요소의 해당 속성을 기준으로 합니다. 단, 어떤 속성에 사용되느냐에 따라 기준이 달라집니다.
/* 백분율의 기준 */
/* width: 부모의 width 기준 */
.child {
width: 50%; /* 부모 너비의 50% */
}
/* height: 부모의 height 기준 (부모에 높이가 지정되어야 함) */
.child {
height: 50%; /* 부모 높이의 50% */
}
/* padding, margin: 부모의 WIDTH 기준 (상하 패딩/마진도!) */
.child {
padding: 10%; /* 상하좌우 모두 부모 너비의 10% */
/* padding-top: 10%도 부모 너비의 10% (높이가 아님!) */
}
/* font-size: 부모의 font-size 기준 */
.child {
font-size: 120%; /* 부모 글꼴 크기의 120% */
}
/* line-height: 요소 자신의 font-size 기준 */
.child {
line-height: 150%; /* 자신의 font-size의 150% */
}
/* transform: translate: 요소 자신의 크기 기준 */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* 자기 자신 너비의 50%, 높이의 50%만큼 이동 */
}
반응형 종횡비 유지 (padding 트릭)
/* 16:9 비율 유지 (옛날 방식) */
.video-wrapper {
position: relative;
width: 100%;
padding-top: 56.25%; /* 9/16 * 100 = 56.25% */
}
.video-wrapper iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
/* 현대적 방법: aspect-ratio 속성 사용 */
.video-wrapper {
width: 100%;
aspect-ratio: 16 / 9;
}
반응형 디자인에서의 단위 활용
clamp() 함수
clamp(최소값, 선호값, 최대값)은 반응형 디자인에서 가장 강력한 CSS 함수입니다.
/* 반응형 타이포그래피 */
.heading {
font-size: clamp(1.5rem, 2vw + 1rem, 3rem);
/* 최소 1.5rem (24px) */
/* 선호 2vw + 1rem (뷰포트에 비례) */
/* 최대 3rem (48px) */
}
/* 반응형 여백 */
.section {
padding: clamp(1rem, 5vw, 4rem);
/* 작은 화면: 1rem */
/* 중간 화면: 5vw */
/* 큰 화면: 4rem */
}
/* 반응형 그리드 간격 */
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
gap: clamp(1rem, 2vw, 2rem);
}
/* 반응형 컨테이너 */
.container {
width: min(90%, 75rem);
margin-inline: auto;
padding-inline: clamp(1rem, 3vw, 2rem);
}
완전한 반응형 타이포그래피 시스템
:root {
/* 유동적 타입 스케일 */
--step--2: clamp(0.6944rem, 0.6597rem + 0.1736vw, 0.8rem);
--step--1: clamp(0.8333rem, 0.7754rem + 0.2899vw, 1rem);
--step-0: clamp(1rem, 0.9091rem + 0.4545vw, 1.25rem);
--step-1: clamp(1.2rem, 1.0636rem + 0.6818vw, 1.5625rem);
--step-2: clamp(1.44rem, 1.2418rem + 0.9909vw, 1.9531rem);
--step-3: clamp(1.728rem, 1.4473rem + 1.4036vw, 2.4414rem);
--step-4: clamp(2.0736rem, 1.6845rem + 1.9455vw, 3.0518rem);
--step-5: clamp(2.4883rem, 1.9582rem + 2.6505vw, 3.8147rem);
/* 유동적 간격 스케일 */
--space-3xs: clamp(0.25rem, 0.2045rem + 0.2273vw, 0.375rem);
--space-2xs: clamp(0.5rem, 0.4545rem + 0.2273vw, 0.625rem);
--space-xs: clamp(0.75rem, 0.6591rem + 0.4545vw, 1rem);
--space-s: clamp(1rem, 0.9091rem + 0.4545vw, 1.25rem);
--space-m: clamp(1.5rem, 1.3636rem + 0.6818vw, 1.875rem);
--space-l: clamp(2rem, 1.8182rem + 0.9091vw, 2.5rem);
--space-xl: clamp(3rem, 2.7273rem + 1.3636vw, 3.75rem);
--space-2xl: clamp(4rem, 3.6364rem + 1.8182vw, 5rem);
--space-3xl: clamp(6rem, 5.4545rem + 2.7273vw, 7.5rem);
}
/* 사용 */
body {
font-size: var(--step-0);
line-height: 1.6;
}
h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-3); }
h4 { font-size: var(--step-2); }
h5 { font-size: var(--step-1); }
.section {
padding-block: var(--space-xl);
}
.stack > * + * {
margin-top: var(--space-m);
}
미디어 쿼리와 단위
/* 미디어 쿼리에서는 em 사용 권장 */
/* em을 사용하면 사용자의 글꼴 크기 설정을 존중 */
/* 권장 */
@media (min-width: 48em) { /* 768px at 16px base */
.container {
padding: 2rem;
}
}
@media (min-width: 64em) { /* 1024px at 16px base */
.container {
padding: 3rem;
}
}
/* 비권장 (사용자의 글꼴 크기 설정 무시) */
@media (min-width: 768px) {
/* ... */
}
단위 사용 모범 사례
접근성을 고려한 단위 선택
/* 접근성 최우선 원칙 */
/* 1. 글꼴 크기: 항상 rem 사용 */
html {
/* px 대신 % 사용하여 사용자 설정 존중 */
font-size: 100%; /* = 16px (기본값) */
}
/* 절대 font-size: px 사용하지 마세요! */
/* BAD: font-size: 14px; */
/* GOOD: font-size: 0.875rem; */
/* 2. 줄 높이: 단위 없는 숫자 사용 */
p {
line-height: 1.6; /* 단위 없음 - 글꼴 크기에 비례 */
/* BAD: line-height: 24px; */
/* BAD: line-height: 1.5em; (상속 시 문제) */
}
/* 3. 최소 터치 타겟 크기 */
button, a {
min-height: 44px; /* WCAG 최소 터치 타겟 */
min-width: 44px;
/* 또는 */
min-height: 2.75rem;
padding: 0.5rem 1rem;
}
/* 4. 포커스 표시 */
:focus-visible {
outline: 3px solid #4A90D9;
outline-offset: 2px;
/* 포커스 아웃라인은 px로 일관된 두께 유지 */
}
속성별 권장 단위 총정리
| CSS 속성 | 권장 단위 | 예시 | 이유 |
|---|---|---|---|
| font-size | rem | 1.125rem | 접근성, 일관성 |
| line-height | 단위 없음 | 1.6 | 상속 시 비례 유지 |
| padding (컴포넌트) | em | 0.5em 1em | 글꼴에 비례 |
| padding (레이아웃) | rem | 2rem | 일관된 간격 |
| margin | rem | 1.5rem | 일관된 간격 |
| width | %, rem, vw | min(90%, 75rem) | 반응형 |
| height | auto, dvh, rem | 100dvh | 콘텐츠에 맞춤 |
| max-width | rem, ch | 65ch | 가독성 |
| border | px | 1px solid | 고정 크기 |
| border-radius | px, em, % | 0.5rem | 상황에 따라 |
| box-shadow | px | 0 2px 4px | 고정 크기 |
| gap | rem, clamp() | clamp(1rem, 2vw, 2rem) | 반응형 간격 |
| 미디어 쿼리 | em | 48em | 접근성 |
실전 레이아웃 예제
/* 완전한 반응형 레이아웃 시스템 */
/* 기본 설정 */
html {
font-size: 100%;
}
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
}
/* 컨테이너 */
.container {
width: min(90%, 75rem);
margin-inline: auto;
}
/* 그리드 시스템 */
.grid {
display: grid;
gap: clamp(1rem, 2vw, 2rem);
}
.grid--2-col {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 25rem), 1fr));
}
.grid--3-col {
grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr));
}
/* 카드 컴포넌트 */
.card {
container-type: inline-size;
container-name: card;
padding: clamp(1rem, 3cqi, 2rem);
border-radius: 0.5rem;
border: 1px solid #e5e7eb;
}
.card__title {
font-size: clamp(1.125rem, 3cqi, 1.5rem);
margin-bottom: 0.5em;
}
.card__text {
font-size: var(--step-0);
line-height: 1.6;
max-width: 65ch;
}
/* 히어로 섹션 */
.hero {
min-height: 100svh;
padding: var(--space-xl) var(--space-m);
display: grid;
place-items: center;
}
.hero__title {
font-size: clamp(2rem, 5vw + 1rem, 5rem);
line-height: 1.1;
}
.hero__subtitle {
font-size: clamp(1rem, 2vw, 1.5rem);
margin-top: var(--space-s);
max-width: 50ch;
}
관련 도구 활용
CSS 작업을 할 때 유용한 온라인 도구들입니다:
결론
CSS 단위의 올바른 선택은 반응형 디자인, 접근성, 유지보수성의 토대입니다. 2026년 기준으로 핵심 원칙을 정리하면:
- 글꼴 크기에는 rem을 사용하세요 - 접근성과 일관성을 보장합니다
- 컴포넌트 내부 간격에는 em을 활용하세요 - 글꼴 크기에 비례하는 디자인을 만듭니다
- 뷰포트 단위는 dvh/svh/lvh를 사용하세요 - 모바일 주소창 문제를 해결합니다
- clamp() 함수를 적극 활용하세요 - 미디어 쿼리 없이 유동적인 크기를 구현합니다
- 테두리와 그림자에는 px를 사용하세요 - 시각적 일관성을 유지합니다
- line-height는 단위 없이 사용하세요 - 상속 시 올바르게 비례합니다
- 컨테이너 쿼리 단위(cqi 등)를 활용하세요 - 컴포넌트 기반 반응형 디자인을 구현합니다
각 단위의 특성을 이해하고 적절한 곳에 사용하면, 다양한 기기와 사용자 환경에서도 일관되고 접근성 높은 웹 경험을 제공할 수 있습니다. 이 가이드에서 소개한 원칙과 예제를 참고하여 프로젝트에 적용해 보세요.