CSS에서 rem 단위 사용하기

rem 단위의 뜻, 그리고 효과적으로 사용하는 방법과 유의사항에 대해 알아봅니다.

김정태

복사됨
페이스북트위터이메일

목차

CSS 단위

CSS에서 길이나 크기를 다룰 때 사용하는 단위는 px, em, vw, vh 등 다양합니다. 웹 개발을 해보셨다면 그중에 픽셀 단위 px가 제일 익숙할 것입니다. 그런데 누군가는 rem 단위가 더 유연하고 좋은 단위라고 말합니다. 실제로 Bootstrap이나 TailwindCSS 등의 CSS 프레임워크는 rem 단위를 사용하여 개발되었습니다. 이번 글에서는 rem 단위가 왜 좋은 것인지, 픽셀 단위와 무엇이 다르고 어떻게 사용해야 하는지, 그리고 유의사항은 무엇이 있는지 자세히 알아보겠습니다.

픽셀 절대 단위 px

픽셀 단위 px는 CSS에서 가장 기본적인 단위입니다. CSS에서 픽셀 단위로 값을 입력하는 것은, 내가 원하는 값은 정확히 이 값이라고 절댓값으로 단호하게 선언하는 것입니다. CSS에서 1px은 사용자 디스플레이 기기의 논리적 해상도 1pt에 대응하며, 픽셀 단위로 지정한 크기는 CSS 개발을 하다가 나중에 크기를 변경하고 싶다면 다른 픽셀값으로 다시 지정해야 합니다.

폰트 사이즈의 상대 단위 em

절대적 단위인 픽셀과 다르게 상대적 단위em은 값을 폰트 사이즈에 대한 상댓값으로 계산하여 결정합니다. 예를 들어, 부모 요소의 font-size가 20px이고, 자식 요소의 font-size1.5em을 입력한다면, 자식 요소는 상속받은 20px의 폰트 사이즈에 1.5를 곱해서 30px의 폰트 사이즈 결과값을 얻게 됩니다.

.parent {
  font-size: 20px;
}
.child {
  /* 결과 → 상속받은 20px × 1.5 = 30px */
  font-size: 1.5em;
}

이렇게 font-size에 em 단위를 쓸 경우, 기반이 되는 값은 상위 요소의 폰트 사이즈입니다. 이런 특성으로 인해 부모 요소 한 번의 변경으로 자식 요소 여럿의 다양한 크기 값을 동시에 바꿀 수 있어 유연한 단위라고 할 수 있습니다. 게다가 em 단위는 font-size 외에도 사이즈 단위가 사용되는 모든 프로퍼티에 사용 가능합니다. 그런 경우에도 계산 기반값은 폰트 사이즈입니다. 정확히 말하면 자신의 폰트 사이즈입니다. 참고로 CSS에서 자신의 폰트 사이즈가 지정되지 않으면 부모의 폰트 사이즈를 상속받습니다.

.parent {
  font-size: 20px;
}
.child-a {
  /* 결과 → 20px × 1.2 = 24px */
  font-size: 1.2em;
  /* 결과 → 자신의 폰트 사이즈 24px × 1.5 = 36px */
  height: 1.5em;
}
.child-b {
  /* 결과 → 자신의 상속받은 폰트 사이즈 20px × 1.5 = 30px */
  height: 1.5em;
}

이렇게 em 단위는 font-size 뿐만 아니라 모든 프로퍼티에서 사용할 수 있으며, 가끔 유용하게 쓸 수 있는 단위입니다. 하지만 다음의 이유로 em 단위가 픽셀 단위를 완전히 대체하여 모든 곳에 사용되기에는 무리가 있습니다.

  • CSS는 스타일만을 정의하고 실제 구조는 HTML 요소 트리가 결정하기에, CSS 내에서는 상위 요소가 무엇이고 그 폰트 사이즈가 얼마인지 알기 어렵습니다.
  • CSS 내에서 상위 요소를 확실히 알더라도, em 단위가 여러 번 중첩된 경우에는 em 값의 계산 결과를 직관적으로 예측하기 어렵습니다.

다음은 이런 문제를 보여주는 예제입니다.

body {
  font-size: 16px;
}

/* CSS 내에서는 상위 요소을 정확히 알 수 없습니다 */
.menu {
  /* 결과 → CSS만으로는 예측 불가 */
  height: 1.5em;
}

/* 상위 요소를 알더라도 em 단위가 중첩되면 값을 예측하기 어렵습니다 */
body > .post {
  font-size: 1.25em;
}
body > .post > .content {
  font-size: 0.9em;
}
body > .post > .content > ul.toc {
  font-size: 1.5em;
}
body > .post .content > ul.toc > a {
  /* 결과 → 16px × 1.25 × 0.9 × 1.5 × 0.5 = 13.5px */
  font-size: 0.5em;
}

루트 요소 폰트 사이즈의 상대 단위 rem

em 단위는 유연하지만, 픽셀 단위를 대체하기엔 무리가 있습니다. 하지만 계산에 기반하는 요소가 정해져 있는 상대 단위가 있다면 어떨까요? 그것이 바로 rem 단위입니다. rem 단위는 CSS3 표준에서 등장했으며, 어원은 Root EM입니다. 어원에서 알 수 있듯, rem 단위는 HTML 루트 요소의 폰트 사이즈가 계산의 기반값입니다.

루트 요소의 폰트 사이즈는 웹 브라우저의 기본 폰트 사이즈가 결정하며, 대부분의 웹 브라우저에서 16px로 정해놓고 있습니다. 그렇다면 어떤 자식 요소에서든 CSS 프로퍼티의 값으로 1.5rem을 지정한 경우, 루트 요소 폰트 사이즈인 16px에 1.5가 곱해져서 최종 계산된 결과값은 24px이 됩니다. 자신의 폰트 사이즈에 비례하는 em 단위와는 달리, rem 단위는 어떤 요소에서 사용하든 계산 기반값이 일관되는 것입니다.

span {
  /* 결과값은 16px × 1.25 → 20px */
  font-size: 1.25rem;
  /* font-size와 관계없이 결과값은 16px × 1.5 → 24px */
  padding: 1.5rem;
}

그런데 이런 단위가 픽셀 단위를 잘 대체할 수 있을까요? em 단위의 문제점인 기반값(폰트 사이즈)의 불명확함은 해결됐으나, 여전히 남는 문제는 계산의 불편함입니다. 디자이너에게서 넘겨받은 프로토타입을 토대로 스타일 시트를 작성하거나, 이미지나 영상 같은 외부 리소스를 삽입하는 경우 등, 스타일 시트 작성자는 매번 필요한 픽셀값에 대해서 rem 값이 얼마가 필요한지 계산해야만 합니다. 그럼 어떤 요소의 border-width1px로 지정하고 싶다면 rem 값으로는 얼마를 입력해야 할까요? 스타일 시트를 읽고 있는데 눈앞에 45rem이라는 값이 있다면 그게 몇 픽셀로 계산되는지 직관적으로 알 수 있을까요?

.container {
  /* 딱 봐도 720px */
  width: 720px;
  /* 결과는 16px에 45를 곱해서 얼마? */
  height: 45rem;
  /* rem 단위로 바꾸고 싶다면? */
  border: 1px solid black;
}

