(번역) 웹에서 텍스트 크기 조정에 대해 다시 생각하기
원문: https://medium.com/airbnb-engineering/rethinking-text-resizing-on-web-1047b12d2881
에어비앤비는 큰 글자가 필요한 호스트와 게스트를 위한 웹 접근성 개선에 상당한 진전을 이루었습니다.
이번 글에서는 아래 주제에 대해 자세히 살펴봅니다.
- 브라우저 확대/축소 기능에만 의존할 때 모바일 웹에서 발생하는 문제
- 모든 프런트엔드 엔지니어의 워크플로에 영향을 미치는 변경 사항을 도입할 때의 어려움
- 접근성 개선 사항을 도입한 후 나타난 이점
에어비앤비는 웹 접근성을 개선하는 것을 최우선 과제로 삼고 있으며, 웹 콘텐츠 접근성 지침(Web Content Accessibility Guidelines, WCAG)을 준수하며 개발하고 있습니다. 접근성 문제가 자주 발생하는 영역 중 하나는 WCAG 1.4.4 텍스트 크기 조정(레벨 AA)입니다. 텍스트 크기 조정이라고 부르는 이 가이드라인은 교정 가능 여부와 관계없이 시력이 낮은 사람(예: 안경 또는 콘택트렌즈 착용)에게 특히 유용합니다. 이 표준은 텍스트 크기가 원래 크기의 200%(2배)로 확대되어도 웹 콘텐츠와 기능이 유지되어야 한다고 명시하고 있습니다. 사이트가 이 가이드라인을 충족하도록 하는 것은 모든 사용자의 접근성을 개선하기 위한 지속적인 노력의 중요한 부분입니다.
이 글에서는 이 가이드라인의 중요성, 사이트 문제를 분석한 방법, rem 단위 사용의 기술적 이점, 접근 방식을 결정한 과정, 마주쳤던 크로스 브라우저 지원 문제, 텍스트 크기 조정에 대한 보고 건수를 줄임으로써 얻은 이점에 대한 조사를 살펴봅니다.
시각 장애가 있는 사용자 요구 충족
“40세 이상의 미국인 9천만 명이 시력 및 안과 질환을 앓고 있습니다. 이는 5명 중 3명 이상입니다.”
시력이 크게 저하된 경험이 있는 사람들이 에어비앤비 홈페이지가 어떻게 보일지 생각해 보죠. 아래 그림과 같이 글자를 편안하게 읽을 수 없게 됩니다.
브라우저 확대
접근성 문제를 더 잘 이해하기 위해 브라우저 확대/축소 기능이 어떻게 작동하는지 살펴보겠습니다. 창 내의 모든 콘텐츠의 크기를 조정하기 위해 Command / Ctrl + 또는 Command/Ctrl과 같은 키보드 단축키에 이미 익숙할겁니다. 확대/축소 수준을 100% 이상으로 높이면 뷰포트의 높이와 너비는 비례적으로 줄어들고 콘텐츠는 더 큰 창에 맞게 확대됩니다.
저희는 접근성 테스트 전략의 일환으로 브라우저 확대/축소를 사용하여 데스크톱과 모바일 크기 모두에서 페이지의 사용성을 테스트 했습니다. 데스크톱 테스트 결과, 사이트 전체에 걸쳐 반응형 웹 방식을 적용한 페이지가 200% 확대 수준에서 비교적 잘 작동하는 것으로 나타났습니다. 모바일 웹과 비교했을 때 전반적인 사용자 경험에서 문제가 더 적게 발생했습니다.
데스크톱에서는 잘 작동하지만 작은 디스플레이에서는 브라우저 확대/축소의 한계가 두드러집니다. 모바일에서 콘텐츠의 크기를 조정하려면 원본의 절반 너비와 절반 높이에 맞춰야 합니다. 이렇게 되면 텍스트와 UI 요소를 읽고 상호작용하기가 매우 어려워져 접근성 문제가 심각하게 발생할 수 있습니다. 오른쪽 이미지에서 볼 수 있듯이 스크롤을 하지 않으면 한 화면의 공간 내에서 하나의 목록도 볼 수 없기 때문에 불편한 경험을 하게 됩니다.
글꼴 크기 조정
글꼴 크기 조정은 전체 페이지 확대/축소와 독립적으로 텍스트 크기를 조정하는 기능을 설명할 때 사용하는 용어입니다. 모든 콘텐츠의 크기를 비례적으로 조정하는 브라우저 확대/축소와 달리 글꼴 크기 조정은 페이지의 텍스트 요소에만 적용됩니다. 따라서 사용자는 나머지 콘텐츠의 레이아웃이나 반응성에 큰 영향을 주지 않고 글꼴 크기를 원하는 읽기 크기로 지정할 수 있습니다.
글꼴 크기 조정은 사용자가 선호하는 크기에 따라 글꼴 크기를 조정할 때 사용하는 용어이기도 합니다. 확대/축소와 달리 이 설정은 모든 사이트에 적용됩니다. 아래는 글꼴 크기 조정이 화면의 텍스트에만 적용되는 예시로, 모든 콘텐츠가 아닌 텍스트의 크기만 증가하는 것을 보여줍니다.
비디오 설명: 에어비앤비 텍스트는 아크 브라우저에서 글꼴 크기를 설정하여 16픽셀에서 32픽셀까지 크기를 조정할 수 있습니다.
이 독립적인 글꼴 크기 조정 개념은 블로그 게시물 ‘에어비앤비 동적 글꼴 조정 지원’에서 설명한 것처럼 iOS의 동적 글꼴 기능과 유사합니다. 동적 글꼴을 사용하면 사용자가 시스템 전체에 선호하는 텍스트 크기를 설정하면 호환되는 모든 앱에서 글꼴 크기가 자동으로 조정됩니다.
iOS의 기존 접근성 전략을 고려할 때, 글꼴 크기 조정(vs 확대 크기 조정)을 웹 접근성 접근 방식에 통합하는 것은 플랫폼간 접근 방식을 균형있게 맞추기 위한 자연스러운 다음 단계였습니다.
px, em vs rem 이해하기
이제 모바일 웹에서 글꼴 크기 조정이 강력한 이유를 이해했으니 글꼴 크기 조정을 지원하기 위해 특정 CSS 길이 단위를 선택하는 이유에 초점을 맞춰보겠습니다. 이 글에서는 px, em 및 rem에만 초점을 맞출 것이지만 다른 단위도 있습니다. CSS 길이 단위는 웹 페이지에서 텍스트 및 기타 요소의 크기가 정해지는 방식을 결정하기 때문에 글꼴 크기 조정과 관련이 있습니다. 일부 길이 단위는 고정되어 있어 사용자의 글꼴 크기 설정에 따라 변경되지 않는 반면, 다른 길이 단위는 상대적이어서 글꼴 크기에 따라 비례적으로 크기가 조정됩니다.
3가지 CSS 길이 단위와 글꼴 크기 조정과의 관계에 대해 자세히 살펴보겠습니다.
- px 단위는 웹에서 가장 일반적으로 사용되는 단위로, 이론적으로 화면의 1픽셀을 나타냅니다. 렌더링된 값이 변하지 않는 고정된 단위입니다.
- em 단위는 px단위와 다르게 상위 요소의 글꼴 크기를 기준으로 하는 상대적인 단위입니다. ‘em’이라는 이름은 전통적으로 글꼴 크기의 기준점으로 사용되던 특정 서체의 대문자 ‘M’의 너비에서 유래했습니다. 1em 단위는 현재 글꼴 크기의 높이와 같으며 기본값은 약 16px입니다. em 단위는 비례적으로 크기가 조정되므로 상위 요소의 글꼴 크기에 영향을 받을 수 있습니다.
- “root em”의 줄임말인 rem 단위는 글꼴 크기에 비례한다는 점에서 em 단위와 비슷하지만 루트 요소(HTML 요소)만을 사용하여 글꼴 크기를 계산합니다. 즉, rem 단위는 글꼴 크기 조정 기능을 제공하지만 상위 글꼴 크기의 영향을 받지 않습니다.
글꼴 크기 조정에 필요한 제어 수준과 예측 가능성에 따라 em 단위와 rem 단위 중 하나를 선택하는 경우가 많습니다. em 단위를 사용할 수 있지만, 특히 복잡한 레이아웃에서는 글꼴 크기가 계단식으로 변경되어 관리하기 어려울 수 있습니다. 반면 rem 단위는 항상 루트 요소의 글꼴 크기를 기준으로 하기 때문에 글꼴 크기 조정에 대해 보다 일관되고 예측 가능한 접근 방식을 제공합니다.
이는 px, em 및 rem 단위의 다양한 글꼴 크기 조정 동작을 보여주는 코드펜 예시에서 확인할 수 있습니다. 앞서 언급한 에어비앤비 예시와 같이 글꼴 크기 조정이 중요한 요구 사항인 상황에서는 일관되고 유지 관리 가능한 글꼴 크기 조정 솔루션을 보장하기 위해 rem 단위를 사용하는 것이 더 안정적인 선택이 될 수 있습니다.
rem과 같은 상대 단위는 px와 같은 고정 단위를 사용할 수 있는 모든 곳에서 사용할 수 있습니다. 그러나 모든 속성에서 무분별하게 rem 단위를 사용하면 원치 않는 확대 동작이 발생하고 복잡성이 증가할 수 있습니다.
에어비앤비의 경우, 모든 요소의 크기를 비례적으로 조정하는 대신 글꼴 크기 조정에만 rem 단위를 우선적으로 사용하기로 결정했습니다. 이와 같은 타겟팅된 접근 방식 덕분에 레이아웃의 모든 측면을 스케일링할 때 발생할 수 있는 단점 없이 텍스트를 일관되게 조정할 수 있었습니다.
이 결정의 근거는 두 가지가 있습니다.
- rem 단위를 사용하여 모든 크기를 조정하는 것은 브라우저 줌과 유사하고 의도하지 않은 레이아웃 문제가 발생할 수 있었습니다.
- 모바일 친화적인 글꼴 크기 조정 솔루션을 제공하는 데 중점을 두었습니다. 글꼴 크기를 rem 단위로 지정함으로써 팀은 가장 중요한 콘텐츠인 텍스트의 크기를 적절하게 조정할 수 있었습니다.
디자이너와 개발자를 위한 원활한 전환 지원
픽셀 기반 값에서 rem 단위로 회사 전반의 CSS 관행을 변경하는 것은 특히 여러 팀에서 작업하는 경우 상당한 도전이 될 수 있습니다. 디자이너와 프런트엔드 개발자에게 새로운 접근 방식을 교육하고 기존의 픽셀 기반 값을 rem 단위로 변환하는 데 필요한 시간과 노력은 채택에 큰 장벽이 될 수 있습니다. 이 문제를 해결하기 위해 에어비앤비 팀은 단위 변환 프로세스를 최대한 자동화하여 새로운 rem 기반 시스템으로 보다 원활하게 전환할 수 있도록 하는 데 집중하기로 결정했습니다.
디자인 반복 작업 마찰 줄이기
디자이너가 새로운 단위를 생각하거나 웹 전용 변환을 도입해야 하는 대신 계속해서 픽셀 단위로 CSS를 작성하기로 결정했습니다. 이렇게 하면 팀이 처음부터 rem 단위를 사용하는 데 필요한 교육이 줄어듭니다.
디자인 팀과 함께 집중한 분야 중 하나는 글꼴 크기를 2배로 늘렸을 때 디자인이 어떻게 보일지 시뮬레이션할 수 있는 텍스트 리사이저 접근성 검사기를 활용하여 글꼴 크기를 조정하여 디자인을 테스트하기 시작한 것입니다. 이 도구는 디자인 프로세스 초기에 문제를 발견하는 데 도움이 되었습니다.
두 개의 CSS-in-JS 시스템의 복잡성 해결하기
에어비앤비는 React-with-Styles에서 Linaria를 사용하는 새로운 접근 방식으로 전환하는 과정에 있습니다. Linaria 도입이 빠르게 진행되는 동안 일관된 경험을 위해 두 가지 스타일링 시스템을 모두 지원해야 할 필요성을 인식했습니다. 서로 다른 두 가지 CSS-in-JS 시스템 사이의 변환을 관리하는 것은 또 다른 과제가 되었습니다.
Linaria
Linaria의 CSS 사용자 정의 프로퍼티에 대한 지원을 활용하여 팀은 기존 픽셀 기반 값을 rem으로 자동 변환하는 새로운 타이포그래피 테마 값을 만들 수 있었습니다. 이 접근 방식을 통해 팀은 새로운 rem 기반 테마 값을 중앙 집중식 방식으로 도입하여 하위 요소에 사용할 수 있게 되었습니다. 이를 통해 팀은 페이지 단위로 rem 값을 재정의할 수 있게 되어 전환 과정에서 필요한 유연성을 확보할 수 있었습니다.
import { typography } from './site-theme';
// 타이포그래피에 사용하는 CSS 변수를 순회하여 px에서 rem 단위로 변환합니다.
const theme: css`
${getCssVariables({ typography: replacePxWithREMs(typography) })}
// Changes from:
// - body-font-size: 16px;
// To
// - body-font-size: 1rem;
`;
// linaria에서 생성된 클래스 이름을 사용하여
// 이 구성 요소의 하위 항목에 대한 테마 변수를 재정의합니다.
const RemThemeLocalProvider: React.FC = ({ children }) => {
const cx = useCx();
return <div className={linariaClassNames.theme)}>{children}</div>;
};
이 접근 방식으로 대부분의 폰트 크기 조정 속성을 변환할 수 있었지만, 테마 외부에서 px 기반 값을 사용하는 코드 부분이 많았습니다. Linaria의 Post CSS 플러그인 지원 덕분에 이러한 부분을 비교적 쉽게 해결할 수 있었습니다. postcss-pxtorem을 활용하여 해당 값을 더 쉽게 대상으로 삼을 수 있었습니다. 우리는 허용 목록을 사용하여 이 변경 사항을 조심스럽게 초기 적용 페이지의 작은 부분에 적용했습니다.
프런트엔드 엔지니어가 px 단위를 사용해야 할 때를 대비해 예외 처리를 제공하는 것이 중요했습니다. 다행히도 아래와 같이 px 값의 대소문자를 다르게 하여 이를 제공할 수 있었습니다.
/* `px`은 `rem`으로 변환 */
.convert {
font-size: 16px; /* 1rem으로 변환 */
}
/* `Px` 또는 `PX`는 `postcss-pxtorem`에서 무시되지만 브라우저에서는 여전히 허용됩니다. */
.ignore {
font-size: 200px;
font-size: clamp(16px, 2rem, 32px);
}
React with Styles
프런트엔드 코드의 상당 부분이 여전히 react-with-styles를 사용하고 있어서, 이러한 경우에도 쉽게 변환할 수 있는 방법을 찾아야 했습니다. 이를 통해 우리는 변환 작업을 상당히 간단하게 만드는 간단한 고차 컴포넌트를 만들었습니다. 먼저 아래와 같이 withStyles 함수를 래핑하고 변환을 피할 수 있는 기능을 추가했습니다.
export const withRemStyles = (
styleFn?: Nullable<(theme: Theme) => Styles>,
options?: WithStylesOptions & { disableConvertToRemUnits?: boolean }
) => {
const disableConvertToRemUnits = getDisableConvertToRemUnits(options);
// 변환이 비활성화된 경우, 원본 withStyles 함수를 반환하면 됩니다.
if (disableConvertToRemUnits) {
return _withStyles(styleFn, options);
}
// 그렇지 않으면 원래 스타일 함수를 px를 rem으로 변환하는 새로운 함수로 래핑하세요.
return _withStyles((theme: Theme) => {
if (styleFn) {
const styles = styleFn(theme);
const remStyles = convertToRem(styles);
return remStyles;
}
return {};
}, options);
};
그런 다음 convertToRem이 키와 값을 살펴보고 글꼴 크기 속성 중 하나에 대해 변환된 값을 매핑합니다. 이를 통해 보다 간단한 방식으로 변환 프로세스를 자동화할 수 있었습니다.
컴포넌트 테스트 개선
두 가지 과제를 해결한 뒤 이제 컴포넌트 테스트를 통해 출시 전에 해결해야 할 주요 문제가 있는지 확인 했습니다. 컴포넌트 문서와 툴링에서는 글꼴 크기를 직접 설정하여 글꼴 크기 조정으로 테스트할 수 있는 내부 플러그인을 구축하여 보다 쉽게 테스트할 수 있도록 했습니다.
스크린샷 테스트는 시각적 회귀를 포착하는 데 도움이 되었습니다. 다양한 루트 글꼴 크기로 추가 스크린샷을 설정하는 기능을 추가함으로써 제품팀이 다양한 글꼴 크기에서 컴포넌트가 어떻게 보이는지 검토하는 데 도움이 되었습니다. 이를 위해 스크린샷을 캡처할 때 추가 글꼴 크기를 설정할 수 있도록 해 글꼴 크기를 조정하기 위해 새로운 컴포넌트 변형을 만들 필요가 없도록 했습니다.
모바일 사파리에서 글꼴 크기 조정
모바일 사파리에서 폰트 크기 조정을 지원하는 것은 더 어려웠습니다. 다른 브라우저와 달리 모바일 사파리에는 폰트 크기 환경설정이 없습니다. 하지만 애플은 자체 폰트인 -apple-system-body를 지원하기 시작했지만, 고려해야 할 중요한 사항이 있습니다.
macOS 하이 시에라(10.13) 이후 데스크톱 사파리에서도 글꼴 환경설정을 지원하지만, MacOS에서 쉽게 ‘글꼴 크기’를 구성할 수 있는 것은 아닙니다. 데스크톱 사파리에서 예기치 않은 동작이 발생할 수 있으므로 이를 방지하기 위해 @supports 문을 사용했습니다. 아래 코드는 모바일 사파리만 대상으로 합니다.
// Apple의 동적 폰트를 사용하려면 이 글꼴 모음을 사용해야 합니다.
// iOS/iPadOS만 대상으로 합니다.
@supports (font: -apple-system-body) and (-webkit-touch-callout: default) {
:root {
font: -apple-system-body;
}
}
또 다른 고려 사항으로는 ‘100%’ 기본 글꼴 크기를 선택하면 표준 글꼴 크기인 16px가 아니라 17px가 된다는 점이 있었습니다. 이는 매우 미묘한 차이이지만, 에어비앤비에서 달성하고자 하는 디자인 품질 기준에 있어 매우 중요한 문제입니다. 따라서 이 문제를 해결하기 위해 인라인 헤드 스크립트를 사용하여 값을 정규화하고 페이지 실행 초기에 배치함으로써 글꼴 크기가 변경되는 것을 방지했습니다.
(() => {
// 브라우저가 지원 문과 일치하지 않으면 아무것도 하지 않습니다.
if (
!CSS.supports(
"(font: -apple-system-body) and (-webkit-touch-callout: default)"
)
)
return;
// 루트 요소 스타일이 아직 구문 분석되지 않았으므로 요소를 만들어야 합니다.
const div = document.createElement("div");
div.setAttribute("style", "font: -apple-system-body");
// Body는 아직 사용할 수 없으므로 루트 요소에 추가해야 합니다.
documentElement.appendChild(div);
const style = getComputedStyle(div);
if (style.fontSize === "17px") {
documentElement.style.setProperty("font-size", "16px");
}
documentElement.removeChild(div);
})();
그런 다음 페이지가 로드될 때 resize observer를 사용하여 값이 다시 변경되는지 감지하고, html 요소의 글꼴 크기 속성을 설정하거나 해제합니다. 이렇게 하면 확장 가능한 글꼴을 계속 지원하지만 기본 글꼴 크기(100%)에는 큰 영향을 미치지 않습니다.
영향
확장 가능한 글꼴을 지원하는 것은 시력이 약한 호스트와 게스트, 더 큰 글꼴 크기와 검색 환경 제어의 혜택을 누리는 모든 분께 큰 변화를 가져올 수 있는 투자입니다. 아래는 시력이 흐릿한 사람에게 기본 글꼴 크기(16px)로 표시되는 홈페이지와 글꼴 크기를 두 배(32px)로 늘렸을 때의 모습을 보여주는 두 가지 예시입니다. 두 번째 이미지가 훨씬 더 읽기 쉽고 사용하기 편합니다.
제품 접근성 전략으로 폰트 크기 조정을 선택한 것은 전반적인 사용자 경험을 크게 향상시키는 다양한 이점을 가져왔습니다. rem 단위로 자동 변환하여 변경 작업을 수행하면서 이 전환이 더 쉬워졌습니다. 이러한 변경 사항이 전체 사이트에 적용된 후 기존 “텍스트 크기 조정” 이슈의 80% 이상이 해결되었습니다. 게다가 그 이후로 새로운 이슈가 줄어들고 있습니다.
결론적으로 웹에서 텍스트 크기 조정 기능을 향상시키는 여정은 귀중하고 실용적인 교훈으로 가득했습니다. rem 단위를 전략적으로 적용하는 방법부터 도구와 자동화의 역할에 이르기까지 모든 교훈은 에어비앤비의 사용자 경험을 높이는 데 있어 중요한 단계였습니다. 우리의 여정을 공유함으로써 다른 이들이 이 전환을 더 원활하게 해낼 수 있기를 바랍니다. 우리의 작업은 계속되고 있으며, 에어비엔비의 접근성을 지속적으로 발전시켜 나갈 것입니다. 이러한 과제에 열정이 있다면 에어비엔비 커리어 기회를 탐색해 보시기 바랍니다.
감사 인사
- 기술 검토와 조언을 해준 Alan Pinto Souza, Dennis Wilkins, Jimmy Guo, Andrew Scheuermann께 감사드립니다.
- 초기 제품 파트너로 도움을 준 Sterling DeMille, Riley Glusker, Ryan Booth께도 감사의 말씀을 전합니다.
- 이 접근 방식을 지원해준 Jordanna Kwok, Sarah Alley, JN Vollmer께 감사드립니다.
- 디자인 지원을 해준 Veronica Reyes와 Jamie Cristal께도 감사의 말씀을 전합니다.