웹 접근성(WCAG 2.1) 자동화: 토큰 시스템에서 컬러 대비 검증하기

디자인 토큰 시스템에서 웹 접근성(WCAG 2.1) 컬러 대비 자동 검증하는 법

웹 접근성(WCAG 2.1)

디자인 시스템을 공들여 구축해 배포했는데, 나중에 사용자로부터 “글자가 잘 안 보여요”라는 피드백을 받거나 접근성 심사에서 대거 탈락하는 상황을 상상해 보세요. 수백 개의 컬러 토큰을 일일이 웹 접근성 검사기에 넣어서 확인하는 작업은 고통스럽고 비효율적입니다. 특히 다크 모드까지 지원하는 시스템이라면 검증해야 할 조합은 기하급수적으로 늘어납니다.

진정한 DesignOps의 가치는 이러한 반복적이고 필수적인 ‘검증’ 과정을 시스템 내부로 끌어들여 자동화하는 데 있습니다. 이번 글에서는 디자인 토큰 빌드 파이프라인(Style Dictionary)에 WCAG 2.1 가이드라인을 이식하여, 기준에 미달하는 컬러 조합을 배포 전에 원천 차단하는 엔지니어링 전략을 공유합니다.

웹 접근성, 왜 토큰 단계에서 ‘Shift-Left’ 해야 하는가

전통적인 접근성 검사는 개발이 완료된 후 브라우저에서 실행되었습니다. 하지만 이때 문제를 발견하면 이미 설계된 컬러 시스템 전체를 수정해야 하므로 수정 비용이 매우 높습니다. 이를 ‘Shift-Left’, 즉 프로세스의 가장 앞단인 디자인 토큰 단계로 옮겨오면 설계 시점에 즉시 오류를 수정할 수 있습니다.

WCAG 2.1의 핵심은 명도 대비(Contrast Ratio)입니다. 일반 텍스트는 최소 4.5:1, 큰 텍스트나 UI 구성 요소는 3:1 이상의 대비를 유지해야 합니다. 이를 계산하는 공식은 다음과 같습니다.

여기서 은 더 밝은 색의 상대 휘도(Relative Luminance)이고, 는 더 어두운 색의 상대 휘도입니다. 이 수학적 공식을 빌드 스크립트에 포함하면, 우리가 정의한 모든 시맨틱 토큰이 기준을 통과하는지 실시간으로 감시할 수 있습니다.

Style Dictionary를 활용한 자동 검증 로직 구현

우리는 앞서 구축한 Style Dictionary의 빌드 프로세스에 ‘검증(Validation)’ 단계를 추가할 것입니다. 단순히 JSON을 CSS로 바꾸는 것을 넘어, 각 토큰이 배경색 위에서 충분한 대비를 갖는지 확인하는 코드를 작성해 보겠습니다.

실무에서는 tinycolor2chroma-js 같은 라이브러리를 활용하면 휘도 계산을 매우 쉽게 처리할 수 있습니다. 아래는 빌드 시점에 특정 기준(AA 또는 AAA)을 충족하지 못하면 에러를 발생시켜 빌드를 중단시키는 커스텀 트랜스포머의 구조입니다.


const tinycolor = require(‘tinycolor2’);

StyleDictionary.registerAction({
name: ‘accessibility-check’,
do: function(dictionary, config) {
const tokens = dictionary.allTokens;
tokens.forEach(token => {
if (token.attributes.category === ‘text’ && token.attributes.background) {
const bgToken = dictionary.tokens[token.attributes.background];
const contrast = tinycolor.readability(token.value, bgToken.value);

if (contrast < 4.5) {
console.error(`❌ 접근성 오류: ${token.name} (${token.value})와 배경 ${bgToken.name}의 대비가 ${contrast.toFixed(2)}로 기준 미달입니다.`);
// 필요 시 process.exit(1)로 빌드 강제 중단
}
}
});
}
});


이렇게 액션을 등록해 두면, 디자이너가 피그마에서 실수로 연한 회색 배경에 연한 파란색 텍스트를 배치하더라도 코드 배포 과정에서 즉시 차단됩니다. 시스템이 인간의 실수를 방지하는 강력한 가드레일이 되는 셈입니다.