rem 단위를 사용하면서 픽셀 단위로 계산된 결과를 예측하는 것은 em 단위와 마찬가지로 비직관적이기 때문에, rem 단위로 코딩하는 것은 전반적으로 불편합니다. 애초에 기반값이 항상 16px일 것이면 rem 단위는 왜 써야 할까요? rem 단위를 쓰면 장점은 무엇이 있을까요?

REM 단위의 장점

웹 사이트 전반에 rem 단위를 사용하면 다음 세 가지 장점을 얻을 수 있습니다.

  • 웹 브라우저마다 다른 기본 폰트 사이즈에 대응
  • 저시력자 접근성에 대응
  • 전체 스타일의 스케일을 손쉽게 조정

웹 브라우저마다 다른 기본 폰트 사이즈에 대응

앞에서 루트 요소 폰트 사이즈, 즉 웹 브라우저의 기본 폰트 사이즈의 기본값은 대게 16px이라고 하였습니다. 하지만 기본 폰트 사이즈가 16px이 아닌 브라우저도 분명히 존재합니다. 그런 브라우저들은 기본값이 왜 다를까요?

오랜 과거에, 웹 서핑은 오직 PC에서만 가능했습니다. 그러나 십수 년 전부터 모바일 기기에도 웹 브라우저가 탑재되면서, 크기는 작으면서 PPI(단위 면적 당 픽셀 수)가 높은 기기에서도 웹 서핑이 원활해야 할 필요가 있었습니다. 일단 주요 기기별 해상도(PPI)는 다음과 같습니다.

기기 PPI
과거~현재 일반 PC 모니터 96~
2000년대 국산 휴대전화 150~180
iPhone 3G(2008) 163
Galaxy S(2010) 235
Amazon Kindle 3 (2010) 167

DPI Calculator / PPI Calculator에서 디스플레이 해상도와 대각선 길이(인치)를 DPI/PPI로 환산 가능합니다.

위 표대로면, 16px이 PC 모니터에서는 4.2mm의 크기로, 모바일 기기에서는 2.5mm도 안 되는 크기로 보일 것입니다. 이러면 모바일 기기는 가뜩이나 화면 크기도 작은데, 글씨는 더 작아서 가독성이 떨어지게 됩니다.

그래서 높은 e북 리더 기기나, Opera Mini, Blackberry의 기본 웹 브라우저 등, 작은 기기에 주로 활용되는 웹 브라우저의 기본 폰트 사이즈는 16px을 넘는 경우가 있습니다. 기본 폰트의 크기를 늘림으로써 가독성을 향상하는 것입니다.

그런데 스타일 시트에서 픽셀 단위만 사용하면, 이런 기본 폰트 사이즈의 차이에 대응하지 못하고, 가독성이 떨어지게 됩니다. 기기의 특성에 맞춰 사전 설정된 폰트 사이즈가 무시되기 때문입니다. 이에 대응하려면 기본 폰트 사이즈에 비례하는 단위인 rem 단위를 사용해야만 합니다.

사실, 논리적 해상도의 포인트 하나에 픽셀을 n²개씩 사용하는 요즘의 고해상도 모바일 기기에서는, 굳이 기본 폰트 사이즈를 16px을 넘게 설정하지 않아도 가독성 문제가 없습니다. 그런 이유로 대부분의 최신 모바일 기기에서는 기본 폰트 사이즈가 16px 그대로입니다.

저시력자 접근성에 대응

기본 폰트 사이즈 값은 보통 웹 브라우저 선에서 고정되어 있습니다. 여기에 더해서 일부 웹 브라우저는 이 기본값을 변경할 수 있는 저시력자 접근성 설정을 제공합니다. 하지만 픽셀 단위를 사용하면 여기에서도 해당 설정이 무시되므로, rem 단위 사용해야만 저시력자 접근성에 유연하게 대응할 수 있게 됩니다.

이런 기능이 제공되는 웹 브라우저에서도 기본값은 대부분 16px입니다.

주요 PC 웹 브라우저의 기본 폰트 사이즈 설정 위치와 기본값

주요 PC 웹 브라우저별 기본 폰트 사이즈 설정의 위치와 기본값을 정리하였습니다.

웹 브라우저 설정 위치 기본값
Chrome 84 설정 → 모양 → 글꼴 맞춤설정 → 글꼴 크기 16px
IE 11 - 16px
Safari 13 - 16px
Firefox 80 설정 → 일반 → 글꼴과 색상 → 크기 16px

Firefox는 글꼴 설정이 HTML 요소에 지정된 언어에 따라 다르게 적용됩니다. 예를 들어, lang 애트리뷰트가 en으로 지정된 요소에 대해 글꼴 설정을 지정하려면 ‘라틴 문자’ 종류를 선택하고 설정을 변경해야 합니다.

전체 스타일의 스케일을 손쉽게 조정

font-size 뿐만 아니라 모든 사이징 프로퍼티에 rem 단위를 사용하고 있고, 반응형 웹 디자인을 위해 min-width 등의 미디어 쿼리를 사용하는 경우, 이 장점은 사용할 수 없습니다. 자세한 내용은 미디어 쿼리 절에서 설명합니다.

rem 단위는 font-size 프로퍼티에 대해서만 사용할 수도 있고, 모든 사이징 프로퍼티에 사용하여 전체 레이아웃을 rem 단위로 만들 수도 있습니다. 여기서 후자의 경우 루트 요소 폰트 사이즈를 변경하는 것만으로, 웹 사이트의 전체 폰트 사이즈 또는 전체 레이아웃 스케일까지 한 번에 변경할 수 있게 됩니다. rem 단위는 루트 요소의 폰트 사이즈 값에 대해 상대적으로 계산되기 때문입니다. 우선 다음 예제를 봅시다.

.title {
  /* 결과 → 16px × 2.5 = 40px */
  margin: 2.5rem;
  /* 결과 → 16px × 1.25 = 20px */
  font-size: 1.25rem;
}

위 예제는 루트 요소 폰트 사이즈가 16px이라고 가정하고 모든 프로퍼티를 rem 단위로 지정하였습니다. 그런데 여기서 전체 레이아웃 스케일을 150%로 키우고 싶다면 어떻게 하면 될까요? 이것이 px 단위로 코딩되어 있었다면, 모든 스타일 요소에 대한 값을 일일이 변경해야 했을 것입니다. 하지만 rem 단위로 정의한 스타일이므로, 간단히 다음과 같이 루트 요소의 폰트 사이즈 프로퍼티만 지정해주면 됩니다.

HTML에서 루트 요소<html>을 말합니다. 이것의 CSS 셀렉터는 :roothtml입니다.

html {
  /* 루트 요소 폰트 사이즈 */
  /* 기본값 16px에서 150%로 키워 24px */
  font-size: 24px;}
.title {
  /* 결과 → 24px × 2.5 = 60px */
  margin: 2.5rem;
  /* 결과 → 24px × 1.25 = 30px */
  font-size: 1.25rem;
}

rem 단위의 기반값을 변경했으므로, 다른 모든 프로퍼티의 계산 결과값도 50%씩 증가하게 됩니다. rem 단위의 유연함이 돋보이는 순간입니다.

