디자인 시스템 접근성 개선기 (2)

뮤돔면·2025년 7월 26일
post-thumbnail

지난 2개월 간 틈틈이 째깍악어 디자인 시스템의 접근성을 개선해왔습니다. 아직 해결해야 할 과제들이 많지만, 이 글을 통해 그간의 여정과 고민을 기록하고자 합니다. 접근성이란 주제에 대한 인식을 조금이나마 높이는 계기가 되길 바랍니다.

기억에 남는 개선점들

36종+a의 컴포넌트를 개선하면서, 특히 몇 가지 기억에 남는 지점들이 있다. 내 가치관과 철학이 담긴 컴포넌트, 가이드라인에 반하는 결정을 내린 컴포넌트, 유독이 까다로웠던 컴포넌트가 그 주인공들이다. 돌아보면 접근성은 결국 사람의 사용성을 다루는 문제이기 때문에 컴포넌트 하나하나에 담긴 고민과 해결 방식에도 많은 철학이 담길 수밖에 없는 것 같다.

1. TextArea: 내 철학 담기

TextArea에 얼마나 입력했는지 조용하고 명확하게 읽어주기
스토리북에서 테스트한 내 TextArea 컴포넌트

위에서 확인할 수 있듯이 째깍악어 디자인 시스템의 <TextArea />는 기본적으로 입력된 글자 수와 최대 허용 글자 수를 우측 하단에 표시해 준다. 해당 지점의 접근성을 고려하면서 다음 문제 상황에 봉착했다.

  1. 해당 정보가 화면에만 존재하기 때문에 저시력 사용자나 스크린 리더 등의 보조기구 사용자는 정보 확인이 어렵다. 입력 중 해당 영역으로 포커스를 의도적으로 이동하거나, 이동시켜야 하는데 좋은 접근이 아니다.
  2. 글자를 입력할 때마다 매번 이 수치를 낭독해 버리면 오히려 과도한 정보로 인지 부하를 유발할 수 있다.

그래서 나는 “얼마나 남았는지”가 중요한 시점에만 이 정보를 제공하기로 결정했다. 글자수를 기준으로 두 지점을 남겼다: 80%, 100% 지점. 그리고 해당 지점에 도달하면 사용자에게 해당 정보를 알리기로 했다. 사용자 경험을 해치지 않는 선에서 접근성을 확보하기 위한 전략이었다.

  1. 사용자가 최대 허용 글자 수의 80%에 도달하면 role=status로 비교적 부드럽게(polite) 알림을 읽어 준다.
  2. 사용자가 최대 허용 글자 수의 100%에 도달하면 role=alert로 즉각적인 경고를 전달한다.

물론 아직 실제 사용자 테스트를 거치진 못했기에 이 접근 방식이 최적이라고 단정할 순 없다. 그래서 회사에 연구 진행을 요청해, 실제 저시력 사용자와 보조 기구 활용자를 대상으로 피드백을 받을 수 있는 환경을 준비 중이다. 사용자 연구를 통해 “언제, 어떻게” 알림이 가장 효과적인지 데이터를 토대로 검증하고, 그 결과를 반영해 컴포넌트를 더욱 개선해 나갈 계획이다.

2. 명암 대비: WCAG 2.2 거스르기

텍스트 색상과 배경색의 대비는 접근성의 기본 원칙 중 하나로, 사용자에게 정보의 인지 가능성을 제공하는 중요한 기준이다. 초기에 우리는 WCAG 2.2의 기준을 따르기로 했고, 그중에서도 상대 명도를 기반으로 한 명암비 계산 방식을 적용하여 텍스트 색상이 배경과 충분한 대비를 이루도록 구현했다. WCAG 2.2에 따르면 일반 텍스트는 최소 4.5:1, 굵은 텍스트는 3:1의 명암비를 확보해야 한다.

