프로젝트를 리팩토링하려고 하는데, 현재 스크린 리더만으로 서비스를 이용하는데 어려움이 있어, 이에 대한 내용부터 개선을 진행하려고 한다.
웹 접근성에 대한 개념과, 웹 접근성이 좋아야하는 이유, 개선 방법들을 알아보고 프로젝트에 적용해볼 것이다.
웹 접근성 이란 장애가 있는 사람들도 웹을 인지하고, 이해하고, 탐색하고, 상호작용할 수 있으며, 웹에 기여할 수 있도록 보장하는 것이다.
WCAG(Web Content Accessibility Guidelines) 는 이 웹 접근성을 달성하기 위해 4가지 핵심 원칙(P.O.U.R) 을 제시한다.
그렇다면 우리는 왜 웹 접근성을 고려해야할까?
웹의 창시자 팀 버너스 리 는 이렇게 말했다.
웹은 모두를 위한 것입니다. 누구든, 어떤 기기든, 어떤 능력이든 간에 접근할 수 있어야 합니다.
— Tim Berners-Lee
애초에 웹은 모든 사람이 자유롭고 평등하게 정보에 접근할 수 있도록 설계되었다.
모든 이들이 동일한 수준으로 웹을 사용할 수는 없겠지만, 처음 설계된 목적에 맞게, 그 이상에 최대한 가까워지기 위해 우리는 웹 접근성을 고려해야 할 것이다.
웹 접근성을 고려하는 것은 검색 엔진 최적화(SEO) 측면에서도 실질적인 이점을 가져다준다.
접근성을 고려하기 위해 적절한 시맨틱 태그를 활용하면, 이는 검색 엔진 크롤러가 페이지의 콘텐츠를 더 잘 이해할 수 있도록 돕는다.
뿐만 아니라, SEO를 개선하기 위한 명확한 콘텐츠 구조, 키보드 내비게이션, 텍스트 대체 설명 등은 장애 유무와 관계없이 모든 사용자에게 더 나은 경험을 제공하므로, 사용자 경험(UX)도 자연스럽게 향상된다.
결국, 이는 사람들의 유입과 더 많은 콘텐츠의 노출로 이어지며, 서비스의 접근성이 향상되어 비즈니스적으로 긍정적인 효과를 낳는다.
WCAG 는 4가지 핵심 원칙으로 Perceivable(지각 가능) Operable(운용 가능) Understandable(이해 가능) Robust(견고함) 을 언급한다.
이 중 하나라도 충족되지 않으면, 장애가 있는 사용자는 웹을 사용할 수 없다고 판단한다.
정보와 사용자 인터페이스 구성요소는 사용자가 지각할 수 있는 방식으로 제공되어야 합니다.
이 말은, 모든 사용자가 웹에서 제공되는 정보를 어떤 방식으로든 인식할 수 있어야 한다는 뜻이다.
이를 위해 다음과 같은 방식을 고려할 수 있다고 한다.
사용자 인터페이스 구성요소와 내비게이션은 운용 가능해야 합니다.
이 말은, 웹에서의 모든 상호작용이 사용자가 실행할 수 있는 방식으로 제공되어야 함을 의미한다.
즉, 사용자가 실제로 상호작용할 수 없는 요소나 인터페이스는 없어야한다.
정보와 사용자 인터페이스의 작동은 이해 가능해야 합니다.
이는 애플리케이션에서 제공되는 정보와 인터페이스가 사용자가 이해할 수 있는 방식으로 제공되어야 한다는 의미이다.
콘텐츠는 보조 기술을 포함한 다양한 사용자 에이전트에 의해 신뢰성 있게 해석될 수 있을 만큼 견고해야 합니다.
웹 콘텐츠가 다양한 기술 환경에서 잘 동작할 수 있도록 설계되어야 한다는 의미이다.
즉, 기술의 발전이나 새로운 장치나 브라우저가 등장하더라도 웹 콘텐츠는 항상 접근 가능하고, 사용자에게 문제없이 제공되어야 한다는 원칙이다.
HTML CSS JavaScript 와 같은 웹 기술이 W3C 의 표준을 따르도록 작성되어야 함.)웹 접근성이 중요한 이유, 4가지 핵심원칙에 대해 알아봤으니, 이제 실제로 어떻게 웹 접근성을 개선할 수 있는지에 대해 알아보자.
시멘틱 태그 란 HTML에서 의미를 담고 있는 태그를 말한다. 비시맨틱한 역할을 하는 div 나 span 사용을 지양하고, header main 과 같은 시맨틱 태그를 사용해야한다.
시멘틱 태그를 사용하면 모든 사용자가 페이지의 구조를 명확하게 이해할 수 있으며,
콘텐츠를 구분하기 쉬워지고 혼란을 줄일 수 있다.
예를 들어, strong 태그는 스크린 리더에서 해당 문장을 더 강하게 읽어주며, 검색 엔진도 이 문장을 중요한 정보로 인식한다.
결국 시멘틱 태그는 보조 기술이 페이지의 구조와 핵심 내용을 더 쉽게 파악하게 도와주고, 접근성과 사용자 경험을 모두 향상시킨다.
이미지는 시각적 정보이므로 시각장애인은 내용을 인식할 수 없다.
따라서, alt 속성으로 대체 텍스트를 제공해야 한다.
<img src="coke.jpg" alt="코카콜라 사진"/>
하지만, 의미 없는 배경이나 아이콘 이미지의 경우 alt 를 빈 값으로 둬서 스크린 리더가 무시하도록 하는게 좋다.
만약에 비디오 콘텐츠가 있다면, 청각장애인을 위해 자막(track)이나 전체 스크립트를 함께 제공해야 한다.
마우스를 사용할 수 없는 사용자도 있기 때문에, 페이지 내의 모든 상호작용은 Tab Enter Space 키로만 조작이 가능해야 한다.
Tab 키를 통해 HTML 구조를 따라 논리적인 순서로 이동할 수 있도록 마크업을 구성해야한다.
tabindex 속성은 수동으로 탭 순서를 지정할 수 있지만, 과도한 사용은 지양해야 한다.
실제로 HTML 요소가 시멘틱 태그로 잘 구성되어 있다면, tabindex 를 자주 사용할 필요 없이 자연스러운 탭 순서가 자동으로 결정된다.
과도한 tabindex 은 오히려 비논리적으로 구성되어 사용자에게 혼란을 줄 수 있고, 보조 기술을 사용하는 사용자에게도 문제가 된다.
또한, tabindex 를 사용하는 기존 요소에 수정이 필요하거나, 다른 요소가 추가될 때마다 tabindex 값을 계속 수정해야 할 필요성이 생기기에, 유지보수에도 악영향을 초래한다.
tabindex = "0" 을 사용하면, div 나 span 과 같은 기본적으로 포커스를 받을 수 없는 요소를 탭 순서에 포함시킬 수 있다.
일반적으로 포커스를 받을 수 없는 요소들이 반드시 탭 순서에 포함되어야 할 때, 사용하면 유용하겠다.
tabindex = "-1" 을 사용하면, 해당 요소가 탭 순서에서 제외되며, 해당 요소에 포커스가 이동하지 않는다.
해당 속성을 사용하면 모달 창이 띄워졌을 때, 배경은 탭 순서에서 제외되어 사용자는 모달 내부 요소만 탐색할 수 있게된다. 이는포커스 트랩 을 구현하는 데 유용하다.
텍스트와 배경 간의 적절한 대비가 모든 사용자가 환경에 구애받지 않고 웹을 쉽게 읽을 수 있도록 돕는다.
WCAG 에 따르면, 일반 텍스트는 배경과의 대비가 최소 4.5:1 이상이어야 한다.
이는 텍스트가 배경과 충분히 구분되어 가독성을 높이고, 시각적 편안함을 제공하는 최소 수치라고 한다.
그리고, 색상만을 중요한 정보를 전달하지 않는 것도 중요하다고 한다.
버튼이나 경고 메시지에서 색상만으로 상태를 표현하지 말고, 아이콘이나 텍스트 등 여러 방법을 통해 함께 제공하는 것이 권장된다.
적절한 폰트 크기는 사용자가 웹을 쉽게 읽게 돕는다.
글자가 너무 작으면 여러 환경에서 읽기 어려울 수 있기 때문에, 최소 크기 기준을 정하는 것이 좋다.
px 단위로 폰트를 설정하면, 웹 페이지의 텍스트 크기가 고정되기 때문에 rem 단위를 사용해 폰트 크기가 상대적으로 조절 가능하게 하는 것이 좋다.
본문 텍스트는 최소 1rem(16px) 이상이 권장되고, 이는 모바일에서도 읽기 쉬운 크기를 보장한다.
반응형 디자인은 다양한 화면 크기와 디바이스 환경에 맞게 웹 페이지를 최적화하는 디자인 방식 이다.
화면이 큰 디바이스와, 화면이 작은 디바이스는 아무래도 표현할 수 있는 콘텐츠의 양이 다르다. 이를 고려하여 웹사이트를 설계하는 것이 중요하다.
이를 통해, 사용자가 어떤 장치를 사용하더라도 콘텐츠가 잘 표시되고, 정보가 쉽게 탐색될 수 있도록 도울 수 있다.
이는 웹 접근성 향상에도 중요한 역할을 한다.
WAI-ARIA (Web Accessibility Initiative - Accessible Rich Internet Applications) 은 시각적, 청각적 장애를 가진 사용자가 웹을 원활하게 사용할 수 있도록 도와주는 기술이다.
스크린 리더와 같은 보조 기술이 웹 콘텐츠를 더 정확하게 이해하고 사용자에게 제공하는 걸 돕는다.
자주 사용되고 중요한 속성들을 살펴보자!
aria-labelledby 는 어떤 요소의 이름 또는 설명을 다른 HTML 요소의 콘텐츠로부터 가져오고 싶을 때 사용한다.
<h2 id="formTitle">회원 가입</h2>
<form aria-labelledby="formTitle">
</form>
이렇게 사용하면 form 요소가 자신을 설명할 이름을 formTitle 이라는 id를 가진 요소의 콘텐츠로부터 가져온다는 의미이다.
따라서 스크린 리더는 이 form 을 사용자에게 회원 가입 이라고 설명한다.
aria-label 은 웹 요소에 대한 텍스트 레이블을 명시적으로 지정할 때 사용되는 속성이다.
화면에 보이는 텍스트가 없거나, 텍스트가 명확하지 않은 경우에 유용하다.
aria-labelledby 은 이미 페이지에 존재하는 다른 요소(제목, 설명 텍스트 등)의 id를 참조하여 해당 콘텐츠를 레이블로 사용하고,
aria-label 은 특정 요소에 대한 텍스트 레이블을 직접 제공 한다는 차이가 있다.
<button aria-label="검색">🔍</button>
이렇게 시각적 텍스트가 없지만 보조 기술이 해당 요소를 올바르게 설명할 수 있도록 한다.
aria-describedby 는 어떤 요소를 설명하는 다른 요소를 지정할 때 사용한다.
스크린 리더는 해당 속성으로 지정된 요소의 콘텐츠를, 기본 라벨 다음에추가 설명 으로 읽어준다.
<label for="email">이메일</label>
<input id="email" type="email" aria-describedby="emailHelp"/>
<div id="emailHelp">이메일은 example@domain.com 형식이어야 합니다.</div>
이렇게 사용하면 input 요소의 추가 설명을 emailHelp 라는 id를 가진 요소의 콘텐츠로부터 가져와 사용자에게 안내한다.
aria-live 속성은 동적 콘텐츠가 업데이트 될 때 스크린 리더에게 해당 내용을 자동으로 읽도록 지시한다.
즉, 새로 생긴 콘텐츠나 변경된 콘텐츠를 자동으로 알리기 위해 사용된다.
off plite assertive 의 세 가지 주요 값이 있다.
aria-live="off"는 콘텐츠 업데이트를 스크린 리더가 읽지 않도록 설정한다.
aria-live 속성을 사용하지 않는 것과 동일한 효과를 가진다.
의도적으로 해당 영역의 변경 사항을 스크린 리더에 알리지 말라는 의도를 나타내고 싶을 때 사용한다.
aria-live="polite"는 콘텐츠가 업데이트 되면 스크린 리더가 현재 읽고 있는 내용을 마친 후 새로운 정보를 읽기 시작한다.
즉, 덜 긴급한 알림에 적합하다.
<div aria-live="polite">
<p>현재 읽고 있는 내용을 읽고 이 메시지를 읽습니다.</p>
</div>
aria-live="assertive"는 콘텐츠가 업데이트 되면 현재 스크린 리더가 읽고 있는 내용을 중단하고 즉시 알리도록 합니다.
즉, 긴급하고 중요한 알림에 적합하다.
<div aria-live="assertive">
<p>현재 읽고 있는 내용을 중단하고 이 메시지를 읽습니다.</p>
</div>
HTML 요소가 어떤 역할을 하는지를 보조 기술에 명시적으로 알려준다.
role에 들어갈 수 있는 값이 많지만, 몇 가지만 살펴보자.
role="alert" 는 긴급한 정보를 즉시 사용자에게 알리는 역할을 한다.
스크린 리더는 즉시 읽고, 사용자에게 중요한 알림을 빠르게 전달한다.
페이지 내에서 발생한 오류나 중요한 경고를 알리는데 유용하다.
<div role="alert">
<p> 저장에 실패했습니다. 다시 시도하세요.</p>
</div>
role="dialog" 은 웹 페이지의 특정 요소가 대화 상자(dialog) 임을 명시하는 역할을 한다.
주로 모달 창이나 팝업 창과 같은 사용자 인터페이스 요소에 사용된다.
이 속성을 통해 사람들에게 해당 요소가 중요한 대화 상자임을 알리기 위해 사용된다.
<div role="dialog" aria-labelledby="dialogTitle" aria-hidden="true">
<h2 id="dialogTitle">삭제 확인</h2>
<p>이 항목을 삭제하시겠습니까?</p>
<button>삭제</button>
<button>취소</button>
</div>
해당 예시는 사용자가 삭제 확인을 위한 대화 상자와 상호작용하는 상황이다.
이 대화 상자는 스크린 리더에 의해 대화 상자로 인식된다.
만약, role="dialog"가 없다면 해당 요소는 그냥 일반적인 div로 처리될 것이다.
role="alertdialog" 는 role="alert와 role="dialog" 를 합친 것으로, 긴급한 알림이나 즉각적으로 사용자 반응을 요구하는 대화 상자에 사용된다.
즉, 중요한 알림을 전달하지만, 대화 상자의 역할을 할 때 사용한다.
예를 들어, 승인/취소를 요구하는 메시지가 있을 때가 있다.
<div role="alertdialog" aria-labelledby="alertTitle" aria-describedby="alertMessage" aria-live="assertive">
<h2 id="alertTitle">경고!</h2>
<p id="alertDesc">이 작업을 수행하면 복구할 수 없습니다. 계속하시겠습니까?</p>
<button>확인</button>
<button>취소</button>
</div>
하지만, role="dialog 와 role="dialog 와 달리 포커스를 강제로 가져온다.
aria-hidden의 값을 true로 설정하면 해당 요소와 그 자식 요소들을 스크린 리더 등 보조 기술에서 감추도록 지시한다.
시각적으로는 보여도, 접근성 트리에는 포함되지 않는다.
시각적으로는 중요한 정보이지만, 보조 기술에게는 무의미하거나 혼란을 주는 정보거나, 이미지 배경 등을 숨길 때 사용한다.
<div aria-hidden="true">로딩 중...</div>
aria-checked는 선택 상태를 나타내는 요소(체크박스, 토글 버튼)에서, 현재 체크 여부 를 보조 기술에 전달하기 위해 사용하는 속성이다.
값이 true 면 체크되어 있음을,
값이 false 면 체크되어 있지 않음을,
값이 mixed 면 부분적으로 체크됨(일부만 선택)을 의미한다.
보통 UI의 상태에 따라 해당 설정을 동적으로 변경하면서 사용하며, 시각적인 변화와 스크린 리더가 인식하는 상태를 일치시키는 것이 중요하다.
aria-pressed 는 주로 토글 버튼 또는 상태를 변경하는 버튼에서 사용된다.
값이 true 면 버튼이 눌린 상태를,
값이 false 면 버튼이 눌리지 않는 상태를,
값이 mixed 면 부분 눌림 상태(토글 스위치의 중간 상태)를 의미한다.
aria-required 는 입력 필드가 필수 입력 항목임을 보조 기술에 알려주는 속성이다.
값이 true 면 해당 입력 필드가 필수 항목 임을,
값이 false 면 해당 입력 필드가 필수가 아님 을 의미한다.
<label for="email">이메일</label>
<input id="email" type="email" aria-required="true">
이렇게 하면 스크린 리더는 이 입력 필드를 필수 항목으로 읽어준다.
보통 UI의 상태에 따라 해당 설정을 동적으로 변경하면서 사용하며, 시각적인 변화와 스크린 리더가 인식하는 상태를 일치시키는 것이 중요하다.
aria-disabled 는 해당 요소가 비활성화 상태임을 보조 기술에 알리는 속성이다.
값이 true 면 해당 요소는 비활성화 상태임을,
값이 false 면 해당 요소는 활성화 상태임을 알린다.
시각적 상태를 명시하는 것이므로, 해당 요소 동작을 실제로 비활성화 하는 것은 아니다. 따라서, 시각적인 변화와 스크린 리더가 인식하는 상태를 일치시키는 것이 중요하다.
aria-selected 는 목록이나 항목 중에서 선택된 항목을 보조 기술에 알려주는 속성이다.
값이 true 면 항목이 선택됨을,
값이 false 면 항목이 선택되지 않음을 의미한다.
aria-modal 은 모달 대화 상자의 접근성을 향상시키는데 사용되는 속성이다.
값이 true 면, 현재 모달 창이 활성화 되어 다른 콘텐츠와 상호작용이 가능함을,
값이 false 면, 현재 모달 창이 닫히거나 모달이 아닌 상태임을 나타낸다.
aria-expanded 는 접을 수 있거나 펼칠 수 있는 UI 요소에서, 현재 상태가 펼쳐져 있는지 접혀 있는지 를 보조 기술에 알려주는 속성이다.
값이 true 라면 요소가 펼쳐져 있음을,
값이 false 라면 요소가 접혀 있음을 의미힌다.
드롭다운이나 내비게이션 메뉴 토글 등에 사용하면 유용하다.
보통 UI의 상태에 따라 해당 설정을 동적으로 변경하면서 사용하며, 시각적인 변화와 스크린 리더가 인식하는 상태를 일치시키는 것이 중요하다.
aria-controls="targetID" 는 해당 요소가 targetID 를 가진 요소를 제어한다는 의미이다.
보통 aria-expanded 와 함께 사용한다.
<button aria-controls="dropdownMenu" aria-expanded="false">메뉴 열기</button>
<ul id="dropdownMenu" hidden>
<li>항목 1</li>
<li>항목 2</li>
</ul>
dropdownMenu 요소를 button 이 제어한다는 의미이다.
보조 기술이 이 속성을 참고해 연관성을 파악할 수 있도록 도와준다.