하지만 이 방법에는 문제가 하나 있습니다. 이렇게 루트 요소 폰트 사이즈 값을 절대 단위인 px로 입력하면, 사용자 웹 브라우저의 폰트 사이즈 기본값 설정이 무시되고 스타일 시트에서 지정한 값으로 대체되고 맙니다. rem 단위의 본래 목적과 장점을 모두 살리려면 다음과 같이 상대 단위 %를 사용하는 것이 좋습니다. 다음과 같이 상대 단위를 사용하면 사용자 웹 브라우저의 기본 폰트 사이즈 기본값에 대한 상댓값을 사용하게 되므로 사용자 접근성을 저해하지 않습니다.

:root {
  /* 루트 요소 폰트 사이즈, 상댓값 */
  /* 전체 레이아웃의 크기를 150%로 키우기 */
  font-size: 150%;}
.box {
  /* 결과 → 16px × 150% × 2.5 = 60px */
  margin: 2.5rem;
  /* 결과 → 16px × 150% × 1.25 = 30px */
  font-size: 1.25rem;
}

rem 단위의 이런 장점을 활용하면 다음과 같은 기능을 쉽게 구현할 수 있습니다.

  • 사용자에게 확대/축소 버튼을 제공하기 → 자바스크립트로 루트 요소 폰트 사이즈를 변경하여 구현
  • 사용자가 모바일 기기를 가로 모드로 하였을 때, 전체 스타일을 축소하여 가독성 향상하기 → CSS 미디어 쿼리를 활용하여 구현

사실 특정 요소의 전체 레이아웃에 대한 간편 확대/축소 기능은 CSS 프로퍼티인 zoom(MDN 문서)으로도 구현할 수 있습니다. 하지만 이는 인터넷 익스플로러 5에서 기원한 비표준 CSS 프로퍼티이며, Firefox에서는 동작하지 않는 등의 문제가 있습니다.

REM 단위 사용하기

rem 단위는 브라우저마다 다른 기본 폰트 사이즈와 저시력자의 접근성에 대응하기 위해 사용합니다. 그렇다면 rem 단위를 어떻게 사용하면 될까요?

앞에서 설명했듯이 크게 두 가지 방식이 있습니다.

  • font-size에 대해서만 사용하기
  • 모든 프로퍼티에 대해서 사용하기

font-size에 대해서만 사용하기

첫 번째로 rem 단위를 font-size 프로퍼티에 대해서만 사용하는 방식이 있습니다. rem 단위의 원래 용도 그대로 쓰는 방법이며, 부작용이 거의 없습니다. 그렇다면 당장 이미 만들어진 웹사이트의 모든 font-size 단위를 rem으로 바꾸기만 하면 될까요? 아래 예제는 일단 기본 폰트 사이즈가 16px이라고 가정하고 만든 스타일입니다.

.box {
  background-color: #111;
  color: #eee;
  border-radius: 3px;
  height: 20px;
  font-size: 1rem;
}

height20px 고정값이고, 폰트 사이즈는 1rem입니다. 만약 웹 브라우저의 기본 폰트 사이즈가 16px이라면 아무 문제 없이 텍스트가 박스 안에 위치할 것입니다. 하지만 기본 폰트 사이즈를 32px로 확 키우면 어떻게 될까요? 폰트 사이즈가 height 값인 20px보다 훨씬 커져 버렸으니, 확대된 텍스트가 잘리거나 넘치게 될 것입니다.

레이아웃을 여유 없게 디자인하다 보니 이런 결과가 빚어졌습니다. 웹 콘텐츠 접근성 가이드라인 WCAG 2.1의 1.4.4 항목에 따르면 텍스트는 200%까지 키워도 내용의 손실이나 기능상 문제가 없어야 한다고 되어있습니다. 그렇다면 어떻게 해야 위 예제에서 폰트가 두 배로 커져도 문제가 없을까요?

일단 떠오르는 방법은, 다음과 같이 애초에 height 값을 두 배로 크게 잡는 것입니다.

height: 40px;

하지만 이 방법은, 기본 폰트 사이즈가 16px일 때, 빈 공간이 너무 많아 디자이너가 원하는 공간 비율을 해칩니다. 게다가 폰트 사이즈가 200%보다 더 커지면 또다시 넘치게 될 것입니다.

대신에 다음 예제와 같이 min-height 프로퍼티를 활용해서, 픽셀 단위로 지정한 높이값보다 rem 단위로 지정한 높이 값이 더 커지면 해당 값으로 대체되도록 할 수 있습니다.

font-size: 1rem;
height: 20px;
min-height: 1rem;

이렇게 하면, 기본 폰트 사이즈가 커짐에 따라 유연하게 박스의 크기도 같이 확대될 것입니다.

혹시 rem 값에 가감이 필요하다면 다음과 같이 CSS 함수 calc를 쓰면 됩니다.

min-height: 1.2rem;
min-height: calc(1.1rem + 8px);

이렇게 rem 단위를 font-size에만 적용하는 방법은, 폰트 사이즈가 커질 때의 레이아웃 고민을 많이 하게 하지만, 다른 부작용은 없는 장점이 있습니다. 외부 리소스를 삽입하는 경우에도 리소스 영역의 넓이와 리소스의 크기가 1:1로 일치하므로 화질 저하 등의 문제도 없습니다.

모든 프로퍼티에 대해서 사용하기

두 번째 방식은 font-size 뿐만 아니라 모든 프로퍼티에 대해 rem 단위를 사용하는 것입니다. 그렇게 하면 웹 브라우저의 기본 폰트 사이즈가 커지면 레이아웃의 크기가 함께 확대되므로, 폰트가 커져서 레이아웃이 망가질 염려를 하지 않아도 됩니다. 아래 예제는 일단 기본 폰트 사이즈가 16px이라고 가정하고 만든 스타일입니다.

.box {
  background-color: #111;
  color: #eee;
  border-radius: 0.1875rem;
  height: 1.25rem;
  font-size: 1rem;
}

레이아웃이 망가지는 것을 고민하지 않아도 되니, rem 단위를 더 쉽게 사용할 수 있습니다. 하지만 원하는 픽셀 값에서 16으로 나누어 입력해야 해서 단위가 낯설고 불편합니다. 그리고 이렇게 작업하면, 정적인 크기와 비율을 가진 이미지와 같은 외부 리소스의 경우, 기본 폰트 사이즈의 변경에 따라 같이 커지면서 리소스 영역과 리소스의 크기 불일치로 화질 저하 등의 문제가 발생할 수도 있습니다. 그리고 뒤에서 설명하겠지만, rem 단위를 레이아웃에 쓰는 경우 부작용이 많습니다.

이렇게 두 방식 간에는 장단점 차이가 극명합니다. 남은 글을 마저 읽어보시고, 어떤 방법이 더 적절할지 고민해보시길 바랍니다.

REM 단위의 계산 직관성 높이기

