공부 모음집/WEB

접근성 준수와 스크린리더

leedaramji 2023. 11. 26. 20:14

접근성 준수와 스크린리더

 
스크린리더를 신경 쓰지 않고 개발을 하는 경우, 스크린리더 사용자를 차별하는 개발을 할 수가 있다. 웹 접근성을 준수하여 장애가 있는 사용자가 보다 쉽게 차별 없이 웹 사이트나 애플리케이션을 이용할 수 있도록 만들어야 한다. 그렇기 때문에 항상 접근성을 준수하여 스크린리더 UX 개선에 신경 쓰는 개발을 해야 한다. 스크린리더는 모바일과 데스크톱 동작 방식이 다르다. 해당 게시물은 모바일 스크린리더에 대한 내용이다. 
 

✅ 웹 접근성에 대한 스크린리더를 공부하고 알게 된 점

코드를 마크업을 할 때  사용하는 태그나 속성을 조금만 신경써서 작성하면 스크린리더의  UX가 많이 개선된다는 점을 알게되었다. 장애인과 고령자 등의 사용자들도 편리하게 이용할 수 있는 UX와, 서비스를 제공할 수 있는 코드가 생각보다 어려운 것이 아니라는 점이다. 그러므로 누구나 차별 없이 서비스를 이용할 수 있는 개발을 위해 앞으로 더 관심을 가지고 신경쓰도록 해야겠다.
 


 
📌 접근성 키워드

  1. 장애를 가진 사람, 고령자 등 누구나 동등하게 쓸 수 있는
  2. 시멘틱 HTML
  3. WAI-ARIA
  4. 스크린리더
  5. 키보드 인터랙션

 

📌 알게된 개념

  1. Accessible Name
    • 스크린리더가 포커스했을 때 읽는 값
    • author > contents
    • wai-aria 속성
  2. Role
    • role 마다 기대되는 동작 ex. role="button"은 "버튼"을 붙여 읽음
    • 시멘틱 태그는 암묵적인 role을 가지고 있다. ex) <button>
  3. Children Presentaional
    • 자식요소의 Accessible Name을 모아서 contents로 (끊어 읽는 문제 해결)
    • 자식요소를 스크린리더가 읽지 않도록
  4. <img>와 alt
    1. alt="" 빈값을 주면 스크린리더는 읽지 않음
    2. alt 명시하지 않으면 src 읽음
  5. 선택/ 취소
    • role="checkbox" - 체크박스
    • aria-checked="true|false" - 선택됨/ 해제됨
  6. 모달창- 다이어로그
    • role="dialog" :사용자가 상호작용할 수 있는 대화상자
    • aria-hidden: true - dialog 외에는 요소 포커스할 수 없음
  7.  소리없는 토스트
    • role="alert" - 내용 읽어줌

 


1. 스크린리더가 앱을 읽는 방법

 

<did>스크린리더</div>
<div>
	<div>
    	<div>커피</div>
        <div>빵</div>
        <div>버터</div>
    </div>
    <div>라따뚜이<div>
<div>2023</div>

 
🔊읽는 순서: 스크린리더 ➡️ 커피 ➡️ 빵 ➡️ 버터 (↩️ 좌측으로 스와이프  )➡️ 빵➡️ 버터➡️ 라따뚜이 ➡️ 2023
 

  • 움직이는 단위: 요소(HTML Element)로 탐색
  • 순차 탐색: 손가락을 좌우로 스와이프 하면 앞뒤로 이동
  • 스크린 터치: 터치한 영역에 있는 요소를 선택
  • 로터(스크린리더 유틸리티)를 이용한 탐색: 머리말/ 단어/ 글자 단위로 이동 가능

 


1-2. Accessible Name

 
- 스크린리더가 요소를 포커스 했을 때 읽는 값

  1.  author: 특별한 속성을 사용해서 정하는 값
    • aria-label, aria-labelledby, alt(<img>)
  2. contents: 요소의 텍스트값

 
☑️ 우선순위 : author > contents
☑️ Accessible Name은 author와 contens 둘 중에 하나로 결정된다.
 

<div>접근성을 중요하다</div>

contents 🔊 접근성은 중요하다
 

<div aria-label="A11Y는 중요하다">
	접근성을 중요하다
</div>

author 🔊 A11Y=는 중요하다
 

