접근성 2/4 (점검)

(잠안와서 생각중..수정계획중)

처음 사용자 상세/전문가 상세로 간단 수정인 줄 알았다가
검수하면서 추가적인 요건이나 수정사항이 생겨서
정확한 완성을 위해 혼동되거나 미비해보이는 것을
아예 전반적으로 처음부터 되짚어 보았다.


0. 공통 우선사항

1) 크롬/엣지는 브라우저 자체에 보정기능 등이 있어 tab키 인식 빠름 (IE만 마크업이나 속성이 정확하지 않으면 아예 새로고침 여러번해서 인식하거나 포커싱이 느림)

2) 스크린리더의 기준

  • 공식 스크린리더
    Windows : (IE) 센스리더 / (IE/Firefox) NVDA, Jaws for Windows, Window-Eyes
    MacOS : (Safari) VoiceOver
  • 현재 작업 후 MS 내레이터로 듣고 있음

1. skipNavi

(1) skipNavi ul>li>a/button 구조일 경우
-li role="presentation" 속성 (tab1 > tab2 > tab3 > tabpanel1 > ... 포커싱 초점이동)
-a/button에는 tabindex 항목 (활성화 : 0 , 비활성화 : -1) ---> 비활성화여도 tab1>2>3으로 포커싱 초점이동됨
(IE는 동작함)

(2) 1번 적용해보고 안될 경우
div>a 구조로 변경 (script 추가 수정)


2. gnb

  • 크롬/엣지 : gnb 2depth는 펼쳐짐, 2depth는 읽지는 않음
  • IE : gnb 2depth 펼쳐지지않음 but 2depth 요소 일부를 읽음 (이건 대부분 사이트가 동일)

3. tab

선택됨의 경우 aria-selected (true/false)
true일때만 title 속성으로 선택됨 넣어줌
(비활성화 = 선택되지않은 tab에 대해서는 소리 필요x)

  • 필수 role="tablist" 탭 메뉴 리스트
  • 필수 role="tab" 탭 메뉴
  • 필수 role="tabpanel" 탭 내용
  • 선택 role="none" (ul > li 구조에서 해당 역할을 하지 않는 경우 필수)

(1) ul>li>a/button 구조

<ul role="tablist">
    <li role="presentation">
        <button type="button" role="tab">tab01</button>
    </li>
    <li role="presentation">
        <button type="button" role="tab">tab02</button>
    </li>
</ul>

role="presentation", role="none"
: semantic의미를 요소와 그 자식요소로부터 제거하기 위해서 사용한다.
시각적으로 게시하는 용도의 요소에 적용.
none은 최근에 나온 속성값으로 presentation과 같은역할을 한다.
호환성문제가 있을 수 있으니까 두개 다 기입해 주는것이 좋음.
https://inswave.com/confluence/pages/viewpage.action?pageId=19076563

(2) div>a/button 구조

<div role="tablist">
    <button type="button" role="tab">tab01</button>
    <button type="button" role="tab">tab02</button>
</div>

ul > li 구조를 잡지 않는게 최선이나 개발 상의 이유로 해당 구조가 강제되는 경우가 있을 수 있다.
아무튼 위 마크업의 보조기기 음성안내 결과는 “목록 항목수 1개”이다.
ul/ol 요소에는 기본값으로 role='list' 속성값이 적용되어 있고,
해당 속성값을 가진 요소의 자식 요소는 모두 목록으로 인식되기 때문이다.
목록의 의미를 원천적으로 제거하려면 ul과 li 모두 해당 속성값을 선언해야 한다.
근데 굳이 이렇게까지 구성할 필요는 없음.. 그렇다면 어떻게 올바르게 적용할 수 있을까?
아래 예시는 탭 UI의 마크업을 구성할 때 흔하게 사용되는 예시이다.
button 요소에 tab 역할을 부여하고, 사이에 있는 li 요소의 의미를 제거,
상위 ul 요소에 탭 목록을 묶어주는 컨테이너 역할을 부여하였다.
결론부터 말하면 사용자의 인식에는 문제가 없으나 명백히 잘못된 마크업이다.
목록의 의미를 원천적으로 제거했으므로 ul/ol의 의미가 없게 되었고,
애초에 목록을 ul/ol 요소로 구성해야 한다는 고정관념이 어디서부터 시작된 건지..
https://selosele.github.io/2020/12/19/about-wai-aria2/


4. tab/tabpanel 내 이동 문제

기본적으로 tab으로 포커싱이 순서대로 읽히고 이전 요소 인식하려면 shift+tab (back 개념)
다만 tab1 (활성화) | tab2 (비활성화) | tab3 (비활성화) 인 경우에는