rem 단위를 사용하기 어려운 이유 중 하나는 단위의 난해함입니다. 픽셀 단위를 사용하는 디자이너와 협업을 하거나 웹 사이트에 외부 리소스를 삽입하는 등 여러 상황에서 픽셀 단위가 필요할 수 있습니다. 그런 상황에서는 원하는 픽셀 값을 적용하려면 보통의 루트 요소 폰트 사이즈 값인 16px에서 나눗셈을 해야 합니다. 그렇기에 원하는 결과에 필요한 rem 값을 머릿속에서 바로 계산하기 어렵고, rem 값을 보고 실제 계산되는 픽셀 길이가 얼마인지 가늠하기가 힘듭니다.

간단한 해법은 루트 요소 폰트 사이즈를 10px로 맞추는 것입니다. 그렇게 하면 원하는 픽셀 값에서 10을 나누기만 하면, 필요한 rem 값을 쉽게 계산할 수 있습니다.

그런데 루트 요소 폰트 사이즈를 10px보다는 1px로 맞추는 것이 더 편하지 않을까요? 하지만 그렇게 하면 특정 브라우저에서 문제가 발생합니다. 관련 내용은 바로 다음 절에서 설명합니다.

html {
  font-size: 10px;}
body {
  /* 결과 → 10px × 1.6 = 16px */
  font-size: 1.6rem;
}
.box {
  /* 결과 → 10px × 6.4 = 64px */
  width: 6.4rem;
}

확실히 기본값 16px을 그대로 쓸 때보다, 계산이 훨씬 편해졌습니다. 하지만 앞서 말했듯이 루트 요소 폰트 사이즈를 절댓값으로 지정하면 저시력자 접근성 설정을 무시하게 되므로, 상댓값 62.5%를 사용하는 것이 더 낫습니다. 16px의 62.5%는 정확히 10px이므로, 같은 결과를 보여주면서 접근성도 해치지 않습니다.

html {
  /* 결과 → 16px × 62.5% = 10px */
  font-size: 62.5%;}
body {
  /* 결과 → 10px × 1.6 = 16px */
  font-size: 1.6rem;
}
.box {
  /* 결과 → 10px × 6.4 = 64px */
  width: 6.4rem;
}

단, 여기에도 한 가지 작은 문제가 있습니다. IE에서는 % 단위로 입력한 값의 소수점이 잘려버리기 때문에, 62.5%는 62%로 계산됩니다. 1rem의 계산 결과가 1px이 아닌 0.992px이 되는 것입니다. 이런 브라우저에서 rem 단위를 사용하면 오차로 인해 rem 값의 계산 결과값이 예상보다 약간 축소될 것입니다. font-size에 대해서만 rem 단위를 사용한다면 별문제가 아니지만, 전체 레이아웃에 rem 단위를 사용하고 있다면 이는 중요한 문제입니다. 해결법은 오직 IE에서만 루트 요소 폰트 사이즈를 절댓값 10px로 고정시키는 것입니다. 어차피 IE에서는 사용자가 폰트 사이즈 기본값을 변경하지 못하므로, 접근성 문제도 일어나지 않습니다. IE에게만 작동하는 CSS 코드를 만드는 것은, 다음 예제의 특별한 CSS 미디어 쿼리 블록을 활용하면 됩니다.

html {
  font-size: 62.5%;
}
@media screen and (min-width: 0\0) {
  /* IE 9, IE 10, IE 11 */
  :root,
  html {
    font-size: 10px;
  }
}
@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
  /* IE 10, IE 11 */
  :root,
  html {
    font-size: 10px;
  }
}

Browser Hacks에서 특정 브라우저에서 작동하는 JS/CSS 코드 스니펫을 구할 수 있습니다.

IE 9 미만의 버전은 rem 단위를 지원하지 않습니다. 그리고 IE 9, 10에서는 font 프로퍼티나 :before, :after 의사 엘리먼트에서 rem 단위를 지원하지 않습니다. 이 내용은 뒤에서 설명합니다.

REM 단위의 계산에 영항을 미치는 요인

여기까지 읽으면, 이제 픽셀 단위 대신에 rem 단위를 써도 아무런 문제가 없을 것만 같습니다. 하지만 rem 단위의 계산 방식에는 함정이 많습니다. 웹 브라우저의 종류나 사용자 설정이 rem 계산에 영향을 미치기 때문입니다. 이 글에서는 PC에서 가장 많이 쓰이는 주요 브라우저 4종 (Chrome, IE, Safari, Firefox)에 대한 유의사항을 소개해드립니다.

Chrome은 같은 Chromium 기반 브라우저인 MS Edge, 네이버 웨일 등과 같은 동작 특성을 보입니다. 다만 사용자 설정의 위치나 구성에는 차이가 있습니다.

  • (Chrome, 맥 Safari, Firefox) 사용자의 폰트 사이즈 하한선 설정값은 얼마인가
  • (맥/모바일 Safari) 어떤 CSS 프로퍼티rem 단위를 사용하는가
  • (맥/모바일 Safari) 루트 요소 폰트 사이즈어떤 단위를 사용하는가
  • (맥 Safari) 사용자가 축소 기능을 사용 중인가
  • (IE) 구버전의 IE를 사용 중인가

보통은 웹 표준 준수성을 이야기할 때 IE가 많이 거론되지만, 여기서 소개하는 내용 중엔 Safari에 관한 내용이 많습니다. rem 단위로 레이아웃을 할 때, Safari는 다른 브라우저와 다르게 계산하는 문제가 많기 때문입니다. 그렇다면 어차피 점유율도 낮은데 Safari를 크로스 브라우징에서 배제해버리면 되지 않을까요? 만약 웹 사이트의 대상 플랫폼이 오직 PC라면 괜찮은 생각일 수 있습니다. 국내에서 애플 맥의 사용 비중은 매우 낮고, 맥 사용자는 Safari보다 Chrome 등의 서드파티 웹 브라우저를 더 많이 사용하니까요. 하지만 문제는 모바일 플랫폼입니다. 국내 스마트폰 점유율에서 애플 아이폰의 비중은 꽤 높습니다. 게다가 네이버 앱이나 Chrome 앱 등, 애플 모바일 OS(iOS/iPadOS)의 거의 모든 서드파티 웹 브라우징 앱은 Safari 엔진으로 동작합니다. 결국 국내의 모든 아이폰과 아이패드 사용자는 Safari를 사용하는 셈입니다. 그렇기에 모바일 플랫폼을 아예 포기할 것이 아니라면, Safari에서 발생하는 rem 단위 문제는 꼭 알아야 합니다.

rem 단위를 font-size에 대해서만 사용한다면, 여기서 설명드리는 대부분의 내용은 몰라도 괜찮습니다. 하지만 rem 단위로 레이아웃을 구성하고 싶으시거나, rem 단위에 대해 잘 알고 싶으시다면 모두 읽어보시는 것을 권장합니다. 이번 절에서 설명드리는 모든 내용은 rem 단위로 모든 레이아웃을 구성함을 전제합니다.

사용자의 폰트 사이즈 하한선 설정값은 얼마인가

Chrome, 맥 Safari, Firefox가 여기에 해당합니다