1-3. Role

 
- 스크린리더가 요소를 어떤 방식으로 다룰지 결정하는 속성
- Role마다 기대되는 스크린리더 동작이 있다.

  • 예) role="button"
    • 요소의 Accessible Name을 읽은 뒤 "버튼"을 붙여 읽음
    • 자식 요소의 Accessible Name을 모아서 contents로 사용

 

시멘틱 태그와 Role

 
- 시멘틱 태그는 암시적으로 Role을 갖고 있다.

  • <button> role="button"
  • <a>: role="link"
  • <input type="checkbox">: role="checkbox"
  • etc...

 

<button>
	클릭하기
</button>

<!-- = 동일하다 -->

<button role="button">
 	클릭하기
</button>

🔊 클릭하기 버튼
 

1-4. Children Presentational

 

  • 특정 Role이 가진 특징
  • 자식 요소의 Accessible Name을 모아서 요소의 contents로 사용
  • 자식 요소를 스크린리더가 읽지 않도록 한다.
  • 시각 사용자가 묶어서 이해하는 정보를 스크린리더가 끊어읽는 문제를 해결할 때 유용함✅

 

<div role="button">
	<span>커피</span>
    	<span>빵</span>
    	<span>버터</span>
</div>

🔊 커피 빵 버터, 버튼
 
☑️ 여기서 contents는 "커피+빵+버터"
☑️ 위 div 태그는 별도의 author를 가지고 있지 않기 때문에 Accessible Name은 contents인 "커피+빵+버터"가 된다.
☑️ 그리고 role은  Accessible Name을 읽은 뒤 "버튼"을 붙여 읽기 때문에 "커피 빵 버터 버튼"이라고 읽는다.
 


3. 케이스 스터디

 

Case 1: 정체를 알 수 없는 버튼

 

📌 <img>와 alt

- 시각에 어려움이 있는 경우 이미지를 이해할 수 없다.
- 이미지가 전달하는 정보를 alt에 명시해서 스크린리더가 읽을 수 있게 해야 한다.
- alt에 빈 값("")을 주면 스크린리더가 읽지 않는다(Accessible Name이 ""이 됨)
- alt를 명시하지 않으면 스크린리더가 src를 읽으므로 반드시 alt를 명시해야 한다.

 

<button>
	/*<img src="이미지 연결" alt="">*/
    <img
    	src="이미지 연결"
        alt="라따뚜이는 요리사"
   	>
</button>

🔊 버튼
🔊 "라따뚜이는 요리사, 버튼"
 
☑️ <button>의 contents: 자식들의 Accessible Name의 합이다.

  • button은 암묵적으로 role을 가진다.
  • children presentaional 특징을 갖기 때문에 자식 요소의 Accessible Name을 모아서 contents로 갖는다. 

 
✅ 문제점과 해결

  • 정체를 알 수 없었던 버튼이 alt만 명시해줬을 뿐인데 어떤 버튼인지 알수 있게 된다.

 


Case 2: 대체 텍스트가 없는 이미지
 
(의미가 없는 이미지)

<img src="/라따뚜이.png">

🔊 "라따뚜이.png, 이미지"
 

<img src="/라따뚜이.png" alt="">

🔊 ...
 
✅ 문제점과 해결

  • alt에 "" 빈값을 주면 스크린리더는 읽지 않는다.

 


Case 3: 버튼일 수도 있고 아닐 수도 있다.
 

<-- 기존 코드 -->
<div>
	<img
    	src=/이미지 경로"
        alt="라따뚜이"
    >
 	<div>
    	<span>프랑스</span><span>파리</span>
        <img src="이미지 경로" alt="">
    </div>
    <div>
    	<span>최고의 요리사</span>
        <span>레스토랑</span><span>쉐프</span>
    </div>
</div>

🔊 라따뚜이 / 프랑스/ 파리/ 최고의 요리사/ 레스토랑/ 쉐프
 
✅ 문제점과 해결

  1. 위의 버튼이 버튼이라는 것을 모른다.
    • role="button"
  2. 스크린 리더가 하나의 정보를 끊어 읽어서 이해가 어렵다.
    • Children Presentaional : <div> 태그를 <button> 태그로 바꿔준다. 그러면 children presentaional 특징 때문에 자식 요소의 Accessible Name을 모아서 읽어준다.

 
🔊 라따뚜이 프랑스 파리 최고의 요리사  쉐프
 


Case 4: 선택 / 취소
 

📌 role="checkbox"

