CSS에 단위가 이렇게 많은 이유
CSS는 크기를 지정하는 단위를 꽤 다양하게 제공합니다: px, em, rem, %, vw, vh, vmin, vmax, ch, ex, cm, mm, in, pt, pc. 이 다양성은 서로 다른 문제가 근본적으로 다른 접근 방식을 요구하기 때문입니다. 사용자 브라우저 환경 설정에 따라 스케일해야 하는 폰트 크기는, 항상 선명하게 유지되어야 하는 1픽셀 테두리와는 다른 단위가 필요합니다.
어떤 상황에서 어떤 단위를 쓸지 아는 것은 프론트엔드 개발에서 가장 실용적인 스킬 중 하나입니다.
절대 단위: 고정 크기
**px(픽셀)**는 CSS에서 가장 많이 쓰이는 절대 단위입니다. 이름과 달리, CSS 픽셀은 반드시 물리적 장치 픽셀과 같지 않습니다. 고해상도(레티나) 디스플레이에서는 CSS 픽셀 하나가 물리적 픽셀 2~3개에 해당할 수 있습니다. px가 제공하는 것은 컨텍스트에 따라 변하지 않는 일관되고 예측 가능한 크기입니다.
px를 쓰면 좋은 곳: 테두리(보통 1px), 박스 그림자, 매우 작은 장식 디테일, 컨텍스트에 관계없이 정확한 픽셀 단위 크기가 필요한 경우.
대부분의 경우 폰트 크기와 레이아웃 치수에는 px를 피하세요. 사용자가 브라우저 접근성 설정에서 텍스트를 확대하는 기능을 막기 때문입니다.
cm, mm, in, pt, pc 같은 다른 절대 단위는 인쇄 스타일시트를 위한 것입니다. 화면 레이아웃에는 쓰지 마세요.
폰트 기준 상대 단위: em
**em**은 적용된 요소의 폰트 크기에 상대적입니다. 요소의 폰트 크기가 16px이면 1em = 16px, 1.5em = 24px, 0.75em = 12px입니다.
em을 font-size 자체에 사용하면 중첩됩니다. 부모도 1.2em으로 설정되어 있고 자식도 1.2em으로 설정하면 1.2 × 1.2 = 1.44배가 됩니다. 깊게 중첩된 구조에서 예상치 못한 결과를 낼 수 있습니다.
em을 쓰면 좋은 곳: 컴포넌트의 텍스트와 비례해서 스케일해야 하는 패딩과 마진. 레이블 폰트 크기와 균형이 맞아야 하는 내비게이션 항목의 패딩이 좋은 예입니다.
루트 기준 상대 단위: rem
**rem**(root em)은 현재 요소가 아닌 루트 `<html>` 요소의 폰트 크기에 상대적입니다. em의 중첩 문제를 해결합니다.
브라우저 기본 폰트 크기는 16px이므로, 루트 폰트 크기를 바꾸지 않으면 1rem = 16px입니다.
rem을 쓰면 좋은 곳: 거의 모든 폰트 크기. 사용자가 브라우저에서 기본 폰트 크기를 20px로 설정했다면, rem 기반 텍스트가 그에 맞게 스케일되어 접근성이 향상됩니다. 전체 페이지 규모의 간격 값(마진, 패딩, 갭)에도 rem을 쓰세요.
흔히 쓰이는 패턴: 루트 폰트 크기를 62.5%로 설정하면(기본 브라우저 설정에서 1rem = 10px) rem 계산이 더 직관적이 됩니다. 그러나 사용자 폰트 크기 설정을 방해할 수 있으니 주의해서 사용하세요.
퍼센트: 부모 기준
**%**는 부모 요소의 동일한 속성에 상대적입니다. width에서 50%는 부모 너비의 절반을 의미합니다. font-size에서 120%는 부모 폰트 크기의 1.2배입니다.
부모 기준 동작 덕분에 %는 유동적인 레이아웃에 매우 유용합니다. flex나 grid 컨테이너 안에서 width: 33.333%로 설정된 컬럼은 어떤 컨테이너 너비에도 자연스럽게 적응합니다.
함정 하나: 퍼센트 height는 부모에 명시적인 height가 정의되어 있어야만 동작합니다. height: auto인 부모 안에서 height: 50%를 설정하면 브라우저가 퍼센트를 무시합니다.
뷰포트 단위: 화면 기준
**vw**(viewport width)와 **vh**(viewport height)는 뷰포트 크기의 퍼센트입니다. 100vw는 브라우저 창의 전체 너비, 50vh는 전체 높이의 절반입니다.
풀스크린 섹션, 히어로 이미지, 고정 요소에 특히 강력합니다. height: 100vh인 섹션은 항상 정확히 한 화면을 채웁니다.
그러나 vh는 모바일 브라우저에서 잘 알려진 문제가 있습니다. 브라우저 크롬(주소창, 내비게이션)이 뷰포트 높이 계산에 일관성 없이 포함되어, "100vh"가 실제 보이는 영역보다 길어질 수 있습니다. 현대 CSS는 `dvh`(dynamic viewport height)로 이 문제를 해결합니다. `100dvh`는 브라우저 크롬을 반영합니다.
**vmin**은 vw와 vh 중 작은 값입니다. **vmax**는 큰 값입니다. 기기 방향에 관계없이 비례적으로 느껴져야 하는 요소 크기 지정에 유용합니다.
알아두면 유용한 최신 단위
**ch**는 현재 폰트에서 "0" 문자의 너비입니다. 텍스트 콘텐츠의 max-width 설정에 유용합니다. `max-width: 70ch`는 폰트 크기에 관계없이 읽기 편한 줄 길이를 만듭니다.
**clamp()**는 단위라기보다 함수지만 언급할 가치가 있습니다. `clamp(1rem, 2.5vw, 2rem)`은 한 번의 선언으로 최솟값, 선호값, 최댓값을 설정하여 미디어 쿼리 없이도 유동적인 타이포그래피 스케일링을 가능하게 합니다.
실용적인 경험 법칙
폰트 크기와 전체 간격에는 **rem**을 사용하세요. 텍스트에 비례해 스케일해야 하는 컴포넌트 내부 간격에는 **em**을 쓰세요. 유동적인 레이아웃 너비에는 **%**를 씁니다. **px**는 얇은 테두리, 그림자, 작은 장식 디테일에만 사용하세요. 풀뷰포트 섹션과 고정 요소에는 **vw/vh**(또는 dvh)를 쓰세요. 접근성을 위해 폰트 크기에는 px를 피하세요.