Early Riser
생각정리
Early Riser
전체 방문자
오늘
어제
  • 분류 전체보기 (128)
    • JS (19)
    • React (33)
    • React Native (2)
    • Library, Tool (13)
    • CSS (2)
    • Algorithm (40)
    • Computer Science (3)
    • 회고 (3)
    • AI (13)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 글쓰기

공지사항

인기 글

태그

  • global minima
  • 자바스크립트
  • javascript
  • RNN
  • BFS
  • dfs
  • 구현
  • 백트래킹
  • lightgbm
  • react
  • LGBM
  • 손실함수
  • 프로그래머스
  • 부스트캠프 합격
  • useEffect
  • 밑바닥
  • 부스트캠프 9기
  • 부스트캠프 합격 후기
  • 파이썬
  • useState
  • 비동기
  • 백준
  • 논문리뷰
  • 오늘의불경
  • js
  • boosting
  • local minima
  • 알고리즘
  • 완전탐색
  • 딥러닝

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Early Riser

생각정리

CSS

WCAG를 준수하는 반응형 text 만들기

2026. 2. 2. 16:46

1. 서론

 반응형 텍스트를 구현할 때 과거에는 Media Query 분기점을 하드코딩했으나, 새로 추가된 CSS Comparison Functions(비교 함수)를 활용하면 하나의 수식으로 해결 가능하다.

 이때 단순히 Viewport 너비에 따라 Font Size를 가변적으로 계산해서는 안 된다. WCAG를 준수하기 위해 텍스트 렌더링은 다음 두 가지 조건을 통과해야 한다.

  • 1. WCAG 1.4.4 Resize Text. 보조 기술 없이 텍스트를 최대 200%까지 크기 조정할 수 있어야 한다. 여기서 Input(입력값)이 브라우저의 Zoom 레벨이라는 점이 중요하다. 사용자가 브라우저를 확대했을 때, 렌더링 된 텍스트는 그에 비례하여 물리적으로 커져야 한다. Smashing Magazine의 'Addressing Accessibility Concerns With Using Fluid Type'에 따르면, 이를 검증하는 가장 간단한 규칙은 다음과 같다: Maximum value(최대값)는 Minimum value(최소값)의 2.5배 이하여야 한다. 최대값이 최소값의 2.5배를 넘지 않는다면 대부분의 브라우저에서 200% 확대 조건을 충족한다.
  • 2. WCAG 1.4.10 Reflow. 이는 320px에서 콘텐츠를 볼 때, Horizontal Scroll(수평 스크롤)이 발생하지 않아야 한다는 조건이다. 즉, Viewport 너비가 320px까지 줄어들면 텍스트 크기도 적절히 줄어들거나, 공간에 맞춰 다음 줄로 이동 되어야 한다.

2. 본문

 반응형 텍스트 구현 시 가장 흔히 발생하는 Anti-pattern은 font-size: 5vw와 같이 Viewport Unit을 단독으로 사용하는 것이다.

vw는 Viewport 너비의 1%를 의미한다(eg. font size 100vw일때 viewport 100px 증가시 폰트는 1px 증가). 이렇게 단독으로 사용하면 브라우저를 Zoom할 때 Viewport의 물리적 동작에서 문제가 발생한다. 사용자가 화면을 Zoom In 하면, 브라우저는 CSS Pixel을 키우지만 Viewport 내의 상대적 비율은 유지하려 한다. 이때 순수 vw 단위로 설정된 텍스트는 Viewport 너비에 종속되므로, 사용자가 확대를 요청해도 Font Size가 고정된 것처럼 동작한다. 이는 wcag 1.4.4의 위반이다.

 따라서 우리는 clamp() 함수를 사용하여 사용자의 기본 설정인 rem과(혹은 다른 non-view port value) Viewport 가변성인 vw를 합성해야 한다. 이때 Linear Interpolation(선형 보간법)을 적용하기 위해서는 '변화가 시작되는 지점'과 '끝나는 지점'을 정의해야 하는데, 여기서 Typography의 가독성 이론이 필요하다.

2.1 최적의 가독성을 위한 기준 설정

 텍스트의 크기가 변할때 읽기 좋은 줄 길이를 유지하는 것이 반응형의 핵심이다. 'Fluid Headings'에 따르면, 이 아이디어는 Body copy(본문)의 권장 글자 수에서 시작된다. 출처에 따라 40자에서 80자 사이가 권장되는데, 해당 아티클에서는 보통 그 중간값인 60자를 최적의 읽기 길이(Optimal reading length)로 설정한다.

이는 광고 업계 표준과도 일맥상통한다. Google Ads 역시 English의 경우 본문 90자, 제목 45자까지 표시를 권고하며(Non-English는 그 절반), 이는 한정된 공간에서의 가독성을 고려한 수치다. 우리는 이 60자(60ch)를 기준으로 Max Viewport를 설정하여, 텍스트가 가장 보기 좋은 너비를 유지하도록 수식을 설계해야 한다.

2.2 clamp() 함수의 Runtime 동작 해석 및 적용

 우리는 Zoom에 반응하는 고정 단위(rem)와 Viewport에 반응하는 가변 단위(vw)를 합산해야 한다. 이를 수학적으로 표현하면 1차 함수 y = ax + b와 같다.

CSS 구현 예시는 다음과 같다.

.text-heading {
  --min-font: 2;
  --max-font: 3;
  --min-viewport: 20; /* 320px */
  --max-viewport: 60; /* 960px */

  /* 1. Slope (기울기 m) = (y2 - y1) / (x2 - x1) */
  --slope: calc((var(--max-font) - var(--min-font)) / (var(--max-viewport) - var(--min-viewport)));

  /* 2. Y-Intercept (y절편 b) = y1 - (m * x1) */
  --intercept: calc(var(--min-font) * 1rem - (var(--slope) * var(--min-viewport) * 1rem));

  /* 3. Apply Function: y = mx + b */
  font-size: clamp(
    var(--min-font) * 1rem,
    (var(--slope) * 100vw) + var(--intercept),
    var(--max-font) * 1rem
  );
}

 이 코드가 어떻게 동작하는지 살펴보자. Viewport Unit이 반드시 Non-viewport Unit과 함께 사용되어야 하고, 위 코드에서 --intercept가 non-viewport unit이다.

 

  • Zoom In 시: rem 기반인 --intercept 값이 커진다. 이 상수항이 존재하므로, Viewport 너비와 무관하게 Font Size는 기저 값에 비례하여 확실하게 커진다. (WCAG 1.4.4 충족)
  • Viewport Resize 시: vw 항인 --slope에 의해 Font Size가 선형적으로 변한다. 320px(20rem) Viewport에서도 수식은 정확히 최소값인 2rem을 반환하므로 가독성이 유지된다. (WCAG 1.4.10 충족)

 

참고 문헌

https://blog.damato.design/posts/fluid-headings/
https://www.smashingmagazine.com/2023/11/addressing-accessibility-concerns-fluid-type/
https://web.dev/articles/baseline-in-action-fluid-type

'CSS' 카테고리의 다른 글

Staking Context와 Position, z-index 그리고 React Portal  (0) 2025.11.21
    'CSS' 카테고리의 다른 글
    • Staking Context와 Position, z-index 그리고 React Portal
    Early Riser
    Early Riser
    2년차 프론트엔드 개발자입니다. https://github.com/EarlyRiser42

    티스토리툴바