기준 CSS 기능을 사용한 반응형 및 유동적 서체

게시일: 2025년 12월 16일

반응형 웹 디자인은 다양한 브라우저, 표시 영역 크기, 기기, 사용자 환경설정에서 보기 좋고 잘 작동하는 웹사이트를 구축하는 접근 방식입니다. 타이포그래피에 적용할 때 중심 관심사는 브라우저 너비에 따라 font-size를 조정하는 것입니다. 이는 line-heightmargin와 같은 간격 값에도 영향을 미칠 수 있습니다.

디자이너는 브라우저에서 사용할 수 있는 공간을 고려하고 그에 따라 서체를 조정하는 것이 좋습니다. 또한 다양한 사용자는 Google이 알 수 없는 개인적인 상황에 따라 여러 기기에서 다양한 font-size 요구사항을 가질 수 있다는 점도 기억해야 합니다. 따라서 최종 결과에 대한 사용자 제어를 빼앗는 행위는 위험합니다. 웹을 탐색하는 동안 글꼴 크기에 영향을 미칠 수 있는 두 가지 기본 입력이 있습니다.

  • 모든 웹사이트에서 기본 font-size 환경설정을 제공합니다.
  • 사이트별로 확대 또는 축소

이 데모의 목표는 브라우저의 표시 영역 크기와 사용자 입력에 모두 반응하는 서체를 만드는 것입니다. 하지만 서체가 뷰포트에 더 많이 반응할수록 사용자 환경설정에 덜 반응한다는 점을 이해해야 합니다. 반응형 서체를 구현하는 경우 신중하게 구현하고 결과가 여전히 액세스 가능한지 테스트하는 것이 중요합니다.

사용자 환경설정을 기반으로 기본 font-size 협상

온라인에서 서체를 정의하는 첫 번째 단계는 사용자의 font-size 환경설정을 기반으로 초기 글꼴 크기를 협상하는 것입니다. 이 폰트는 페이지에 표시되는 대부분의 텍스트에 사용되며, 제목과 같은 다른 폰트 크기의 기준으로 사용됩니다. 여기서 가장 간단한 옵션은 조정 없이 1em를 사용하여 사용자에게 전체 제어 권한을 부여하는 것입니다. 다른 font-size 값을 설정하지 않으면 1em는 사용자 환경설정을 나타냅니다. 반대로 font-size를 픽셀이나 기타 절대 단위 (심지어 표시 영역 관련 단위)로 설정하면 사용자가 완전히 재정의되므로 피해야 합니다.

하지만 사용 사례에 따라 다른 서체가 필요합니다. 큰 텍스트로 된 기사는 읽기 쉬운 반면, 데이터가 많은 사이트는 작은 텍스트로 된 더 콤팩트한 디자인이 필요할 수 있습니다. 어떤 경우든 디자인에 적합한 기본값을 제안하면서도 사용자가 고유한 상황에 따라 결과를 조정할 수 있도록 허용하는 것이 좋습니다.

옵션 1: 가정을 기반으로 배수 계산

일반적인 절충안은 사용자 기본 font-size에 상대적으로 em 또는 % 단위로 조정된 font-size를 정의하는 것입니다. 일반적으로 이 접근 방식은 브라우저가 16px 기본값을 제공하고 대부분의 사용자가 해당 기본값을 그대로 유지한다는 가정에서 시작됩니다. 사이트에 20px 글꼴 크기가 더 적합하다고 생각되면 일반적으로 1.25em 또는 125%font-size이 원하는 결과를 제공합니다.

html {
  /* 20px preferred, 16px expected: 20/16 = 1.25 */
  font-size: 1.25em;
}

여기에서 calc() 함수를 사용하여 수학을 표시할 수도 있지만 방정식(목표 크기를 예상 크기로 나눈 후 1em을 곱한 값)을 알아야 합니다.

html {
  font-size: calc(20 / 16 * 1em);
}