첫 번째 요인은 일부 웹 브라우저의 사용자 설정에 존재하는 폰트 사이즈 하한선이라는 설정입니다. 설정의 이름은 웹 브라우저마다 약간 다를 수 있지만, 목적은 모두 같습니다. 이는 접근성과 관련된 설정으로, 사용자에게 보이는 폰트 사이즈가 지정된 크기보다 작아지지 못하게 막음으로써, 글씨가 너무 작아서 읽기 어려운 상황을 줄이기 위한 것입니다. 지나치게 작은 크기의 폰트는 접근성을 저해시키기 때문에 분명히 유용한 기능입니다.

.title {
  /* 결과 → max(지정한 14px, 하한선 10px) = 14px */
  font-size: 14px;
}
.content {
  /* 결과 → max(지정한 8px, 하한선 10px) = 10px */
  font-size: 8px;
}

em/rem 단위를 사용하여 개발하더라도, 폰트 사이즈 하한선은 계산을 다 끝내고 가장 마지막에 적용됩니다. 또한 font-size가 아닌 프로퍼티에 사용한 em/rem 단위에 대해서는 전혀 영향을 주지 않으므로 문제가 없습니다. (단, Safari는 예외)

/* IE, Firefox, Chromium 기반 등의 모던 브라우저에서 실행 (Safari 제외) */
html {
  /* 결과 → max(16px × 6.25%, 하한선 10px) = 10px */
  /* 하위 요소에는 하한선을 적용하지 않고 */
  /* 16px × 6.25%의 결과값 → 1px로 전파됩니다 */
  font-size: 6.25%;
}
.content {
  /* 결과 → max(상속받은 1px × rem값 8, 하한선 10px) = 10px */
  font-size: 8rem;
  /* 결과 → 상속받은 1px × rem값 8 = 8px */
  /* font-size가 아니므로 하한선은 전혀 적용되지 않습니다 */
  padding: 8rem;
  /* 결과 → 현재 요소 폰트 계산값 8px × em값 0.8 = 6.4px */
  /* font-size가 아니므로 하한선은 전혀 적용되지 않습니다 */
  padding: 0.8em;
}

다시 강조하지만, Safari에서는 위와 같이 작동하지 않습니다. 이제 남은 세 가지 요인은 모두 Safari에 관한 문제입니다.

주요 웹 브라우저의 폰트 사이즈 하한선 설정 위치와 기본값

주요 웹 브라우저별 폰트 사이즈 하한선 설정의 위치와 기본값을 정리하였습니다.

웹 브라우저 설정 위치 기본값
Chrome 84 설정 → 모양 → 글꼴 맞춤설정 → 최소 글꼴 크기 10px
IE 11 - -
맥 Safari 13 설정 → 고급 → 손쉬운 사용 → 다음보다 작은 … OFF (9px)
모바일 Safari 13 - -
Firefox 80 설정 → 일반 → 글꼴과 색상 → 고급 → 최소 글꼴 크기 0

Firefox는 글꼴 설정이 HTML 요소에 지정된 언어에 따라 다르게 적용됩니다. 예를 들어, lang 애트리뷰트가 en으로 지정된 요소에 대해 글꼴 설정을 지정하려면 ‘라틴 문자’ 종류를 선택하고 설정을 변경해야 합니다.

(맥/모바일 Safari) 어떤 CSS 프로퍼티에서 rem 단위를 사용하는가

맥 Safari와 모바일 Safari 둘 다 여기에 해당합니다

Safari의 문제는 Safari에서는 em/rem 단위를 font-size가 아닌 프로퍼티에 사용하여도 하한값이 적용된다는 것입니다. 예를 들어 Safari 사용자가 폰트 사이즈 하한선 설정을 켜고, 설정값을 기본값 9px로 한 경우, 다음 예제와 같은 상황이 발생합니다.

html {
  font-size: 6.25%;
}
.content {
  /* 결과 → max(상속받은 1px × rem값 8, 하한선 9px) = 9px */
  font-size: 8rem;
  /* 정상 결과 → 상속받은 1px × rem값 8 = 8px */
  /* Safari 결과 → max(상속받은 1px, 하한선 9px) × rem값 8 = 72px */
  padding: 8rem;  /* 정상 결과 → 현재 요소의 폰트사이즈 8px × em값 0.8 = 6.4px */
  /* Safari 결과 → 현재 요소의 폰트사이즈에 하한선 적용한 결과값 9px × em값 0.8 = 7.2px */
  margin: 0.8em;}

위 예제에서 문제는 하이라이트 된 부분에 있습니다. 보시다시피 Safari에서는 폰트와 관계없는 padding 같은 프로퍼티에서 rem 단위를 사용했음에도, 루트 요소 폰트 사이즈에 하한값을 적용하고 연산하여, 다른 브라우저들과는 큰 차이를 보입니다. 그런데 Safari만 결과가 이렇게 크게 다르다면 크로스 브라우징은 실패한 것입니다. 이걸 어떻게 해결해야 할까요?

일단 간단한 해법은 루트 요소 폰트 사이즈에 6.25%를 입력해서 1px로 맞추던 것을, 62.5%로 고쳐서 10px로 맞추는 것입니다. 그렇게 하면 루트 요소 폰트 사이즈가, Safari의 폰트 사이즈 하한선 설정 기본값인 9px에 걸리지 않게 되니까요. 아까의 예제를 다시 고쳐보겠습니다.

html {
  /* 1px이 아니라 10px이 되도록 맞춤 */
  font-size: 62.5%;}
.content {
  /* 결과 → max(상속받은 10px × rem값 0.8, 하한선 9px) = 9px */
  font-size: 0.8rem;
  /* 정상 결과 → 상속받은 10px × rem값 0.8 = 8px */
  /* Safari 결과 → max(상속받은 10px, 하한선 9px) × rem값 0.8 = 8px */
  padding: 0.8rem;
  /* 정상 결과 → 현재 요소의 폰트사이즈 8px × em값 0.8 = 6.4px */
  /* Safari 결과 → 현재 요소의 폰트사이즈에 하한선 적용한 결과값 9px × em값 0.8 = 7.2px */
  margin: 0.8em;
}

이제 위 코드는, Safari에서나 다른 브라우저에서나 비슷하게 보일 것입니다.

단 예제에서 margin에 사용한 em 단위의 경우 여전히 문제가 있습니다. 루트 요소 폰트 사이즈는 하한선에 걸리지 않으나, 현재 요소 폰트 사이즈는 하한선에 걸렸기 때문입니다. em 단위를 font-size가 아닌 곳에 쓸 때는, Safari에서는 다르게 보일 수 있음을 잘 생각해야 합니다.

이제 적당히 해결됐으니, 이정도 선에서 만족해도 괜찮을까요? 그런데 이것은 Safari의 폰트 사이즈 하한선 기본값 9px을 간신히 피해서 해결한 것입니다. 대부분의 디스플레이에서 9px의 폰트 크기는 많이 작기 때문에, 하한선 설정을 사용하는 저시력 사용자라면 10px보다 더 큰 값으로 설정할 확률이 높습니다.