- 스크린리더가 "체크박스"라고 읽음
- aria-checked="true|false"와 함께 사용하면, "선택됨/선택 해제됨"도 읽어줌
- Children Presentational

 

<-- 선택 안됨 -->
<div
	role="checkbox" aria-checked="false"
>
	<img src="이미지 경로" alt="">
    <span>라따뚜이</span>
    <span>파스타</span>
    <span>맵게</sapn>
</div>

🔊 "라따뚜이 파스타 맵게, 체크상자, 선택 해제됨"
 


Case 5: 다가갈 수 없는 바텀시트
 

📌 role="dialog"

- dialog: 사용자가 상호작용할 수 있는 대화상자 (모달창, 팝업)

- aria-modal: 스크린리더가 dialog 밖의 요소에 포커스할 수 없게 만드는 속성
➡️ "true"인 경우 스크린리더가 dialog만 포커스하게 되므로 사용자가 dialog를 잘 인지할 수 있음
➡️ 스크린리더가 구현하지 않은 경우가 있어 직접 구현 필요하다.💡
➡️ TODO: 모달인 dialog가 열렸을 때 dialog 밖을 포커스할 수 없도록 만들기
    ㄴ> Dialog 요소 외의 요소를 포커스할 수 없게 만들기(aria-hidden)
        ㄴ> 자동으로 포커스가 Dialog로 옮겨가게 됨

 

📌 aria-hidden

- 요소에 aria-hidden="true"를 명시할 경우, 스크린리더가 해당 요소와 자식을 읽지 않는다.
<div aria-hdden="true">
	<span>라따뚜이</span>
</div>

🔊 ... (스크린리더는 읽지 않는다.)
 

    <div>
        <h1>주문하시겠습니까?</h1>
        <h2>등록된 카드를 보여드립니다. 결제하셨나요?</h2>
    <div>
    <div>
    	<button>카카오 카드</button>
        <button>국민 카드</button>
        <-- ...-->
    </div>    
    <-- 바텀 시트 -->
    <div>
        <div role="dialog">
            <-- 시각적으로 보이지 않는 스크린리더용 버튼 추가-->
            <button className="sr-only">닫기</button>
            <header>어디에서 결제했나요?</header>
            <--... -->
    	</div>
    </div>        
</body>
<-- 스크립트 추가-->
function openModal(dialogContainerElement) {
	[...document.body.children].forEach(element => {
    	if (dialogContainerElement !== element) {
        	element.setAttribute('aria-hidden', 'true');
        }
     });
 }

☑️ 모달을 열었을 때 dialog를 제외한 모든 요소에 aria-hidden을 true로 바꾸는 코드다.
 

<div aria-hidden="true">
    <h1>주문하시겠습니까?</h1>
    <h2>등록된 카드를 보여드립니다. 결제하셨나요?</h2>
<div>
<div aria-hidden="true">
    <button>카카오 카드</button>
    <button>국민 카드</button>
    <-- ...-->
</div>

☑️  모달창이 열리면 dialog가 아닌 모든 div 태그에 aria-hidden="true"가 추가된다. 그러면  스크린리더가 해당 요소와 자식을 읽지 않는다. 그리고 스크린리더는 aria-hidden="true"가 없는 바텀시트 요소에 포커스가 가게 된다.
 


 
Case 6: 소리없는 토스트
 

스크린리더는 읽지 않고, 눈으로만 확인가능한 상황
 

📌 role="alert"

- 다음과 같은 상황에서 스크린리더가 해당 요소를 읽어줌
  1. 요소가 DOM Tree에 추가되었거나
  2. 요소의 자식에 변경사항이 생겼을 때
<div>
	최대 2개 추가할 수 있습니다.
</div>

🔊 ...
 

<div role="alert">
	최대 2개 추가할 수 있습니다.
</div>

🔊 최대 2개 추가할 수 있습니다.
 
☑️ role="alert"만 추가했을 뿐인데 유용한 정보를 전달하는 방식으로 코드가 바뀌게 된다.
 
 
📕공부 출처: https://youtu.be/tKj3xsXy9KM?si=f9nm_TpXz-B3d5yA

'공부 모음집 > WEB' 카테고리의 다른 글

FireBase란? (+ cloud 서비스란?)  (0) 2024.03.26
SPA (Single Page Application)  (2) 2023.12.05
💡 브라우저 좌표  (0) 2023.11.07
Web APIs  (0) 2023.11.07
url 입력과정  (0) 2023.10.17