사용자의 접근성을 개선하기 위한 과정은 여러가지가 있다. Semantic HTML, 키보드 인터랙션, 스크린리더, WAI-ARIA 등등
이중 스크린리더를 사용하여 시각에 불편함이 있는 사용자들의 경험을 개선하기 위한 방법을 알아보고자 한다.
<스크린 리더가 접근성을 개선하는 과정>
1. 움직이는 단위 : 요소 (HTML Element)
2. 순차탐색 : 손가락을 좌우로 스와이프 하면서 앞뒤로 이동
3. 스크린 터치 : 터치한 영역에 있는 요소를 선택
4. 로터를 이용한 탐색 : 머리말/단어/글자 단위로 이동
** 사전지식**
1. Accessible Name
스크린리더가 요소를 포커스 했을 때 읽는 값은 다음 중 하나로 결정된다.
1. author : 특별한 속성을 사용해서 정하는 값 (aria-label, aria-labelledby, alt(<img>)) --> 우선순위가 더 높음
2. contents : 요소의 텍스트값
2. Role
: 스크린 리더가 요소를 어떤 방식으로 다룰지 결정하는 속성이다. Role마다 기대되는 스크린 리더 동작이 있다.
( Example : role = "button" )
- 요소의 Accessible Name을 읽은 뒤 "버튼"을 붙여 읽음
- 자식 요소의 Accessible Name을 모아서 contents로사용
3. Semantic tag 와 Role
- div 나 span은 role을 갖고있지 않지만, sementictag는 암시적으로 role을 갖고있다.
- <button> 은 role="button" 과 같다.
- <a> 은 role="link" 과 같다.
- <input type="checkbox"> 은 role="checkbox" 과 같다.
--> 따라서 적절하게 Semantic tag를 사용하는 것 만으로도 스크린 리더에 이로울 수 있다.
4. Children Presentational
- 특정 role이 가진 특징인데, 자식 요소의 Accessible Name을 모아서 요소의 contents로 사용한다.
- 자식 요소를 스크린 리더가 읽지 않도록 한다.
-시각 사용자가 묶어서 이해하는 정보를 스크린리더가 끊어읽는 문제를 해결할 때 유용하다
5. <img> 와 alt
: 시각에 어려움이 있는 경우 이미지를 이해할 수 없는데, 이미지가 전달하는 정보를 alt에 명시해서 스크린리더가 읽을 수 있게 해야한다.
alt는 <img>의 author를 정하는 속성이다.
-alt에 빈값('')을 주면 스크린리더가 읽지 않는다 ('Accessible Name')이 ''가 됨
-alt를 명시하지 않으면 스크린리더가 src를 읽으므로 반드시 alt를 명시해야 함.
6. role = "checkbox"
: 스크린리더가 "체크박스"라고 읽는다.
-aria-checked = "true|false"와 함께 사용하면. "선택됨/선택 해제됨"도 읽어준다.
-Children Presentational
7. role = "dialog"
: 사용자가 상호작용할 수 있는 대화상자이다.
8. aria-modal (7번에 이어서)
: 스크린리더가 dialog 밖의 요소에 포커스할 수 없게 만드는 속성이다.
스크린리더가 dialog만 포커스하게 되므로 사용자가 dialog를 잘 인지할 수 있다. (밑의 예시 참고)
9. aria-hidden
: 요소에 aria-hedden-"true"를 명시할 경우, 스크린리더가 해당 요소와 자식을 읽지 않는다.
10. role = 'alert'
: 다음과 같은 상황에서 스크린리더가 해당 요소를 읽어준다.
- 요소가 DOM Tree에 추가되엇거나
- 요소의 자식에 변경사항이 생겼을 때
** 케이스 스터디 **
1. 정체를 알 수 없는 버튼
위의 코드를 아래와 같이 고칠 수 있다.
--> 스크린 리더가 읽는 flow를 살펴보면, img태그의 author은 없기 때문에 accessible name은 '내 포인트 내역으로 이동' 이된다.
그리고 버튼에도 author가 없기 때문에 contents가 accessible name으로 결정이 되는데, 버튼의 컨텐츠는 조금 특수한 방식으로결정이 된다.
왜냐하면 button은 children presentational이라는 특징을 갖고 있는데, 이는 자식 요소에 accessible name을 모아서 그 요소에 컨텐츠로 사용한다. 그래서 버튼의 컨텐츠는 자식들의 accessiable name의 합이라고 볼 수있다.
따라서 이 버튼 컨텐츠는 곧 이 이미지 태그의 accessible name의 "내 포인트 내역으로 이동" 이 된다.
2. 대체 텍스트가 없는 이미지
시각사용자는 여기에 큰 의미를 두지 않는다. 그냥 장식용 이미지라고 생각하는 것이다.
하지만 스크린리더는 "imgempty.png"라고 읽어서 사용자에게 혼란은 주는데,
이 이미지의 코드는 alt가 명시되어있지 않기 때문에 scr값이 읽힌 것이다!
그렇다면 alt값을 빈값을 주면 스크린 리더가 그냥 지나간다는 점을 이용해서 아래의 코드와 같이 alt에 빈값을 주면 문제점을 해결할 수 있다.
3. 버튼일 수도 있고 아닐 수도 있다
시각사용자는 이 요소를
-> "저 브랜드는 20% 캐시백에 한도가 1천원이네"
-> "화살표를 보니 상세 페이지로 가는 버튼인가보다"
등등의 의미로 해석한다.
하지만 스크린리더는
-> "브랜드명 / 20 / 퍼센트 / 최대 / 천 / 원"
으로 끊어읽는다.
//문제점//
1. "브랜드명 / 20 / 퍼센트 / 최대 / 천 / 원" 이게 버튼이라는걸 모른다.
2. 하나의 정보를 끊어 읽어 이해가 어렵다.
//해결//
1. 버튼이라는걸 알려주면 되기 때문에 button 이라는 role을 사용하면 된다.
2. Children Presentational 을 이용해보자. 이 요소의 자식의 accessible name을 모아서 컨텐츠로 사용하기 때문에, 불필요하게 끊어읽는 이 정보들을 모아서 읽을 수 있을 것 같다!
4. 선택 / 취소할 수 있는 카드
이 화면을 봤을 때 시각사용자는
-> "카드 눌러서 선택하면 되겠구나. 다시 누르면 취소되겠지?"
라고 생각하지만,
스크린리더는
-> "명량핫도그 / 30 / 퍼센트"
라고 끊어읽는다.
//문제점//
1. 저 부분이 클릭할 수 있다는 사실을 모른다.
2. 하나의 정보를 끊어읽어서 이해가 어렵다.
3. 선택된 상태인지 모른다.
//해결책//
1-2는 위 케이스에서 해결!
3. role = "checkbox"를 이용해보자
--> 스크린리더는 "명량핫도그 30퍼센트, 체크상자, 선택 해제됨"이라고 읽게된다.
5. 다가갈 수 없는 바텀시트
시각사용자는
-> "카드를 눌렀더니 어디서 결제했는지 물어보는구나"
라고 인지하지만
스크린리더는 저 흰색 박스의 텍스트들을 쭉 읽고 바텀시트에 도달하지 못한다.
//문제점//
1. 바텀시트가 열렸지만 스크린리더 사용자는 알 수 없다.
//해결책//
role = "dialog"와 aria-hidden="true" 를 이용한다.
((위의 문제점을 자세히 설명하자면))
토스카드 버튼을 누르면 바텀시트가 뜨는데 스크린 리더는 아무것도 읽지 않게 된다.. 그리고 사용자가 몇번 더 눌러보지만 아무일도 일어나지 않고 스크린리더는 다음 요소인 "프론트엔드 카드" 읽는데 여기서 사용자는 서비스 사용을 포기하게 된다.
++ 그리고 자바스크립트로 모달을 열었을 때 바텀창이 아닌 모든것들의 aria-hidden = "true"로 바꿔주는 스크립트를 작성
6. 소리없는 토스트
이런 화면 하단의 토스트를 봤을 때,
시각사용자는
-> "2개까지만 추가할 수 있구나"
라고 생각할 수 있지만,
스크린리더는 아무것도 읽지 않는다.
//문제점//
토스트를 띄워서 더 선택할 수 없다는 경고를 했지만, 눈으로만 확인할 수 있다.
//해결책//
role = 'alert'를 추가해준다.
결론적으로 프론트엔드 개발자는 tag를 변경하거나 속성을 1-2개 추가하는 정도로 UX를 개선할 수 있다.
'Web' 카테고리의 다른 글
[웹심화] SSR 과 CSR (우리가 옳은 선택을 했나?) (1) | 2023.01.13 |
---|---|
[웹심화] Next.js (0) | 2022.11.30 |
[웹심화] SWR : 데이터를 가져오기 위한 React Hooks (0) | 2022.10.21 |