그렇다면 Safari를 사용하는 저시력 사용자가 폰트 사이즈 하한선 설정값을 15px로 키운다면 어떻게 될까요? 다른 브라우저에서는 오직 작은 글씨의 폰트 사이즈만 커지겠지만, Safari에서는 하한선이 루트 요소 폰트 사이즈 6.25%(10px)의 1.5배로 커졌으니 모든 레이아웃이 1.5배로 커지게 될 것입니다. 그런데 문제는 그뿐만이 아닙니다. 다음 예제를 봅시다.

/* Safari에서 실행 */
html {
  font-size: 62.5%;
}
.button {
  /* 하한선 9px → max(16px × 62.5% × 1.5, 하한선 9px) = 15px */
  /* 하한선 15px → max(16px × 62.5% × 1.5, 하한선 15px) = 15px */
  font-size: 1.5rem;
  /* 하한선 9px → max(16px × 62.5%, 하한선 9px) × 1 = 10px */
  /* 하한선 15px → max(16px × 62.5%, 하한선 15px) × 1 = 15px */
  padding: 1rem;
  /* 하한선 9px → max(16px × 62.5%, 하한선 9px) × 0.2 = 2px */
  /* 하한선 15px → max(16px × 62.5%, 하한선 15px) × 0.2 = 3px */
  border: 0.2rem solid black;
  /* 하한선 9px → max(16px × 62.5%, 하한선 9px) × 0.3 = 6px */
  /* 하한선 15px → max(16px × 62.5%, 하한선 15px) × 0.3 = 9px */
  border-radius: 0.6rem;
}

기존에 넉넉하게 크던 폰트 사이즈 계산 결과값은 그대로고, 다른 모든 사이즈는 커지는 이상한 결과가 되어버렸습니다. 이런 현상을 다른 브라우저와 비교하여 모의 실행한 결과는 다음과 같습니다.

하한값 없음 보통식 하한값 15px Safari식 하한값 15px
1.2rem
1.2rem
1.2rem

일단 두 결과 모두, 하한선 이상의 크기를 가진 1.5rem(15px)짜리 폰트 사이즈는 그대로입니다. 그러나 유독 Safari에서는 폰트 사이즈 하한선 설정이라는 본래 의미를 벗어나서, 레이아웃 크기를 키워버렸습니다. 이는 루트 요소 폰트 사이즈인 62.5%(10px)에 하한선을 적용하여 15px로 키워서 연산했기 때문입니다.

Safari의 이런 문제를 해결할 방법은 루트 요소 폰트 사이즈를 열 배로 더 키워서 625%(100px)로 만드는 것입니다. 100px 정도면 절대로 Safari의 하한선 설정에 걸리지 않을 것이므로, CSS 코딩은 좀 더 어려워지겠지만 어쨌든 문제는 해결될 것입니다.

아니면 어차피 대부분의 Safari 사용자는 하한선 설정을 사용하지 않으므로 그냥 포기하는 것입니다. 접근성이 필요한 사용자는 다른 브라우저를 사용해야 할 것입니다. 그렇더라도 루트 요소 폰트 사이즈는 62.5%를 계속 유지해야 합니다. 이유는 두 가지가 있는데, 첫 번째 이유는 6.25%를 사용한다면 혹시라도 하한선 설정을 이용하는 Safari 사용자에게서 레이아웃 변형이 아주 크게 일어날 것이기 때문입니다. 다음은 아까와 같은 예제에서 루트 요소 폰트 사이즈를 6.25%로 변경하고 rem 값도 1/10로 줄인 모의 실행 결과입니다.

하한값 없음 보통식 하한값 15px Safari식 하한값 15px
1.2rem
1.2rem
1.2rem

이보다 더 중요한 두 번째 이유는 바로 이어서 설명합니다.

(맥/모바일 Safari) 루트 요소의 font-size에 어떤 단위를 사용하는가

맥 Safari와 모바일 Safari 둘 다 여기에 해당합니다

맥 Safari에서는 폰트 사이즈 하한선 설정은 기본적으로 비활성화되어있습니다. 모바일 Safari에서는 해당 설정이 존재하지도 않습니다. 하지만 그런 상태에서도 특정 조건에서는 폰트 사이즈 하한선이 9px로 강제 적용되는 특징이 있습니다. 이 현상은 루트 요소 폰트 사이즈를 상대 단위인 %로 지정하고, 스타일에 rem 단위를 사용할 때 발생합니다. 보통 rem 단위로 레이아웃을 만드는 경우, 루트 요소 폰트 사이즈에 % 단위를 쓰게 되므로 이 내용 역시 중요합니다. 다음 예제는 이런 문제를 무시하고 루트 요소 폰트 사이즈를 6.25%(1px)로 지정한 뒤, Safari에서 실행하는 예제입니다.

/* Safari에서 실행 */
html {
  /* 결과 = 16px × 6.25% → 1px */
  font-size: 6.25%;}
.title {
  /* 상속받았으나 1rem이나 마찬가지 */
  /* 하한값이 적용되어 1px → 9px */
  font-size: inherit;}
.box {
  /* 1px × 5 → 5px을 예상하지만 */
  /* 하한값이 후적용되어 9px */
  font-size: 5rem;  /* 1px × 3 → 3px을 예상하지만 */
  /* 하한값이 선적용되어 9px × 3 → 27px */
  padding: 3rem;}
.another {
  /* px 단위로 지정한 것은 하한값 미적용 */
  font-size: 5px;
  padding: 3px;
}

rem 단위를 사용한 프로퍼티에 대해서만 하한값이 적용된 것처럼 계산되고 있습니다. 여기서 하한값은 사용자의 설정과 관계없이 항상 9px입니다.

Safari 접근성 설정 호환성을 버린다고 해도 이런 이유로 루트 요소 폰트 사이즈는 62.5% 이상으로 지정해야 하는 것입니다. 그리고 루트 요소 폰트 사이즈에 % 단위 대신 픽셀 단위를 사용하거나, 스타일에 픽셀 단위를 사용하면 이 문제는 일어나지 않습니다.

(맥 Safari) 축소 기능을 사용 중인가

맥 Safari만 여기에 해당합니다

이 문제는 맥 Safari 사용자가 웹 페이지 축소 기능을 사용하는 상황에 발생하며, 모바일 Safari와 기타 대부분의 브라우저에서 일어나지 않습니다. 맥 Safari에서 이런 문제가 일어나는 이유는, 사용자가 축소 기능을 사용하면 Safari에서는 루트 요소 폰트 사이즈도 그만큼 줄어들었다고 여기는 것으로 인해 발생합니다. 예를 들어 웹 사이트에서 루트 요소 폰트 사이즈를 62.5%로 설정했고 사용자가 웹 페이지를 한 단계(85%로) 축소한다면, 실제 사용자의 눈에 보이는 크기는 기본 폰트 사이즈 16px62.5%와 85%를 곱해서 8.5px가 될 것입니다. 하지만 이는 사용자의 의도대로 전체 페이지 스케일을 축소한 것이므로, 폰트 사이즈가 줄었다고 여기긴 어렵습니다. 그런데도 맥 Safari에서는 브라우저 축소 기능의 결과로, 실제 눈에 보이는 폰트 사이즈에 하한선이 적용되어버려, 앞에서 설명한 하한선 문제를 발생시킵니다.

