스크린 리더를 위한 올바른 상태 정보 적용하기
안녕하세요, 엔비전스 입니다. 무더운 여름 잘 보내셨는지요? 지금 아티클이 올러온 걸 보면 알 수 있지만 저희는 잘 지내고 있습니다 :)
이번에는 스크린 리더 사용자를 위해 어떻게 올바른 상태 정보를 적용할 수 있는지 잘못된 어떤 사례는 어떤 것이 있는지 알아보는 시간을 갖고자 합니다.
컨트롤 텍스트 변경
가장 직관적이면서도 문제가 많은 방법으로, 버튼을 눌러서 바뀐 상태에 따라 개발자가 컨트롤 텍스트를 변경하는 사례입니다. iOS VoiceOver에서는 이 방법이 아주 효과적인 방법일 수 있습니다.
장점
iOS VoiceOver와의 궁합
iOS용 VoiceOver는 누른 요소를 한 번 더 읽는 특성이 있습니다. 그렇기 떄문에 누름과 동시에 변경된 텍스트를 바로 들을 수 있습니다.
풍부한 표현력
또한, 비교적 상태 정보를 제공함에 있어서 풍부한 표현력을 갖습니다. 예를 들어, iOS에는 userInteractionEnabled와 selected 트레이트 외에 아무런 상태 정보가 없습니다.
즉, 텍스트를 바꾸는 식으로 상태정보를 제공한다면 기획자의 뜻대로 더 풍부한 정보를 제공할 수 있습니다.
단점
반면, 단점도 명확합니다. 가장 대표적인 사례가 특정 기술을 사용하지 않고 텍스트만 바뀌었을 때 특정 스크린 리더가 읽지 못하는 호환성 이슈가 있습니다.
TalkBack과의 호환성
Android TalkBack은 컨트롤 내용이 변경되었을 때, 버튼에 Live Region 등을 거는 등 아무런 조치도 하지 않았을 때 변경된 텍스트를 읽지 못합니다.
웹 플랫폼에서는 PC 스크린 리더를 기준으로 aria-label로 변경된 대체 텍스트는 버튼을 눌렀을 때 업데이트된 정보를 바로 읽는 것이 일빈적입니다. 그러나, Android는 이 또한 읽지 못합니다.
실수 가능성 증가
버튼 대체텍스트를 상태 정보처럼 변경했을 때, 특정 컴포넌트와 의미론적으로 충돌할 수 있습니다.
예를 들어봅시다. 다음은 iOS VoiceOver에서 볼 수 있는 흔한 사례입니다.
- 눌리지 않았을 때
- 재생, 버튼
- 눌렸을 때
- 선택됨, 일시 정지, 버튼
아무 생각 없이 읽었을 때는 ‘그래서 이게 뭐가 문제지?’ 라고 생각할 수도 있습니다. 만약 그렇게 생각하신다면 다시 한번 뜻을 생각해보세요.
버튼 텍스트가 일시 정지로 됐는데 선택됨 정보를 같이 읽습니다. 즉, 현재 무언가 재생중이고, 일시정지하려면 누르라는 의미로 버튼 텍스트가 바뀌었습니다.
그런데, 느닷없이 선택됨이라는 트레이트가 추가됨에 따라, 의미가 반전되었습니다. 일시정지가 선택되어 있다는 것은 지금 일시정지 상태라는 의미로 받아들이게 됩니다.
해결책과 결론
가급적이면 대체 텍스트를 상태정보 대신 사용하는 것은 피하는 것이 좋습니다. 위에서 설명했듯, 가장 큰 이슈는 호환성 문제가 있기 때문입니다.
또한 이미 선택 정보를 갖고 있는 컴포넌트에 선택에 관한 상태 정보를 텍스트로 주는 사례가 생기기 떄문입니다.
이 문제를 해결하기 위해서는 다음과 같은 원칙을 따릅시다.
- 대체 텍스트로 상태 정보를 주는 행위는 가급적 피한다.
- 남이 만든 컴포넌트나 네이티브 컴포넌트를 사용할 때, 해당 요소에 상태정보가 제공되는지 반드시 확인한다.
- 설령 내가 만든 컴포넌트라고 하더라도 가급적이면 레이블을 바꾸지 않고 상태정보만을 업데이트한다.
힌트
플랫폼에 따라서는 힌트를 상태정보로 제공하는 것이 상태정보를 대신할 대안이 될 수 있습니다.
그러나 역시 마찬가지로 힌트는 말그대로 해당 컨트롤에 관한 사용방법을 담아야 하는 것으로 의미에 맞지 않으며 여러 문제를 야기할 수 있습니다.
문제점
- 스크린 리더 사용자가 힌트 정보를 끄고 사용한다면 무용지물이다.
- 힌트 정보는 변경되었을 때 바로 발화되지 않는다.
- 웹은 기기에 따라 aria 속성은 지원 정도가 상이하고, title 속성은 마우스를 올렸을 때 툴팁 말풍선이 표시되므로 원치 않는 상황이 발생할 수 있다.
- Android TalkBack의 경우, 요소를 읽는 방식을 설정할 수 있다. 힌트나 title 속성 등은 항상 뒤에 읽으므로 사용자의 선호 설정을 무시한다.
해결 방법
상태정보 적용방법 1과 별반 다를게 없습니다. 가급적이면 네이티브 UI에서 제공하는 API를 사용하는 것이 좋으며, 웹에서는 올바른 WAI-ARIA 상태정보를 사용하는 것 또한 방법입니다.
팝업
상황에 따라서는 상태 정보를 버튼에 바로 전달하지 않고 팝업을 표시하는 사례도 있습니다. 대표적으로 회원가입 화면이 그렇습니다.
이 방법은 요소를 비활성화 하는 방법보다 친절한 방법입니다.
서식에 오류가 있을 때, 혹은, 서식이 비어있을 때, 단순히 버튼이 비활성화되는 것이 아니고, 버튼은 그대로 두되 사용자가 필수 서식을 입력하지 않고 넘어가려고 할 때, 팝업을 표시하여 사용자가 상황을 명확히 인식할 수 있게 하는 방법입니다.
장점
사용자가 버튼을 조금 더 빠르게 찾을 수 있습니다. 기본적으로 비활성화된 버튼은 명도 대비가 매우 낮아 사용자가 버튼이 있음을 아예 인지하지 못할 수도 있습니다.
반면에, 버튼이 비활성회되어있지 않다면, 저시력 사용자의 레이아웃을 파악하는 데 큰 도움을 줄 수 있습니다.
단점
컴포넌트 하나가 더 필요할 수도 있습니다. 기본 브라우저 대화상자를 사용할 수도 있지만 기업 상황이나 요구에 따라 커스텀 팝업을 표시하는 것이 일반적입니다.
또한, 팝업 접근성이 올바르게 적용되어 있지 않다면, 오히려 역효과를 일으킬 수 있습니다. 예를 들어, 팝업이 활성화되었지만 사용자의 초점을 팝업 안으로 보내주지 않는다거나, 팝업 밖으로 초점이 빠져나가는 등의 이슈가 생길 수 있습니다.
실시간 콘텐츠 영역(Live Region)과 스크린리더 알림으로 상태정보 전달
이 방법은 최근 회원가입 폼에서 쓰이는 방법으로, 실시간으로 사용자의 입력을 감지하고 서식의 요구사항과 맞지 않는 형식의 텍스트를 작성했을 때 사용자에게 오류 내용을 알리는 용도로 사용합니다.
장점
동적인 서식을 만드는 데 유리합니다. 외관상 버튼이 많이 없어 사용자에게 단순하고 깔끔하다는 인상을 심어줄 수 있습니다.
특히, 캐러셀에서 다음 페이지, 이전 페이지 버튼을 눌러 넘겼을 때, 이 라이브 리전이나 스크린리더 알림 기능이 유용합니다.
또한, 스크린 리더의 초점이 해당 영역으로 이동하지 않더라도 내용을 들을 수 있으므로 잘만 적용한다면 매우 좋은 사용자 경험을 제공합니다.
단점
스크린 리더라는 보조기술 이해도가 높아야 합니다. Live region은 웹 기술로 예로들어 assertive와 polite의 차이점을 명확히 알고, 어떨 때 이 기술을 써야하는지 잘 선택해야 합니다. 또한, 언제 이 영역에 내용을 업데이트할지도 잘 파악해야 합니다.
선의로 개발하였지만, 오히려 사용자에게는 걸리적거리는 실시간 정보만을 제공할 수도 있습니다.
올바른 모바일 접근성 API 사용 (권장)
플랫폼마다 보조기술 사용자를 위해 상태 정보를 제공하는 API를 가지고 있습니다. 이 API를 사용하는 것이 가장 이상적인 해결 방법입니다.
우선적으로, 대체할 수 없는 요소가 아니라면 가급적이면 커스텀 요소 사용을 자제하는 것이 기본 원칙입니다.
해당 섹션은 모바일에 관한 섹션이지만 웹으로 예를 들어보자면 메뉴 요소가 없으므로 메뉴를 구현하는 것, 탭 요소를 구현하는 것은 어쩔 수 없는 선택이지만, 버튼 요소는 HTML에 이미 있으므로, 최대한 네이티브 <button> 태그를 사용하는 것을 우선해야 합니다.
모바일 상태정보 제공에 관해서는 수많은 아티클과 포럼 게시글이 있으므로 여기서 따로 다루지 않습니다.
WAI-ARIA(웹)
웹에서 제공할 수 있는 상태 정보는 어찌보면 네이티브보다 다양합니다. 그만큼 호환성 문제도 많이 일어납니다. 그래서 위에서 설명했듯이 항상 기본으로 제공되는 컴포넌트를 최대한 고쳐 사용하는 것을 원칙으로 해야 합니다.
특히, WAI-ARIA는 단순히 스크린 리더에 정보를 전달할 뿐, 실제 네이티브 동작을 구현해주진 않기 때문에 복잡한 동작을 요구하는 컴포넌트에서 오류가 생길 가능성이 높습니다.
웹 상태 정보 제공 시 오류사항
특히 WAI-ARIA를 사용하여 상태 정보 제공 시, 요소 유형에 따라 지원하거나, 금지된 속성을 사용하여 상태정보나 대체 텍스트를 제공하는 경우가 많습니다.
자주 볼 수 있는 사례
aria-selected를 지원하지 않는 요소에 aria-selected로 선택 정보를 제공하는 사례가 많습니다. 대부분의 WAI-ARIA 상태 정보는 허용된 요소와 그렇지 않은 요소가 존재합니다. WAI-ARIA 1.3를 잘 참고해야 하는 이유입니다.
WAI-ARIA 1.3 기준, 상태정보별 지원 요소
내용이 길어 <details>로 콘텐츠를 제공합니다. 콘텐츠를 확인하려면 버튼을 눌러 확인하시기 바랍니다. 해당 하위 정보는 모두 WAI-ARIA 1.3의 내용에서 발췌되었음을 알립니다.
속성별 지원 유형 목록
- aria-busy
- 전역 상태 속성
- aria-checked
- aria-current
- 전역 상태 속성
- aria-current
- aria-expanded
- aria-grabbed
- 전역 상태 속성
- aria-hidden
- 전역 상태 속성
- aria-invalid
- aria-pressed
- aria-selected
[TIP] WAI-ARIA 1.3 문서에서 명세 빠르게 찾기
WAI-ARIA 1.3 페이지의 각 요소와 속성 제목은 모두 아이디 값이 있습니다. 따라서, 긴 문서를 끝까지 읽을 필요가 없으며, 링크 끝에 #(샾) 기호와 함께 원하는 속성명이나 유형 이름을 작성하면 빠르게 해당 내용으로 이동할 수 있습니다.
- 예시 1 :
- https://www.w3.org/TR/wai-aria-1.3/#aria-haspopup
- 예시 2
- https://www.w3.org/TR/wai-aria-1.3/#alertdialog