Menu

CSS 단위 rem, em, px 차이: 퍼센트, vw, vh까지

rem은 루트 글자 크기, em은 현재 요소의 글자 크기를 기준으로 하고, px은 고정이며, %는 속성에 따라 달라요. 중첩 데모로 각 단위를 측정해 보고, em이 누적되는 이유, 언제 무엇을 쓸지, vw, vh, dvh의 동작 방식을 알아봐요.

이 페이지에는 실행 가능한 에디터가 있습니다 - 편집하고 실행하면 결과를 바로 볼 수 있습니다.

중첩 데모 하나로 보는 rem과 em

rem은 루트 글자 크기(<html> 요소, 기본 16px)를 기준으로 해요. em은 현재 글자 크기를 기준으로 하고, font-size에서는 부모의 글자 크기를 뜻해요. 같은 클래스를 세 번 중첩하면 차이가 드러나요.

출력된 크기는 브라우저가 계산한 값이에요. 각 1.25em은 부모에 곱해져서 20px, 25px, 31.25px이 돼요. 각 1.25rem은 루트만 봐서 20px, 20px, 20px이에요. 이 누적 때문에 중첩된 목록과 메뉴에서 em 글자 크기가 통제 불능이 되고, 대부분의 사이트가 글자 크기를 rem으로 정해요.

각 단위의 기준

단위기준기본 1단위
px없음(CSS 픽셀)1px
rem루트 요소(html)의 글자 크기16px
em요소의 글자 크기. font-size 자체에서는 부모의 글자 크기최상위에서 16px
%속성에 따라 달라요(아래 참고)
vw / vh뷰포트 너비 / 높이의 1%
dvh, svh, lvh동적, 작은, 큰 뷰포트 높이의 1%
vmin / vmax뷰포트의 짧은 / 긴 변의 1%
ch현재 글꼴의 "0" 너비약 0.5em
ex현재 글꼴의 x-height약 0.5em

CSS 픽셀은 기기 픽셀이 아니에요. 3배율 화면의 휴대폰에서 1px은 기기 픽셀 3개 너비예요. 화면이 달라도 시각적 크기가 대략 같게 유지되고, 그래서 테두리와 그림자에는 여전히 px이 괜찮아요.

텍스트에 맞춰 커지는 간격에는 em

em은 글자 크기에만 쓰는 게 아니에요. padding, margin, width, border-radius에서는 "이 요소의 글자 크기의 몇 배"라는 뜻이에요. 그래서 버튼 클래스 하나가 어떤 크기에서도 동작해요.

각 버튼의 padding은 세로로 글자 크기의 절반, 가로로 글자 크기 하나라서 세 버튼이 크기만 다른 같은 버튼처럼 보여요. px padding이라면 크기마다 padding 규칙을 따로 써야 해요.

버튼은 기본적으로 페이지의 글자 크기를 상속받지 않는다는 점에 주의하세요(브라우저가 폼 컨트롤에 자체 크기를 줘요). 그래서 여기서 가운데 버튼은 Chrome에서 16px이 아니라 13.33px이에요. 버튼과 입력 요소가 페이지와 맞게 하려면 font: inherit를 추가하세요.

퍼센트: 속성에 따라 달라요

%에는 하나의 뜻이 없어요. 속성마다 무엇의 퍼센트인지 정해져 있어요.

속성%의 기준
width, max-width, left, right부모(포함 블록)의 너비
height, top, bottom부모의 높이, 부모에 높이가 지정된 경우에만
padding, margin (네 방향 모두)부모의 너비
font-size부모의 글자 크기(150% = 1.5em)
line-height요소 자신의 글자 크기
transform: translate()요소 자신의 크기

width: 50%는 부모의 절반인 200px이에요. padding-top: 5%는 20px이에요. 부모 높이가 아니라 너비의 5%예요. 그리고 height: 50%는 아무 일도 하지 않아요. 부모에 높이가 지정되지 않아서 자식은 텍스트와 그 padding만큼만 높아요. width와 height 페이지에서 이 규칙을 자세히 다뤄요.

vw, vh와 모바일 주소창

1vw는 뷰포트 너비의 1%, 1vh는 높이의 1%예요. 전체 화면 섹션과 유동적인 크기(흔히 clamp() 안에서)에 유용해요. 휴대폰에서 vh에는 함정이 있어요. 스크롤할 때 브라우저 주소창이 들어왔다 나갔다 하는데, 100vh는 주소창이 없을 때의 높이라서 주소창이 보이면 height: 100vh 히어로의 아래가 잘려요. 새 단위가 이걸 해결해요.

단위쓰는 높이
100vh대부분의 모바일 브라우저에서 큰 뷰포트(바가 숨겨짐)
100svh작은 뷰포트(바가 보임): 항상 들어가요
100lvh명시적으로 큰 뷰포트
100dvh동적 뷰포트: 바가 움직이면 바뀌어요
.hero {
  min-height: 100vh;  /* fallback for older browsers */
  min-height: 100svh; /* fits the screen even with the address bar visible */
}