이제 기본값이 사용자의 환경설정과 관련이 있으므로(이 경우 사용자의 환경설정의 1.25배) 환경설정이 더 크거나 작은 사용자는 결과에 영향을 미칠 수 있습니다. 하지만 개발자와 사용자가 모두 20px 기본값을 요청했는데 결과가 25px(조정된 기본값에 1.25를 곱한 값)이 된다면 이상할 수 있습니다. 아무도 요청하지 않은 크기이기 때문입니다.

옵션 2: clamp()가 작업을 처리하도록 허용

더 미묘한 접근 방식은 수학 없이 CSS 비교 함수를 사용하는 것입니다. 1em이 16px와 같다고 가정하고 px에서 em로 신뢰할 수 없는 변환을 수행하는 대신 1em를 사용자 환경설정을 참조하는 변수로 생각할 수 있습니다. 1em가 나타내는 픽셀 값과 관계없이 max(1em, 20px)font-size는 항상 디자인 환경설정 (20px)과 사용자 환경설정 (1em) 중 더 큰 값을 반환합니다. 따라서 사용자는 더 큰 글꼴 크기를 선택할 수 있지만 더 작은 글꼴 크기는 선택할 수 없습니다.

clamp() 함수로 전환하면 사용자가 선호하는 크기가 선택한 기본값과 너무 멀어질 때 양방향으로 크기를 조정할 수 있습니다. 예를 들어 clamp(1em, 20px, 1.25em)font-size는 사용자 기본값보다 크지만 기본값의 125%을 초과하지 않는 한 기본적으로 20px로 설정됩니다.

이렇게 하면 디자인이 사용자 환경설정에 가까운 경우 디자인이 우선 적용되지만 사용자 환경설정이 지정된 범위를 벗어나는 경우 사용자가 우선 적용됩니다. 전환 계산이 없고, 사용자 환경설정 크기에 관한 가정이 없으며, 디자이너 값과 사용자 값을 곱하지 않습니다.

html 요소에서 이를 루트 font-size로 설정하면 이제 협상된 기본 크기로 사이트 어디에서나 1rem를 참조할 수 있습니다.

대응성 추가

font-size가 뷰포트에 반응하도록 하려면 미디어 쿼리 (또는 컨테이너 쿼리) 중단점을 추가하면 됩니다. 예를 들어 화면 크기에 따라 고정된 값을 변경할 수 있습니다.

html {
  font-size: clamp(1em, var(--base-font-size, 16px), 1.25em);
  @media (width > 30em) { --base-font-size: 18px; }
  @media (width > 45em) { --base-font-size: 20px; }
}

정적 기본값에 뷰포트 또는 컨테이너 단위를 추가하는 방법도 있습니다.

html {
  font-size: clamp(1em, 16px + 0.25vw, 1.25em);
}

vw (표시 영역 너비) 또는 vi (표시 영역 인라인 크기) 단위는 사이트를 렌더링하는 브라우저 부분인 전체 표시 영역의 1% 를 나타냅니다. 마찬가지로 cqwcqi 단위는 페이지의 인라인 크기 컨테이너의 1% 를 나타냅니다. 자세한 내용은 컨테이너 쿼리 및 단위 데모를 참고하세요.

이 접근 방식은 미디어 또는 컨테이너 중단점에서 한 값에서 다른 값으로 점프하는 대신 font-size의 변경사항이 다양한 뷰포트 너비에 걸쳐 일정하므로 유연한 타이포그래피라고도 합니다. 하지만 전환의 부드러움에 주의를 빼앗기지 마세요. 이러한 구분은 일반적으로 창 크기를 부드럽게 조정하는 경우 테스트에서만 표시됩니다. 이 효과는 사용자에게 거의 표시되지 않습니다. 사용자는 브라우저 크기나 확대/축소 수준을 정기적으로 변경할 수 있지만, 중단점과 표시 영역 단위의 차이를 확인하려면 느리고 유연한 방식으로 조정해야 합니다. 크기 조절 후 결과가 아닌 전환에만 영향을 미칩니다.