이런 문제로 인해, 만약 루트 요소 폰트 사이즈에 62.5%를 지정한 상태에서 너비가 10rem으로 지정된 어떤 요소가 있다면, Safari 사용자가 85%, 75%, 50%로 아무리 축소를 해도, 너비가 90px 아래로 절대 작아지지 않을 것입니다. 이 문제도 해결하기 위해선 앞에서 말한 루트 요소 폰트 사이즈를 625%로 지정하는 방법을 써야만 합니다.

(IE) 구버전의 IE를 사용 중인가

구버전의 IE만 여기에 해당합니다

rem 단위는 CSS3에 등장하였고, HTML5와 CSS3 표준을 본격적으로 지원하기 시작하는 IE 9부터 지원합니다. IE 9 미만의 버전을 지원하려면 자바스크립트 폴리필을 사용하거나 다음과 같이 픽셀 단위와 병기해야합니다.

.content {
  font-size: 36px;
  font-size: 1.5rem;
}

또한 IE 9, 10에서는 폰트 관련 스타일을 한 번에 지정하는 font 프로퍼티에서 rem 단위를 사용할 수 없습니다. 그리고 :before, :after 같은 의사 엘리먼트에 대해서도 rem 단위를 쓸 수 없습니다.

.content {
  /* IE 9, 10에서는 아랫줄의 전체 내용이 무시됩니다. */
  font: 1rem/1.6 Roboto;
}
.content:before {
  /* IE 9, 10에서는 아랫줄의 내용이 무시됩니다. */
  font-size: 1.2rem;
}

근래에 쓰이는 웹 브라우저는 IE를 제외하곤 모두 rem 단위를 지원합니다. rem 단위의 브라우저별 호환표는 Can I use에서 보실 수 있습니다.

Windows 버전별 기본 설치된 IE 버전

Windows IE
Windows 7 IE 8
Windows 8 IE 10
Windows 8.1 IE 11
Windows 10 IE 11

미디어 쿼리

이제 rem 단위로 레이아웃을 만들 때의 유의사항은 모두 소개했습니다. 남은 문제는 미디어 쿼리입니다. 반응형 디자인을 목표로 하는 경우, 필연적으로 min-width 등의 미디어 쿼리를 사용하게 됩니다. 보통은 픽셀 단위를 사용하여 다음과 같이 작성합니다.

@media only screen and (min-width: 640px) {
  /* 브라우저 폭이 640px 이상일 때 */
  .container {
    margin: 0 auto;
    max-width: 640px;
  }
}

하지만 레이아웃 구성에 rem 단위를 사용했다면, 사용자 브라우저의 기본 폰트 사이즈에 따라 전체 레이아웃 크기가 변하므로, 미디어 쿼리에도 rem 단위를 사용해야 할 것입니다.

html {
  font-size: 62.5%;
}
@media only screen and (min-width: 64rem) {  /* 브라우저 폭이 640px 이상일 때 */
  .container {
    margin: 0 auto;
    max-width: 64rem;  }
}

하지만 이는 제대로 동작하지 않습니다. 미디어 쿼리 블록은 의도한 640px이 아닌 1024px에서 반응할 것입니다. 이유는 미디어 쿼리의 작동 방식에 있습니다. W3C 미디어 쿼리 스펙을 보면, 미디어 쿼리에서 em이나 rem 같은 상대 단위는 페이지에서 지정한 스타일이 아니라 브라우저에 설정된 기본값에 상대적이라고 명시되어 있습니다. 즉, 미디어 쿼리에서의 1em이나 1rem은 개발자가 지정한 루트 요소 폰트 사이즈와 완전히 별개이며, 개발자가 계산 기반값을 바꿀 수 없다는 것입니다. 그러므로 미디어 쿼리에서는 앞에서 설명드린 계산 직관성 높이기 방법을 사용할 수 없습니다. 미디어 쿼리를 작성할 때는 매번 원하는 픽셀 단위의 크기 값에서 기본 폰트 사이즈인 16으로 나눠서 입력해야 합니다. 이전의 예제는 다음과 같이 고쳐야 합니다.

이렇게 미디어 쿼리의 rem 단위와 다른 곳에 쓴 rem 단위가 달라도, 사용자가 브라우저 설정에서 기본 폰트 사이즈를 변경하면 미디어 쿼리의 rem 단위와 다른 곳에 사용한 rem 단위가 모두 같은 비율로 조절되기에 문제는 없습니다.

rem 단위로 레이아웃을 만든 웹 사이트에서 em/rem 단위를 사용하는 미디어 쿼리를 사용하여 반응형 스타일을 구성한다면, 루트 요소 폰트 사이즈 변경을 통한 웹 사이트 스케일링 수법 사용할 수 없습니다. 해당 사이즈 값을 변경하여도 미디어 쿼리에서 사용한 em/rem 단위의 기반값은 변하지 않기 때문입니다. 대신 rem 단위를 오로지 font-size에만 사용한다면 문제가 없을 것입니다.

html {
  font-size: 62.5%;
}
@media only screen and (min-width: 40rem) {  /* 브라우저 폭이 640px 이상일 때 */
  .container {
    margin: 0 auto;
    max-width: 64rem;
  }
}

이제 완벽하게 동작합니다. 미디어 쿼리만 단위가 달라서 계산하기가 좀 번거롭지만, 어쨌든 잘 작동하는 것처럼 보입니다. 그러나 이대로 사용하면, 또 Safari에서 잘 작동하지 않습니다. Safari는 미디어 쿼리 표준을 잘 준수하지 않기 때문입니다.

맥/모바일 Safari 단위 문제 해결하기

Safari는 미디어 쿼리에서도 rem 단위는 개발자가 정한 루트 요소 폰트 사이즈에 상대적으로 계산됩니다. 그러므로 위 예제는 Safari에서 정상적으로 작동하지 않습니다. 따라서 다음과 같이 단위를 em으로 변경해야 합니다. 미디어 쿼리에서 em 단위는 Safari에서도 브라우저의 기본 폰트 사이즈에 상대적으로 계산되므로, 문제가 해결됩니다.

html {
  font-size: 62.5%;
}
@media only screen and (min-width: 40em) {  /* 브라우저 폭이 640px 이상일 때 */
  .container {
    margin: 0 auto;
    max-width: 64rem;
  }
}

맥 Safari 확대/축소 문제

일단 다음과 같이 픽셀 단위 미디어 쿼리 A와 em 단위 미디어 쿼리 B가 있다고 가정하겠습니다.

@media only screen and (min-width: 960px) {
  /* 미디어 쿼리 A */
}
@media only screen and (min-width: 60em) {
  /* 미디어 쿼리 B */
}

브라우저의 기본 폰트 사이즈가 16px이라고 가정하면, 60em960px과 동일합니다. 그러므로 정상적이라면 페이지를 확대하든 축소하든, 두 쿼리는 항상 결과가 같을 것입니다.

하지만 맥 Safari에서는 항상 페이지를 로드하는 시점의 확대/축소 비율만 em 단위의 미디어 쿼리에 반영됩니다. 예를 들어, 사용자가 배율을 85%로 설정한 상태에서 페이지가 로드된다면 960px의 85%인 816px부터 미디어 쿼리 B가 통과됩니다. 100% 상태에서 페이지가 로드한 후, 확대/축소를 하는 것은 아무 문제가 없습니다.