vw에도 함정이 있어요. 세로 스크롤바가 공간을 차지할 때(Windows처럼) 100vw는 스크롤바 너비를 포함해서, width: 100vw가 페이지보다 넓어져 가로 스크롤바가 생길 수 있어요. "부모의 전체 너비"에는 width: 100%를 쓰세요.

읽기 좋은 줄 길이에는 ch

ch는 "0" 문자의 너비라서, max-width: 65ch는 글자 크기와 상관없이 문단을 줄당 약 65자로 제한해요. 읽기 편한 길이예요.

어떤 단위를 쓸까

용도쓸 것이유
글자 크기rem어디서나 일관되고, 독자의 글자 크기 설정을 존중해요
컴포넌트의 padding과 간격rem 또는 em컴포넌트 자신의 텍스트와 함께 커져야 하면 em
테두리, 가는 선, 그림자px글자 크기와 상관없이 가늘게 유지돼야 해요
레이아웃 너비%, fr, rem이나 ch로 쓴 max-width컨테이너를 따르고, 줄 길이를 제한해요
전체 화면 섹션svh / dvh(vh 대체값과 함께)모바일 주소창을 처리해요
유동적인 글자rem과 vw를 섞은 clamp()한계 안에서 화면과 함께 커져요

rem은 독자를 존중하고 px은 그렇지 않은 이유

브라우저에는 기본 글자 크기 설정이 있고, 더 큰 글자가 필요한 사람들이 써요. 이 설정은 루트 글자 크기를 바꿔서 rem과 em으로 된 모든 것이 함께 커져요. font-size: 14px는 독자가 무엇을 골랐든 14px로 남아요. 브라우저 확대는 px도 키우지만, 많은 독자가 기대는 건 글자 크기 설정이에요. 글자 크기를 rem으로 정하는 주된 이유예요.

어떤 사이트는 1rem이 10px이 되어 계산이 쉽도록 html { font-size: 62.5%; }를 지정해요. 여전히 독자의 설정(고른 값의 62.5%)을 존중하지만, body에 읽기 좋은 font-size를 꼭 지정하세요. 그렇지 않으면 자기 크기가 없는 모든 요소가 10px 텍스트로 보여요.

자주 하는 실수

  • 중첩된 요소의 em 글자 크기. 단계마다 곱해져요. 글자 크기에는 rem을 쓰세요.
  • 아무 일도 하지 않는 height: 50%. 퍼센트 높이가 동작하려면 부모에 높이가 지정되어 있어야 해요.
  • padding-top: 10%가 부모 높이를 따를 거라고 기대하기. 세로 padding과 margin 퍼센트는 부모의 너비를 써요.
  • 가로 스크롤바를 만드는 width: 100vw. 스크롤바를 포함해요. 100%를 쓰세요.
  • 휴대폰에서 잘리는 height: 100vh. 100svh나 100dvh를 쓰세요.
  • html { font-size: 12px } 지정하기. 루트의 px 값은 페이지 전체에서 독자의 글자 크기 설정을 덮어써요. 루트는 그대로 두거나 퍼센트를 쓰세요.

자주 묻는 질문

rem과 em은 무엇이 다른가요?

rem은 루트 요소(<html>)의 글자 크기를 기준으로 해서 1.5rem은 페이지 어디서나 같은 크기예요. em은 요소 자신의 글자 크기(font-size에서는 부모의 글자 크기)를 기준으로 해서 요소가 중첩되면 누적돼요.

1rem은 몇 픽셀인가요?

기본적으로 16px이에요. 브라우저가 루트 글자 크기를 16px로 정하기 때문이에요. 사용자가 브라우저 설정에서 기본 글자 크기를 키우거나, html { font-size: ... }를 지정하면 1rem도 함께 바뀌어요.

글자 크기에는 rem과 px 중 무엇을 써야 하나요?

글자 크기에는 rem을 쓰세요. 독자가 브라우저에서 정한 기본 글자 크기 설정을 존중하고, px는 이를 무시해요. 브라우저 확대는 둘 다 키우지만, 모든 독자가 확대를 쓰지는 않아요.

rem 대신 em은 언제 써야 하나요?

버튼의 padding이나 텍스트 옆 아이콘 크기처럼 요소 자신의 텍스트에 맞춰 커져야 하는 간격에 em을 쓰세요. 그러면 같은 클래스가 어떤 글자 크기에서도 제대로 보여요. 글자 크기와 페이지 수준 간격에는 rem을 써서 아무것도 누적되지 않게 하세요.

100vh와 100dvh는 무엇이 다른가요?

모바일 브라우저에서 100vh는 주소창이 숨겨졌을 때의 높이라서, 주소창이 보이는 동안 100vh 섹션은 보이는 화면보다 커요. 100dvh(동적 뷰포트 높이)는 주소창이 나타나고 사라지는 것을 따라가고, 100svh는 항상 작은 쪽 높이예요.

Coddy programming languages illustration

Coddy로 코딩 배우기

시작하기