유연한 글꼴 크기의 주요 장점은 중단점을 수동으로 계산하거나 지정할 필요가 없어 모든 크기에서 보간된 결과를 제공한다는 것입니다. 시작점 (16px)과 변경률 (0.25vw은 뷰포트가 100px 증가할 때마다 font-size0.25px 증가함) 및 최소값과 최대값만 설정합니다. 뷰포트가 1000px 너비인 경우 font-size16px + 2.5px 또는 18.5px가 되지만 이 계산은 브라우저에서 완전히 처리합니다. 이는 데모에서 사용된 접근 방식으로, cqi 단위를 사용하여 컨테이너 기반 반응형을 보여줍니다. 정의된 컨테이너가 없는 루트 (html) 요소에 사용되는 경우 cqi 단위는 여전히 뷰포트 크기를 나타냅니다.

특정 표시 영역 크기에서 지정된 font-size를 기준으로 생각하는 것을 선호한다면 좀 더 명확한 직접 미디어 쿼리 접근 방식을 사용하는 것이 좋습니다. 의도한 중단점을 기반으로 표시 영역 단위를 계산하려고 하면 복잡해집니다. 많은 사용자가 서드 파티 도구에서 값을 복사하여 붙여넣는 방식으로 이 작업을 수행하지만, 이렇게 하면 코드를 직접 이해하거나 변경하기가 훨씬 더 어려워집니다. 일반적으로 CSS에서는 의도를 가장 명확하게 표현하는 옵션이 가장 좋습니다.

경고: 뷰포트 변경이 항상 동일한 의미를 갖는 것은 아닙니다.

미디어 쿼리와 vi 단위는 서로 다른 방식으로 적용되지만 두 접근 방식 모두 동일한 표시 영역 측정에 기반합니다. 표시 영역이 600px 너비인 경우 100vw600px과 같아지고 (width > 500px) 미디어 쿼리 내의 스타일이 적용됩니다.

하지만 600px 너비의 표시 영역은 무엇을 의미할까요? 실제로 픽셀은 모든 상황에서 단일 의미를 갖는 고정된 크기가 아닙니다. 픽셀 수가 적은 뷰포트가 휴대전화와 같은 작은 화면이나 좁은 브라우저 창에 표시되는 것은 당연하지만, 이는 신뢰할 수 있는 가정은 아닙니다. 실제로 확대하고 브라우저 창을 작게 만드는 것은 측정된 표시 영역 너비에 동일한 영향을 미칩니다. 한 작업 (확대/축소)은 픽셀 크기를 변경하고 다른 작업 (크기 조절)은 브라우저 자체의 크기를 변경하지만 둘 다 브라우저 너비에 걸쳐 있는 픽셀 수를 변경합니다. 표시 영역 측정에서 얻을 수 있는 것은 현재 픽셀 크기와 현재 브라우저 창 간의 관계입니다.

사용자에게는 확대/축소와 크기 조절이 매우 다른 용도로 사용됩니다. 확대/축소 수준을 변경하는 사용자는 페이지의 콘텐츠를 더 크게 또는 더 작게 만들려고 하지만 브라우저의 크기를 조절하는 사용자는 여러 화면에서 공간을 관리할 뿐입니다. 사용자 의도는 다르지만 CSS 측정 결과는 동일합니다. 창이 작아지거나 픽셀이 커지면 브라우저 너비에 걸쳐 있는 픽셀 수가 줄어듭니다.

이러한 단절로 인해 반응형 서체를 신뢰할 수 없게 됩니다. 텍스트가 표시 영역 또는 컨테이너에만 기반하여 크기가 조정되도록 설정된 경우 사용자 확대/축소는 영향을 미치지 않습니다.