(1) tab1 (활성화) tabindex="0", tab2/3 (비활성화) tabindex="-1"인 경우면
tab1 (활성화) → tabpanel1 (활성화된 탭의 패널) 순서로 포커싱 이동

(2) 1케이스에서 활성화든 비활성화든 tab 메뉴 전체를 읽으려면
ul>li>a 구조라면 li에 role="presentation"을 추가하거나

활성화된 첫번째 탭에서 엔터 선택 시(사용자가 직접 눌러서) 비활성화된 이후 탭요소를
키보드로 포커싱하는 경우가 있음
(공통 사항으로는 내레이터에서는 일단 모든 탭을 다 읽고 총 갯수 인식)

심사원에서는 tabindex는 가급적 지양해달라고 했는데,
case1로 해야할지 case2로 해야하는지 확인해봐야할거 같음
(nuli 공식사이트에서는 case2고 nuli 내 naver a11y사이트에서는 case1로 되있음)

(3) wa 인증받은 사이트들의 경우에는 tab에 tabindex를 안 넣고 aria-selected만 넣거나
아예 wai-aria 속성 안 넣고 순서대로 읽는 경우도 있었음
(이거는 정답 기준이 없는 것 같은데..)

(추가사항)
w3.org 예시 탭에서는 tab1 > tabpanel1로 이동하고 (tab2,3은 tabindex="-1"이라 스킵됨)
다만 비활성화인 탭은 키보드 제어를 추가해서 tab1에서 keypress 시에 tab2,3로 이동되고있음

https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/tabs.html


5. tab 활성화 시 변경되는 select(listBox/comboBox UI)

  • select의 경우, ul>li로 별도의 listBox/comboBox UI으로 변경하지 않으면 브라우저의 어느 높이값에서 활성화시키느냐에 따라 위 또는 아래로 펼쳐지는 경우 있음 (크로스브라우징 이슈)
  • 비활성화된 두번째 탭 활성화 시 select box로 변경되어야 하는데..
    이때 포커싱하면 탭1 -> 탭2의 가제목 -> 탭2의 select 이렇게 포커싱이 3번 가게됨 (shift+tab으로 돌려도 마찬가지)

탭2의 가제목을 숨김 처리할 수 있는 idea

(1) css 속성으로 opacity:0; z-index:-1; 넣고 이후 js로 제어 (네이버세미나에 나온 내용)

그러면 탭2 가제목이 처음 비활성화일때는 보여주다가
탭2가 활성화되면 가제목요소에 숨김 속성을 넣고(display:none 아님)
탭2의 select(dropdown)이 바로 선택되게 하란 거 같은데

확인사항

<div class="se-property-toolbar-label-select-container __select-container">
  <button type="button" title="" class="se-font-size-code-toolbar-button se-property-toolbar-label-select-button se-is-activated" aria-expanded="true" aria-haspopup="true">
    <span class="se-toolbar-label" data-role="label" aria-hidden="true">26</span>
    <span class="se-toolbar-tooltip">글자 크기 변경</span>
  </button>
  <div class="se-toolbar-option se-toolbar-option-font-size-code" role="listbox">
    <button type="button" title=""  class="se-toolbar-option-text-button se-toolbar-option-font-size-code-fs11-button" aria-current="true">
      <span class="se-toolbar-option-label" aria-hidden="true">26</span>
      <span class="se-toolbar-tooltip">26</span>
      <span class="se-blind">선택됨</span>
    </button>
    <button type="button" title=""  class="se-toolbar-option-text-button se-toolbar-option-font-size-code-fs11-button" aria-current="false">
      <span class="se-toolbar-option-label" aria-hidden="true">32</span>
      <span class="se-toolbar-tooltip">32</span>
    </button>
    <button type="button" title=""  class="se-toolbar-option-text-button se-toolbar-option-font-size-code-fs11-button" aria-current="false">
      <span class="se-toolbar-option-label" aria-hidden="true">38</span>
      <span class="se-toolbar-tooltip">38</span>
    </button>
    </div>
</div>
.se-body .se-toolbar-button-tooltip { opacity:0; z-index:-1; }
.se-body .se-toolbar-button:hover .se-toolbar-button-tooltip { opacity:1; z-index:1; }

aria-current="true" 속성사용
<span class="offscreen">선택됨</span> 넣어줌

  • 스크린리더로 들었을때 비활성/접힌상태 > 축소가 기본
  • 엔터(선택 시) 활성/펼쳐진상태 > 확장

https://smarteditor.naver.com/desktop/

(2) 탭2 내에 select 넣기 > 이런 경우면 아이디/아이핀 사이트를 공통으로 맞춰야 하는데..
약관 버전명 변경하는 스크립트때문에 여기서 꼬일 거 같음

(3) 선택목록
select 안 쓰고 그냥 button/ul, li로 만든 후
첫번째 button요소를 탭2로 하는 방법으로 변경