이 계산식을 토대로 '텍스트 자동 반전' 로직을 개발했고, 전 컴포넌트에 적용했다. 그런데 그 결과가 조금 이상해보였다. 우리 테마의 primary 색상 중 하나인 파란색( #18C1E7 ) 버튼 내부에서 텍스트가 검정색으로 자동 선택된 것이다!
관련된 논문과 실험, 칼럼들을 찾아보며 여러 사례를 검토해본 결과, 기존 WCAG의 명암비의 계산 기준이 실제 시각적 인지에 있어 오류를 유발할 수 있다는 주장에 공감하게 되었다. 예컨대 시각적으로 더 선명해보이는 파랑색-흰색의 색 조합이 파랑색-검정색의 색 조합보다 명암비가 낮았고, 심지어는 WCAG의 기준을 충족하지 못했다. 이는 우리 디자인 시스템의 색 조합 시스템과도 충돌된 결과였다!

WCAG의 계산식은 사람의 색인지를 적절하게 반영하지 못했다.
스토리북에서 테스트한 내 TextArea 컴포넌트 출처: https://uxmovement.com/buttons/the-myths-of-color-contrast-accessibility/

많은 고민 끝에 WCAG 2.2의 가이드라인을 따르지 않기로 결정했다. 그리고 디자인 팀과의 논의를 거쳐, 디자인 시스템의 색상 팔레트 안에서 가장 조화롭게 동작하는 명도 임계값을 도출했다. 우리 테마의 primary 두 값의 사이 값인 0.57로 최종 결정한 것이다. 이 임계값보다 배경색의 상대 명도가 낮을 경우 밝은 텍스트 색상(예: 흰색), 높을 경우 어두운 텍스트 색상(예: 검정색)을 자동으로 적용하도록 로직을 수정했다.

조용히 올라간 따봉
상대명도값에 대한 PR

그리고 이후에 알게 되었는데, WCAG 3.0에서는 이 명암비에 대한 기준이 변경될 예정이었다. 실제 인간의 색인지 모델에 가까운 APCA(Advanced Perceptual Contrast Algorithm) 접근을 활용한다고 하는데, 내 결정이 완전히 틀리지는 않았구나. 하는 생각이 들어 내심 기분이 좋았다. 어쩌면 인지심리학을 전공했기 때문에 문제를 제기할 수 있지 않았나하는 생각이 드는 지점이기도 했다.

우리팀에서 제일 조용한 개발자분의 귀여운 리액션
상대명도값에 대한 PR

3. ChainPicker: 선례 남기기

키보드로 ChainPicker 돌리기
스토리북에서 테스트한 내 ChainPicker 컴포넌트

<ChainPicker /> 는 째깍악어 디자인 시스템의 컴포넌트 중 하나로, 체인을 돌려서 항목을 선택하는 데 사용하는 컴포넌트다. 웹 기반의 서비스나 디자인 시스템에서는 쉽게 만날 수 없는 컴포넌트이고, 일반적으로 모바일 서비스에서 사용된다(🔗 antd-mobile의 pickerView를 떠올리면 쉽다). 그렇기에 해당 컴포넌트의 접근성을 개선하는 작업은 개척의 영역, 선례를 남기는 작업에 가까웠다.

필자의 경험과 지식 범주 안에서 role=spinButton 을 떠올렸다. "돌아간다"는 의미에서 <ChainPicker /> 컴포넌트는 스핀버튼를 통해 선택되는 값이 노출되는 영역과 유사하다고 볼 수 있었다. 여러 지점들을 이 스핀버튼 형태와 일관성 있도록 수정했다. 특히 키보드를 통해 이 <ChainPicker /> 컴포넌트를 돌릴 수 있도록 인터랙션 처리를 추가해두었다. 방향키를 길게 누르면 이 <ChainPicker />가 길게 돌아간다. 구체적인 내용은 🔗 개인적으로 정리한 개선 기록들 노션 링크에서 확인할 수 있다.

사실 돌아보면 가장 아쉬움이 남는 컴포넌트이기도 하다. 경험의 유사함이라는 측면에서 특히 그렇다. <ChainPicker /> 컴포넌트는 특유의 모멘텀 스크롤 등 시각적으로 매우 화려한 동작을 갖고 있는데, 이런 ‘감각적인 경험’이 시각에 의존하지 않는 사용자에게까지 전달되지는 못하고 있다는 생각이다. 모멘텀이라는 경험을 단순한 방향키 조작으로 전달하기에는 조금 아쉽다는 생각이다. 편의성을 위해 감각적인 경험을 양보한 모양새인데, 현실적으로 어쩔 수 없는 것일까?

4. DatePicker: 최후의 컴포넌트

DatePicker에서 스케줄 정확하게 읽어주기
스토리북에서 테스트한 내 DatePicker 컴포넌트

<DatePicker /> 컴포넌트는 접근성의 끝판왕이라고 생각해 가장 마지막에 작업하려 남겨둔 컴포넌트였다. 어쩌면 정형화된 표준이 존재하지 않는 컴포넌트이기도 해서 실 서비스에서 사례들을 찾아보는데 더 많은 시간을 투자했다. 실제로 구글 캘린더와 에어비앤비의 날짜 선택 플로우에서 많은 영감을 받았다. 특히 에어비앤비의 달력의 키보드 인터랙션 전략이 인상적이었다(키보드만으로도 날짜 탐색과 선택이 가능했고, 심지어는 편했다!).

👉에어비앤비 가서 해보기

MUI의 DatePicker를 기본 구조로 삼되, 에어비앤비의 내비게이션 흐름과 접근성 전략을 적극 차용하고, 구글 캘린더의 renderEvent와 이벤트 읽기 처리 방식도 일부 참고하기로 결정했다. 구체적인 내용은 역시 🔗 개인적으로 정리한 개선 기록들 노션 링크에서 확인할 수 있다.

간단하게 PR을 올리려고 했는데 길어졌다.
스토리북에서 테스트한 내 DatePicker 컴포넌트

<DatePicker />를 마지막으로 남겨둔 것은 적절한 선택이었던 것 같다. 나머지 컴포넌트들을 개선하면서 얻은 인사이트와 경험치가 있었기에 그나마 수월했기 때문이다(물론 가장 오랜 시간이 걸리긴 했다!). 게임의 마지막 보스를 가까스로 처치하고 클리어하는 느낌이랄까.


그리고 남은 것들

개발자로서의 내 가치를 재확인하다

주말과 퇴근 시간을 쪼개가며 작업에 몰입할 수 있었던 건, ‘사회적 기여’라는 개인적인 목표가 있었기 때문이었다. 접근성 작업을 마치면서 프론트엔드 개발자로서 내가 어떤 가치를 만들 수 있을지 돌아보게 됐고, 자연스럽게 내 정체성에 대해서도 다시 생각해보게 되었다.

요즘은 생성형 AI, 바이브 코딩 같은 흐름 덕분에 개발의 진입 장벽이 많이 낮아졌다. 그래서일까, 오히려 이런 시기일수록 개발자로서 어떤 지향점을 가져야 하는지 고민할 필요가 있다고 느껴진다. 기술에 의미를 부여하는 건 결국 개발자의 몫이기 때문이다.

접근성 개선 작업 역시 그랬다. 실제로 ‘이 컴포넌트의 접근성을 개선해줘’라고 GPT에 요청해보면 결과가 나쁘지 않은 경우도 있었다. 하지만 일부 결과는 규칙에만 매몰돼 현실의 스크린 리더 사용 방식과 어긋났고(role: none 처리-구형 스크린리더들은 대응하지 못할텐데?), 때로는 HTML의 기본 규칙조차 잘못 이해한 제안을 내놓기도 했다(dl 태그 아래에 div 태그를 둘 수 없다는 주장, 바뀐지가 언젠데...참고). aria-label로 설정한 레이블은 문맥을 고려하지 않아 실제 사용자 입장에서 이해하기 어려웠다(학습할만한 '좋은 접근성 사례' 자체가 부족했기 때문일까? 그렇다면 우리는 더더욱 반성해야 할지도 모른다). 이러한 한계를 포착하고, 방향을 수정하고, 그 이상의 의미를 부여하는 것은 여전히 개발자의 몫이었다.

이런 과정을 겪으면서, 아직은 현실을 ‘관찰’하는 능력과 상상력에 있어서는 사람이 더 우위에 있다는 생각이 들었다. 특히 내가 기억에 남는다고 느낀 작업들은 대부분 단순한 기준 충족을 넘어서 실제 사용 환경과 그 안에서의 경험을 고민한 작업들이었다. 사실 그동안 접근성이나 인클루시브 디자인에 관심을 가지면서도 ‘이게 정말 가치 있는 일일까’란 의문을 가졌던 적이 많았는데, 이번 작업을 통해 그 물음에 확신을 더할 수 있었고, 한편으로는 안도감이 들기도 했다. 이러한 지점들이 기술에 의미가 투영된 영역이 아닐까 싶다.

앞으로의 과제

앞으로 디자인 시스템의 접근성 개선 방향은 비교적 분명하다.

  1. 스크린리더, 스위치, 점자 생성기 등의 보조기구 사용자들을 대상으로 한 질적 인터뷰 수행하기
  2. 여러 기기, 여러 환경에서 더 많은 접근성 테스트 수행하기(OS, 모바일 및 PC, (구)버전 등)
  3. 째깍악어의 접근성 가이드라인 만들기
  4. 디자인 시스템의 조합 혹은 디자인 시스템으로 커버할 수 없는 사례들에서의 접근성 개선 방향을 정리해서 전파하기

이 중 (1) 질적 인터뷰 관해서는 연구비 확보를 위해 상부에 보고를 올렸고, (4) 특수 케이스 정리는 최근 교사 리뉴얼 프로젝트를 하면서 조금씩 진행하고 있다. 다만 여러 환경에서의 테스트나 가이드라인 설계는 아직 방향성을 좀 더 고민해봐야 한다.


최근에 🔗 @uturi라는 개인 모노레포를 하나 만들었다. 접근성을 공부하면서 떠올린 아이디어들을 라이브러리 형태로 정리해보고 싶었고, 조금은 웹 접근성 씬(?)을 흔들어보고 싶다는 마음도 담았다. 겨드랑이에 난 날개라는 약점(장애)을 극복하고 영웅이 되는 우투리가 모티브다.

첫번째 라이브러리로 얼마전 @uturi/sonification을 프리릴리즈했다. 표나 시계열 차트의 수치 정보를 청각적으로 표현하는 라이브러리다. 숫자를 멜로디 혹은 음량으로 변환해준다고 생각하면 쉽다. 정식 릴리즈가 되면 별도로 글을 써볼 생각이다. 언젠가는 이 '우투리'가 접근성을 대표하는 라이브러리 집합으로 성장하길 바라면서, 이 '웹 접근성'이라는 주제도 메이저한 영역이 되었으면 좋겠다는 바람으로 글을 마친다.

profile
스크립트가 중심이 되는 프론트엔드에서 개발하고 있습니다. 서비스의 철학을 고민합니다. 배려하고 포용하는 모든 것들을 사랑합니다.

0개의 댓글