[💡 에디터의 실무 팁: 모든 토큰을 검사하기보다 usagegroup 속성을 활용해 ‘배경’과 ‘전경(글자)’이 명확히 정의된 시맨틱 토큰 위주로 검사하는 것이 오탐지를 줄이는 비결입니다.]

트러블슈팅: 브랜드 컬러가 접근성 기준을 통과하지 못할 때

실무에서 가장 난처한 상황은 기업의 ‘심벌 컬러(Brand Color)’ 자체가 웹 접근성 기준에 미달하는 경우입니다. 예를 들어 밝은 노란색이나 연한 주황색이 브랜드 컬러라면, 흰색 배경 위에서 4.5:1의 대비를 맞추는 것이 거의 불가능합니다.

저는 이 문제를 해결하기 위해 ‘접근성 전용 변주(Accessibility Variant)’ 전략을 사용합니다. 디자인 가이드는 유지하되, 웹 UI의 텍스트로 쓰일 때만 명도를 낮춘 brand-primary-dark 토큰을 자동으로 생성하여 매핑하는 방식입니다.

실제로 한 핀테크 프로젝트에서 주황색을 주력으로 사용했는데, 텍스트 가독성 문제로 큰 혼란이 있었습니다. 이때 시스템적으로 버튼 내부의 텍스트는 자동으로 neutral-900을 선택하게 하거나, 주황색의 채도를 미세하게 조절한 ‘디지털 전용 컬러’를 토큰 시스템에 이중화하여 해결했습니다. 이는 디자인의 심미성을 해치지 않으면서도 법적 규제와 사용자 경험을 모두 잡는 실무적인 타협점입니다.

지속적인 모니터링과 CI 연동

검증 로직이 완성되었다면, 이를 GitHub Actions와 같은 CI 환경에 연동해야 합니다. 디자인 토큰 레포지토리에 푸시가 발생할 때마다 접근성 체크 스크립트가 실행되도록 설정하세요. 만약 대비 수치가 기준에 못 미친다면 PR(Pull Request)이 승인되지 않도록 막을 수 있습니다.

또한, 검사 결과를 단순히 콘솔에 찍는 것에 그치지 않고 Storybook과 연동하여 시각적인 리포트를 제공하는 것도 좋은 방법입니다. 각 컬러 토큰 옆에 AA/AAA 통과 여부를 뱃지로 표시해 주면, 개발자와 디자이너 사이의 불필요한 커뮤니케이션이 획기적으로 줄어듭니다. 기술은 복잡한 가이드라인을 모두가 지킬 수 있는 ‘쉬운 규칙’으로 바꿔줄 때 가장 빛이 납니다.

자주 묻는 질문(FAQ)

Q1. 모든 텍스트에 대해 4.5:1을 지켜야 하나요? 로고나 장식용 텍스트, 비활성화된(Disabled) 버튼의 텍스트는 WCAG 명도 대비 규정에서 제외됩니다. 하지만 사용자 경험을 위해 비활성 상태라도 최소한의 가독성(보통 2.5:1 이상)을 확보하는 것을 권장합니다.

Q2. 다크 모드에서는 대비 기준이 달라지나요? WCAG 기준은 모드와 상관없이 동일하게 적용됩니다. 오히려 다크 모드에서는 배경이 어둡기 때문에 아주 밝은 흰색 텍스트가 눈부심(Halation)을 유발할 수 있으므로, 4.5:1을 넘기되 너무 과하지 않은(약 15:1 이하) 범위를 유지하는 것이 팁입니다.

Q3. 자동 검증 도구만 믿어도 될까요? 자동 검증은 명도 대비 같은 ‘수치적’ 요소는 완벽히 잡아내지만, 폰트의 굵기나 배경 패턴의 복잡성 같은 ‘맥락적’ 요소는 놓칠 수 있습니다. 자동화 시스템을 기본으로 하되, 주요 화면에 대해서는 스크린 리더 테스트 등 수동 점검을 병행해야 합니다.

댓글 남기기