표시 영역 상대 단위의 값을 1vw 또는 100vw로 변경하면 글꼴 크기와 표시 영역 간의 정확한 관계가 변경됩니다. 1vw 글꼴은 표시 영역 크기의 100px마다 1px만큼 커지지만 100vw 글꼴은 표시 영역과 크기가 정확히 동일합니다. 이 값을 변경하여 브라우저에 비해 글꼴이 더 느리거나 빠르게 커지도록 할 수 있습니다. 하지만 뷰포트 관련 값은 사용자가 확대 또는 축소할 때 일정하게 유지되므로 사용자 컨트롤에 전혀 반응하지 않습니다.

마찬가지로 1vw100vw 모두 사용자 기본값 font-size를 고려하지 않습니다.

font-size에 뷰포트 또는 컨테이너 상대 단위를 단독으로 사용하는 것은 항상 사용자에게 적대적입니다. font-size이(가) 컨테이너에 완전히 반응하는 경우 사용자 기본값이나 조정에도 반응할 수 없습니다. 최선의 의도와 보호 조치를 취하더라도 사용자로부터 최종 font-size 제어 권한을 박탈하는 것은 피해야 합니다. 이는 사용자 경험을 저해할 뿐만 아니라 법으로 요구되는 경우가 많은 접근성 가이드를 위반할 수도 있습니다. 구체적으로 웹 콘텐츠 접근성 가이드라인의 섹션 1.4.4에서는 '보조 기술 없이 텍스트의 크기를 최대 200%까지 조정할 수 있어야 합니다'라고 요구합니다.

font-size 값이 확대/축소에 반응하도록 하는 방법

뷰포트 상대 font-size가 확대/축소에 반응하도록 하려면 뷰포트 상대 값을 다른 값에 대한 조정으로 적용해야 합니다. CSS에서는 calc() 함수 또는 min(), max(), clamp()과 같이 계산을 허용하는 다른 수학 함수를 사용하여 이를 구현할 수 있습니다. calc(16px + 1vw)font-size는 표시 영역 크기와 픽셀의 현재 (확대/축소 관련) 크기를 모두 기반으로 합니다. vw 단위는 확대/축소의 영향을 받지 않지만 기본값은 영향을 받습니다.

결과적으로 표시 영역 크기와 사용자 확대/축소 설정에 모두 반응하는 font-size가 생성됩니다. 사용자가 200%로 확대하면 기본값은 두 배 (32px)로 렌더링되지만 반응형 값은 변경되지 않습니다. 1000px 표시 영역은 처음에 16px + 10px = 26pxfont-size를 제공하지만 200% 확대/축소에서는 글꼴 크기가 160%을 약간 넘는 42px로만 커집니다. 심각한 문제는 아닌 것 같지만 font-size가 뷰포트를 기반으로 할수록 확대/축소의 효과는 떨어집니다.

작은 화면에서는 font-size가 기본 픽셀 값에서 주로 발생하며 확대/축소에 잘 반응합니다. 하지만 화면이 클수록 뷰포트 크기가 렌더링된 글꼴 크기에서 차지하는 비율이 커지므로 확대/축소의 효과가 줄어듭니다. 이는 500% 확대/축소 (대부분의 브라우저에서 최대치)가 WCAG 1.4.4에서 요구하는 글꼴 크기 200% 증가를 더 이상 제공할 수 없는 시점에서 특히 위험해집니다. 하지만 그 전에도 확대/축소가 효과가 없으면 답답할 수 있습니다.

글꼴 크기 및 확대/축소 효과와 뷰포트 너비를 보여주는 그래프 글꼴 크기는 `calc(17px + 2.5vw)`로 계산되며, 표시 영역 너비에 따라 선형으로 증가합니다. 가능한 최대 확대/축소를 나타내는 500% 확대/축소 선을 보면 표시 영역 너비가 증가함에 따라 확대/축소의 효과가 떨어지며 표시 영역 너비가 2040px을 초과하면 글꼴 크기가 200% 증가하지 않습니다.
가로축은 표시 영역 크기를 나타내며, 0~2600px 너비입니다. font-size의 세로축도 픽셀 단위이며 calc(17px + 2.5vw)의 결과를 보여줍니다. 500% 확대/축소 선은 동일한 뷰포트 너비 가로축을 사용하지만 세로축을 백분율로 처리합니다.