<button aria-haspopup="listbox" aria-controls="li_sort" aria-expanded="false">네이버 랭킹순</button>
<ul id="li_sort" role="listbox" aria-labelledby="select_lb" style="display:none">
	<li id="li_sort01" role="option" aria-selected="false" tabindex="0">네이버 랭킹순</li>
	<li id="li_sort02" role="option" aria-selected="false" tabindex="0">낮은 가격순</li>
	<li id="li_sort03" role="option" aria-selected="false" tabindex="0">높은 가격순</li>
	<li id="li_sort04" role="option" aria-selected="true" tabindex="0">등록일순</li>
	<li id="li_sort05" role="option" aria-selected="false" tabindex="0">리뷰 많은순</li>
</ul>
  • 필수 role="listbox" 선택 목록
  • 필수 role="option" 선택 목록에서 선택 가능한 항목
  • aria-haspopup="true"
    메뉴를 열기 위한 버튼에 설정 혹은 메뉴 항목이 서브메뉴를 가진 경우 설정하며,
    메뉴 버튼인 경우 해당 버튼이 팝업 메뉴를 가지고 있음을 스크린 리더 사용자가 알 수 있도록 하기 위해 사용합니다.
  • aria-expanded="true"
    메뉴가 확장되었음을 나타낼 때 사용됩니다.
    스크린 리더는 <접근성 메뉴 확장됨> 등과 같이 스크린 리더 사용자에게 알립니다.

참조
https://nuli.navercorp.com/
https://nuli.navercorp.com/tool/waiAria
https://accessibility.naver.com/assistance


해결실마리 찾기 - 스크린리더 확인사항

(1) 내레이터

  • 내레이터는 기본적으로 탭 개수에 따라 1/N으로 읽음 (탭1 1/3, 탭2 2/3, 탭3 3/3)
  • wai-aria 속성 안 넣는 경우 버튼, 단추 이런 식으로 읽음
  • ul>li>a/button인 경우 : 총 개수 인식 안되서(li로 덮어쓰면 연결된 탭 목록이라고 인식하지 않는거 같음) 탭 A 1/1, 탭 B 1/1.. 로 읽음
  • div>a/button인 경우 : 탭 A 1/3, 탭 B 2/3, 탭 C 3/3 (정확하게 읽음)
  • ul>li role="presentation"> a/button인 경우 : 탭 A 1/3, 탭 B 2/3, 탭 C 3/3 (이렇게 바꿔야 할듯)

(2) 센스리더

  • div>a/button인 경우 : 링크 A, 링크 B...
  • ul>li>button인 경우 : "A, B, C, ...." (순서대로 읽는데 탭 속성 안읽고, 1/N 개수 안셈, 선택됨 안 읽음)

(3) NVDA

  • div>a/button인 경우 : 구조 : 링크 A, 링크 B ...
  • ul>li>button인 경우 : "탭 선택됨 A, 탭 B, 탭 C"로 읽음 (1/N 갯수 안셈)
  • ul>li>a (탭 아닌 목록) : 목록 시작 ~ 목록 끝 (이랬던거같음)

(4) Jaws for windows
설치안되서 확인못함

(기타) title="선택됨" 속성 인식하지 않는 경우 때문에
숨김텍스트 span 요소로 append/text 하는 거 같기도 함


느낀 점

결론 : 일단 최대한 기존 마크업에서 wai-aria 속성을 더 넣고 select(drowdown)만 다시 짜야될 거 같음 (li role="presentation"을 미리 알았더라면.. 많이 바뀌면 반영도 힘들거같고)

  • 몇개는 기준이 애매해서 확인해봐야할거 같은데 -> 스크린리더 비교해서 들어보니 어느정도 힌트얻음

  • wa 심사인증받은 사이트 몇개 봤는데 결국 다 달라서 nuli 기준에 맞춰서 하는 게 나은듯함 (갓네이버) 참조할라고 f12로 보는데 skipNavi랑 gnb랑 동일하고 그 외엔 다 달라서 이 글 쓰게 됐다는거...

  • 주석.txt 안써도 vscode 작성 > sourcetree 열어서 commit > gitlab에서 확인하고 commit한 변경 부분만 바로 볼수있게 전달하면 얼마나 좋을까..

  • 난 원래 챌린지하는 걸 좋아하지만 몇몇갠 딱 떨어지는게 아니라서 어렵다... 시행착오중... (기획자한테 좀 미안했음..ㅠ)

  • 그래도 과정이든 시간을 들이든 답이 딱 안나오면 어쩔수없는거 같다
    좀 시간을 들여서 보면 수정은 되는데 빨리 딱 안된다는게 문제
    (머리회전 부엉이)

좋은 웹페이지 즐겨찾기