웹 접근성은 모든 신체적 한계, 환경적 한계를 고려해 개발하는 것을 의미한다. (우리나라 장애인 차별 금지법에도 웹접근성과 관련된 내용이 작성되었기 때문에 의무적으로 지켜야 하는 사항이다.) 즉, 모두가 사용할 수 있도록 웹사이트를 디자인-개발하는 것이다.
웹 접근성을 따르는 개발은 장애가 있거나 노령으로 인한 신체 변화, 여러 기기 환경을 사용하는 모든 사람이 웹사이트와 도구 등을 사용할 수 있도록 개발하는 것을 의미한다.
웹 접근성 지침은 W3C에서 설립한 WAI(Web Accessibility Initiative)에서 전문적으로 연구하며 가이드라인을 제공하고 있다. 이 가이드 라인에서는 웹 컨텐츠 및 사용자들이 사용하는 도구 개발에서 지켜야 할 점이나 브라우저나 확장 프로그램을 만드는 사람들이 주의해야 할 점등에 대한 가이드라인 을 제공한다.
그 중, WCAG(Web Content Accessibility Guidelines) 는 접근성을 갖춘 웹사이트를 만드는 데 필요한 지침을 제공한다. WCAG를 기반으로 몇 가지 가이드 라인과 적용 방법에 대해 알아보자.
WCAG에서 다루는 Content는 웹 페이지, 프로그램의 정보를 의미한다. 즉 텍스트나 이미지 사운드 같은 정보들을 어떻게 해야 더 많은 사람이 쉽게 이해하는지 작성한 단일 공유 표준이다.
📍 출처 : WCAG Checklists
Web Accessibility Initiative - Accessible Rich Internet Applications 문서에는 접근성을 갖춘 JavaScript 위젯을 만드는 데 필요한 기술들이 담는다.
참고로, JSX에서는 모든 aria-*
HTML 어트리뷰트를 지원하고 있다. React에서 대부분의 DOM 프로퍼티와 어트리뷰트에 대한 값이 캐멀 케이스로 지원되는 반면, aria-*
와 같은 어트리뷰트는 일반적인 HTML과 마찬가지로 hypen-case(혹은 kebab-case, lisp-case 등)로 작성해야 한다.
<input
type="text"
aria-label={labelText}
aria-required="true"
onChange={onchangeHandler}
value={inputValue}
name="name"
/>
불필요한 속어나 약어를 사용하면, 장애를 가진 사람과 가지지 않은 사람, 그리고 외국인까지 모두 정보를 이해할 수 있는 가능성이 낮아진다. 약어는 되도록이면 풀어서 작성을 해야하며, 속어나 비속어는 사용을 지양하는 것이 좋다.
시각적으로 정보를 획득하기 어려운 사람들을 위해 컴퓨터 화면의 정보를 음성으로 읽어주는 스크린 리더는 제목 요소를 기준으로 목차를 만들거나, 이전과 이후 문단으로 이동하는 기능을 제공할 때가 많다. 때문에, 콘텐츠 내의 제목과 단락을 명확히 구분해야 스크린 리더가 조금 더 명확하게 글의 내용을 파악할 수 있다.
시맨틱 HTML은 어플리케이션에 있어 접근성의 기초가 된다. 시멘틱 HTML 태그 엘리먼트를 사용하면 정보의 의미가 강조되어 자연스럽게 접근성이 갖춰지기 때문이다.
시멘틱 HTML 태그 요소 사용에 대한 Bad 케이스와 Good 케이스를 비교해보자.
Bad Case
<div>
글의 제목
<br><br>
글의 내용1 글의 내용2
</div>
Good Case
<article>
<h1>글의 제목</h1>
<p>글의 내용1</p>
<p>글의 내용2</p>
</article>
레이아웃을 작성할 때 <article>
이나 <nav>
, <footer>
등의 시멘틱 태그를 사용하는 것이 좋다. 이를 통해서 스크린 리더가 컨텐츠 정보를 읽을 때 기계에 추가로 정보를 제공해줌으로써 조금 더 명확한 정보를 토대로 콘텐츠를 이해하고 읽을 수 있게 된다.
React로 구성한 코드를 돌아가게 만들기 위해서 <div>
와 같은 의미가 불분명한 엘리먼트를 사용해야 할 때도 있다. 특히 목록 같은 HTML <table>
을 사용할 때 그 문제가 두드러진다. 이런 경우 우리는 React Fragment를 사용하여 여러 엘리먼트를 하나로 묶어주는 것을 리액트 공식문서에서는 권장하고 있다.
import React, { Fragment } from 'react';
function ListItem({ item }) {
return (
<Fragment>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment> );
}
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
<ListItem item={item} key={item.id} />
))}
</dl>
);
}
Fragment는 배열의 각 요소들을 매핑할 때에도 warp 해주는 용도로 사용이 가능하다.
function Glossary(props) {
return (
<dl>
{props.items.map(item => (
// 항목을 매핑할 때 Fragment는 반드시 `key` 프로퍼티가 있어야 합니다.
<Fragment key={item.id}> <dt>{item.term}</dt>
<dd>{item.description}</dd>
</Fragment> ))}
</dl>
);
Fragment 태그에 어떤 props도 필요하지 않고 다만 요소들을 하나로 warp 해주는 태그로써 사용하길 원한다면, 아래와 같이 짧게 줄여 사용할 수도 있다.
function ListItem({ item }) {
return (
<>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</> );
}
HTML 폼 컨트롤(<input>
, textarea>
)을 구분하기 위해서는 스크린 리더를 사용하는 사용자를 위해 이에 대한 자세한 설명이 담긴 라벨이 필요하다.
<label htmlFor="namedInput">Name:</label>
<input id="namedInput" type="text" name="name"/>
스크린 리더에 오류 문구를 노출하여 모든 사용자가 오류 상황을 알 수 있게끔 한다.
<button>
이나 <input>
, <select>
같은 요소 등을 사용하지 않고 <div>
와 CSS를 이용해서 비슷하게 구현하여 사용할 때가 있다. 하지만 <div>
와 CSS를 이용하여 구현하게 되면 기본 요소들이 제공하는 키보드 동작들을 모두 사용하지 못한다. <select>
또한 <div>
로 구현하게 되면, 화살표로 아이템을 선택하고 탭으로 이동하는 동작들을 사용하지 못하게 된다. 그렇기 때문에 키보드를 사용해서 모든 동작을 이용할 수 있게끔 하려면 어쩔 수 없이 <div>
태그를 이용해야 했을 때 추가적인 코드 작성을 해야만 한다.
role
: 해당 요소의 원래 목적을 작성한다. 예를 들어 <button>
태그 대신 <div>
를 이용하게 된다면, role=button
이라는 명확한 사용 목적을 명시한다. 이렇게 명시하게 되면 스크린 리더는 <div>
태그라도 버튼으로 인식하게 된다.tab-index
: 해당 요소를 탭 키로 도달하게 하는 속성이다. 이 속성을 이용해서 탭 키로 이동할 다음 키보드 위치를 제공하게 한다. 모든 웹 어플리케이션은 키보드만 사용하여 모든 동작을 할 수 있어야 한다. 리액트 어플리케이션은 런타임 동안 지속해서 HTML DOM을 변경하기에 가끔 키보드 포커스를 잃거나, 예상치 못한 요소에 포커스를 맞출 때가 있다. 이 때문에 키보드 포커스를 올바른 방향으로 변경해주는 작업이 필요한 것이다.
키보드 사용자는 일반적으로 탭 키를 이용해서 링크와 버튼, 텍스트를 입력하는 부분을 찾게 된다. 이 때문에 포커스를 하는 지점을 명확하게 하는 작업이 필요하다. 만약 outline CSS 속성을 0이나 none 으로 지정하게 될 경우에 Focus
가 된 요소인지 아닌지를 화면에서 식별할 수 없게 되고, 이 때문에 마우스를 사용할 수 없는 사람들에게 현재의 포커스 된 지점을 알려줄 수 없게 되기 때문이다.
마우스 혹은 포인터 이벤트로 노출된 모든 기능 역시 키보드만으로 사용할 수 있도록 해야 한다. 포인터 장치만 고려할 경우에 키보드 사용자들이 어플리케이션을 사용하지 못하는 경우가 많기 때문이다.
이미지나 동영상, 그리고 오디오는 모든 스크린 리더에서 접근할 수 없다. 이미지와 동영상 같은 경우 시각 장애가 있는 사람들은 접근하기가 어렵고 오디오의 경우 청각 장애가 있는 사람들에게 접근이 어렵다. 이러한 문제들 때문에 요소들이 어떠한 의미인지 명확하게 전달해야만 한다.
<img src="coffee.png">
스크린 리더는 이미지를 "coffee.png, image" 라고 읽게 된다. 파일 이름이 해당 이미지를 잘 설명할 수 있다면 특별히 추가할 요소는 없어도 되지만, 만약 이미지와 상관 없는 제목이 들어가게 된다면 어떤 이미지인지 파악하기가 어려워질 것이다. 이 때문에 우리는 alt
와 title
속성을 지정해야만 한다.
<img src="coffee.png" alt="유리잔에 담긴 아이스아메리카노" title="아이스 아메리카노">
위의 예시처럼 alt
와 title
속성을 추가하게되면 스크린 리더는 "유리잔에 담긴 아이스아메리카노" 라고 읽게 된다. 이처럼 alt
속성을 통해서 이미지가 시각적으로 어떤 모습인지를 명확하게 설명해야만 한다. 그리고 이미지가 문서에서 큰 의미가 없는 것이라면, background
이미지로 작성하거나 alt
속성에 빈 문자열을 지정하면 된다.
물론, 애니메이션이나 깜빡이는 효과, 색상 선택에도 주의를 기울여 선택해야 한다.
웹 접근성(시각장애인을 위한)
HTML 노드에 어떤 태그가 있더라도 CSS만 제대로 작성하면 디자이너가 그린 것과 똑같은 화면을 만들 수 있다. 일반적 경우라면 아무 문제없다. 다만, 웹 접근성(web accessibility) 차원에서는 문제가 된다. 웹페이지에 일반적인 방법으로 접근할 수 없는 사람들, 특히 시각장애인의 경우는 볼 수 없기 때문에 스크린 리더와 같이 문서를 소리로 바꿔주는 특수한 장치를 이용해야 한다. 웹사이트를 눈이 아닌 귀로 듣는 경험은 어떨지 상상하기 어렵다. 아마 많이 불편할 것이다. 우리가 상상할 수 없다고 간과해서는 안된다. 웹을 만드는 사람이라면 조금이라도 이 불편함을 해소할 수 있도록 도와야 할 의무가 있다.
SEO(검색엔진 최적화)
검색엔진이 웹사이트를 방문하면 문서에 포함된 링크를 따라가며 관련 페이지를 모두 방문하고 수집한다. 수집된 문서는 구글 시스템에서 분석 과정을 거친다. 웹사이트에 사용된 태그와 단어의 빈도 등 검색엔진 자체 알고리즘에 따라 주요 키워드를 추출한다. <div>
와 <span>
만 사용한 문서는 어떤 부분이 중요한 영역인지 구분이 어렵다. 문서의 제목에 해당하는 <title>
, 본문 영역 표시 <main>
, 글 제목 <h1>
등 주요 항목을 별도의 태그로 구분한 문서가 더 좋은 점수(실제 점수가 있는 건 아니다)를 획득한다. 즉, 검색 결과 상위에 노출된다. 물론, 검색엔진마다 알고리즘이 다르기 때문에(우리는 알 수 없다) 무엇이 정답이다 말할 수는 없다. 하지만, 상식적으로 생각해도 영역 구분이 확실한 문서가 그렇지 않은 문서보다 더 적절한 키워드를 추출할 것이라 예상할 수 있다. 우리가 웹문서를 의미에 맞게 구성해야 하는 이유다.
개발자들을 위해서(알아보기 쉽게 해서 유지보수성을 높이기)
알아보기 쉬운 태그들로 인해 유지보수성을 높이기 때문에 시멘틱 태그를 사용해야만 한다.
웹 접근성 가이드라인을 모두 완벽하게 만드는 것은 사실상 불가능하다. 하지만 가이드라인을 준수하여 더 많은 사람들에게 사이트의 접근성을 높여주고, 이용할 수 있도록 하기 때문에 웹 생태계를 위해서 프론트엔드 개발자는 이러한 가이드를 숙지하고 고려하여 사용하는 것은 매우 중요하다.
웹은 점점 규모가 커지고, 의미 있는 내용을 추리는데 더 많은 시간과 자원을 사용한다. 정확하고 가치 있는 정보를 탐색하기 위해서는 웹문서가 단순한 코드의 나열이 아니라 의미를 가진 하나의 구조로 작동해야 한다. 단순히 정보가 나열된 문서는 중요한 요소를 구분하기 어렵다. 자칫 크롤러가 엉뚱한 부분을 중요하다고 착각하는 요인이 될 수 있다. 우리가 웹페이지를 구성할 때 적절한 위치에 적합한 요소를 사용해야 이런 오해를 줄일 수 있다. 즉, 시맨틱 태그를 이용해서 의미를 구분할 수 있는 문서를 만들어야 사용자에게 정확한 정보를 제공할 수 있다.
👩🏻💻 해당 포스팅은 React 공식문서 를 베이스로 한 스터디 기록입니다.
📚 기초부터 완성까지, 프런트엔드 를 참조했습니다.