그래프의 왼쪽 가장자리 (0 표시 영역 너비)에서 500% 확대/축소는 완전히 효과적입니다. 하지만 브라우저 크기가 커지면 효과가 빠르게 떨어지고 (확대/축소 불가능한) 뷰포트 단위가 font-size에서 더 큰 요인이 됩니다. 브라우저의 너비가 2040px인 경우 최대 500% 확대/축소로 글꼴 크기를 200%만큼만 늘릴 수 있습니다. 이 시점 이후에는 200%의 유효 글꼴 확대/축소가 더 이상 불가능합니다.

이 계산을 최소값과 최대값이 있는 clamp() 함수로 이동하면 확대/축소 가능한 텍스트를 보장하는 경계를 적용할 수 있습니다. 맥스웰 바비안에 따르면 다음과 같습니다.

최대 글꼴 크기가 최소 글꼴 크기의 2.5배 이하이면 텍스트는 모든 최신 브라우저에서 항상 WCAG SC 1.4.4를 통과합니다.

@media@container 쿼리는 vwcqw 단위와 동일한 측정값을 기반으로 하므로, 중단점을 사용하여 글꼴 크기를 변경할 때도 동일한 논리가 적용됩니다. 크기 증가가 너무 급격하면 확대/축소가 효과가 없습니다. 다음 시각화에서 이러한 값이 어떻게 상호작용하는지 실험해 볼 수 있습니다.

font-size 값이 사용자 기본값에 반응하도록 하는 방법

하지만 calc(16px + 1vw)는 여전히 사용자 기본 글꼴 설정에 응답하지 않습니다. 이를 위해 px 대신 em 또는 rem 단위를 사용하여 기준(최솟값 및 최댓값)을 설정할 수 있습니다. 이 모든 것을 합치면 연결된 데모와 일치하는 친숙한 결과가 표시됩니다.

html {
  font-size: clamp(1em, 17px + 0.24vw, 1.125em);
}

참고:

  • 최소값과 최대값 모두 사용자 환경설정을 기반으로 하고 확대/축소에 반응하는 em 단위를 사용합니다.
  • 추가 vw 값은 최소한으로 유지되므로 확대/축소에 너무 큰 영향을 미치지 않습니다.
  • 최대 크기 (1.125em)는 최소 크기 (1em)의 2.5배 미만이므로 항상 200%의 효과적인 font-size 값을 사용할 수 있습니다.

pow()이 적용된 서체 스케일

대부분의 디자인은 두 개 이상의 글꼴 크기를 사용합니다. 서체 스케일은 여러 글꼴 크기 간의 관계를 설명합니다. 이는 기본 크기와 다른 크기를 계산하는 일련의 곱셈으로 표현할 수 있습니다. CSS는 사용자의 글꼴 크기 환경설정 또는 기본값인 16px을 나타내는 medium 키워드와 관련된 내장 서체 스케일을 제공합니다. 전체 키워드 스케일은 다음과 같습니다.

  • xx-small: 3/5 (0.6)
  • x-small: 3/4 (0.75)
  • small: 8/9 (0.89)
  • medium: 1 (다른 크기에 곱해지는 기본 크기)
  • large: 6/5 (1.2)
  • x-large: 3/2 (1.5)
  • xx-large: 2/1 (2)
  • xxx-large: 3/1 (3)

이 스케일은 루트 font-size가 아닌 사용자 기본값과 관련이 있으므로 사이트의 루트 font-size를 변경하면 제대로 작동하지 않습니다. 대부분의 작성자는 맞춤 속성을 사용하여 유사한 유형의 스케일을 다시 만듭니다. 티셔츠 사이즈 이름을 동일하게 사용하기도 하고 수학적 스케일에서 위아래로 일련의 단계를 선호하기도 합니다. 일반적인 비율을 기반으로 이러한 스케일을 생성하는 서드 파티 도구가 많이 있습니다. 대부분 서양 음악 스케일에서 차용했습니다.