굉장히 이상하고 버그스러운 이런 동작은, 이미 WebKit Bugzilla에 등재되어 있으며, 버그가 맞습니다. 그리고 확대/축소 기능이 있는 모바일 Safari에서는 이런 문제가 없습니다. 이에 대한 해결법은 아직 없으며, 맥 Safari에 국한된 이슈이므로 맥 Safari의 호환성이 정말 중요하다면, 웹 사이트에 맥 Safari에서의 확대/축소 배율 이슈에 대한 안내를 추가하거나, 레이아웃에 em/rem 단위를 배제하고 픽셀 단위를 쓰는 방법을 생각해야 할 것입니다.

소수점 처리 문제

이번에는 Safari를 포함한 대부분의 브라우저에 해당하는 문제입니다. 이렇게 미디어 쿼리에서 상대적 단위를 쓰는 경우, 상댓값의 소수점 처리가 일관되지 않는 이슈가 있습니다. 이것은 max-width 미디어 쿼리를 사용해야 하는 경우에 문제가 됩니다. 다음 예제를 보겠습니다.

@media only screen and (max-width: 639.999999em) {
  /* 640px 미만에서 작동해야함 */
}
@media only screen and (min-width: 640em) {
  /* 640px 이상에서 작동해야함 */
}
@media only screen and (max-width: 39.999999em) {
  /* 640px 미만에서 작동해야함 */
}
@media only screen and (min-width: 40em) {
  /* 640px 이상에서 작동해야함 */
}

위 쿼리들 중, 픽셀 단위를 쓴 쿼리는 의도대로 작동합니다. 하지만 em 단위를 쓴 쿼리는 브라우저 폭이 640px일 때, 둘 다 통과됩니다. 사실 소수점 깊이를 줄이면 의도대로 잘 작동하기도 합니다. 하지만, 브라우저의 확대/축소 배율에 따라서 다시 일관되지 않는 결과가 나타납니다.

이는 상대 단위에 대한 반올림 이슈이며, 명확한 해결법이 없습니다. 그러므로 max-width 쿼리는 일관되지 않게 작동해도 상관없는 스타일에 대해서만 사용하거나, 아예 max-width 쿼리 사용을 최대한 배제하는 것이 좋습니다.

결론

REM 단위를 사용할 때 유의사항 정리

지금까지의 내용으로 rem 단위는 접근성을 위한 단위라는 것을 알 수 있었습니다. 여기에서 충분한 메리트를 느낀다면 rem 단위를 적극적으로 사용하며 개발하면 됩니다. rem 단위를 폰트 사이즈에 대해서만 사용하거나, 나아가 픽셀 단위를 대체하여 모든 레이아웃 관련 프로퍼티에 사용할 때의 유의사항을 정리해보겠습니다.

font-size에 대해서만 사용할 때 유의사항

  • 모든 font-size 프로퍼티에 들어가는 사이즈에 rem 단위를 씁니다.
  • 다른 모든 프로퍼티에는 픽셀 단위와 em 단위를 씁니다. 이때, 웹 브라우저의 기본 폰트 사이즈가 200%(32px)까지 커져도 레이아웃이 망가지지 않도록 합니다.
  • 미디어 쿼리는 픽셀 단위를 씁니다.

모든 프로퍼티에 대해서 사용할 때 유의사항

  • 루트 요소 폰트 사이즈를 기본값으로 두거나 62.5% 또는 625%로 설정합니다. (소수점 이슈가 있는 IE를 지원해야 하는 경우, IE에 한하여 픽셀 단위로 지정)
  • rem 단위를 전체 레이아웃의 단위로 쓰면서 일어나는 모든 이슈를 숙지합니다.
  • 미디어 쿼리는 em 단위를 쓰며, max-width는 쓰지 않습니다.

REM 단위를 써야 할까

접근성 측면에서 rem 단위를 사용하는 것은 중요하지만, 생각해야 할 사항이 많습니다.

  • 저시력 사용자에 의해 기본 폰트 사이즈가 커지는 상황에 대응하다 보면, 디자이너가 의도한 레이아웃을 유지하기 어렵습니다.
  • 전체 레이아웃의 단위로 쓰려면, 앞서 설명한 복잡한 이슈들을 잘 이해해야 합니다. 그리고 Safari는 호환성 및 버그 이슈까지 있습니다.
  • 어차피 대부분의 사용자는 설정 깊숙한 곳에 있는 폰트 사이즈 설정은 바꾸지 않습니다. 대신에 브라우저 자체 확대/축소 기능을 더 사용합니다.

rem 단위는 웹이 대중화된 이후에, CSS3와 함께 웹 표준에 뒤늦게 추가된 개념입니다. 그 때문에 이 단위를 활용하기 위해 기본 폰트 사이즈를 조절하는 옵션이 웹 브라우저에 있기는 해도, 픽셀 단위로 제작된 대부분의 기존 웹 사이트에서 작동하지 않습니다. IE와 Safari 같은 브라우저에선 아예 해당 기능을 빼버리기까지 했습니다. 그렇기에 사용자들은 해당 옵션에 대해 모르거나 잘 사용하지 않았고, 웹 사이트에서 자체적으로 제공하는 폰트 사이즈 확대 기능이나 웹 브라우저에서 제공하는 간편한 자체 확대/축소 기능을 사용하게 됩니다. 실제로 국내 IT 대기업인 네이버나 카카오에서 퍼블리싱하는 웹 사이트에서도 픽셀 단위를 더 많이 사용하고 있고, 자체적인 폰트 사이즈 확대 기능을 제공합니다.

그럼 어차피 잘 안 쓰는 단위인데, 굳이 쓸 필요가 없지 않을까요? 하지만 분명히 이런 기능에 대한 수요는 많으며, 계속 늘고 있습니다. 스마트폰으로 인한 인터넷 보급 확대와 인구 고령화에 따라 웹 서핑 연령대는 점차 높아지고 있고, 나이가 들수록 노안으로 인해 작은 글씨는 읽기 힘들기 때문입니다. rem 단위는 이런 사용자의 접근성을 제공하기 위한 목적을 지니는 표준이므로, 웹 사이트가 자체적인 확대/축소 기능을 제공하기에 앞서서, rem 단위를 사용하여 일차적으로 접근성 지원을 하면 좋을 것입니다. 그런 웹 사이트가 많아질수록, 웹 브라우저에서도 해당 설정을 좀 더 사용자에게 드러내고, Safari 같은 브라우저도 해당 기능을 지원하게 될 확률이 커지리라 생각합니다.

이 글을 보고 나서도 폰트 사이즈에 픽셀 단위를 사용하는 것은 괜찮습니다. 다만 rem 단위가 무엇이고, 왜 필요한지 알아가시는 것만으로 좋겠습니다. rem 단위를 적극적으로 사용하기까지 하시면 더할 나위 없이 좋습니다.

참고한 글

EM vs REM vs PX – Why you shouldn’t “just use pixels”

PX, EM or REM Media Queries?

EM-based media queries are based on…

Making sense of units in CSS Media Queries (in the year 2019)

관련 글

최근 글