html {
  /* musical ratios */
  --minor-second: calc(16/15);
  --major-second: calc(9/8);
  --minor-third: calc(6/5);
  --major-third: calc(5/4);
  --perfect-fourth: calc(4/3);
  --augmented-fourth: sqrt(2);
  --perfect-fifth: calc(3/2);
  --major-sixth: calc(5/3);

  /* the golden ratio*/
  --golden-ratio: calc((1 + sqrt(5)) / 2);
}

하지만 CSS에서 자체 스케일을 만드는 데 외부 도구가 필요하지 않습니다. 새로운 pow() 함수가 1rem를 자체 기본 크기로 사용하여 스케일을 생성할 수 있습니다.

html {
  /* choose a ratio */
  --scale: 1.2;

  /* generate the scale using pow() */
  --xx-small: calc(1rem * pow(var(--scale), -0.5));
  --x-small: calc(1rem * pow(var(--scale), -0.25));
  --small: calc(1rem * pow(var(--scale), -0.125));
  --medium: 1rem;
  --large: calc(1rem * pow(var(--scale), 1));
  --x-large: calc(1rem * pow(var(--scale), 2));
  --xx-large: calc(1rem * pow(var(--scale), 3));
  --xxx-large: calc(1rem * pow(var(--scale), 4));

  /* change the ratio for different viewport sizes */
  @media (width > 50em) {
    --scale: var(--perfect-fourth);
  }
}

전체 단계를 사용하여 크기를 일관되게 유지할 필요는 없습니다. 실제로 일반적인 12pt 서체 스케일은 단계당 대략 5개의 분수를 사용합니다. 여기에서 큰 크기는 스케일의 전체 단계를 사용하는 반면 작은 크기는 분수를 사용하여 더 느린 속도로 스케일링합니다.

CSS 믹스인 및 함수를 사용하면 이 로직을 더욱 간결하게 만들 수 있으며, progress()와 같은 다른 기본 제공 도구를 사용하면 한 값에서 다른 값으로 유연하게 조정되는 스케일을 더 쉽게 만들 수 있습니다. 하지만 이러한 기능은 이 데모의 범위를 벗어납니다.

인페이지 컨테이너 크기에 응답

vw 또는 vi 대신 cqi 단위를 사용하여 컨테이너 쿼리에서 이러한 모든 계산이 작동하도록 할 수 있지만, 모든 유형 설정 컨테이너가 1rem로 사용자 환경설정을 다시 참조할 수 있도록 html 요소에 사용자 font-size를 그대로 두는 것도 도움이 됩니다. 데모에서는 전체 서체 스케일이 전역 서체의 루트 html 요소가 아닌 body에 적용된 후 type-set 속성이 있는 모든 요소의 컨테이너 크기에 따라 재설정됩니다.

이는 항상 컨테이너 상대 글꼴 크기와 상충됩니다. 컨텍스트의 각 요소에 대해 더 유연한 글꼴 크기를 설정할 수 있지만 페이지 전체의 일관성은 떨어집니다. 어떤 것이 더 중요한지는 사용 사례의 세부사항에 따라 다릅니다. 유연한 서체 자체는 트레이드오프이므로 확대/축소와 같은 사용자 제어가 덜 효과적이라는 점을 기억하세요.

반응형 서체와 서체 스케일은 디자이너에게 유용한 도구이지만, 필요하지 않다면 더 복잡하게 만들 필요는 없습니다. 사용자 기본값과 내장 유형 스케일도 좋은 선택입니다. 하지만 반응형 (또는 유연한) 서체를 선택하는 경우 다양한 사용자 기본값 및 확대/축소 설정과 관련하여 결과가 어떻게 작동하는지 테스트해야 합니다. 자, 그러면 동영상을 시청해 볼까요?