Skip to content
This page has been auto-translated and may contain errors.View in English

접근성

docs.scrimba.com

사람들은 다양한 방식으로 웹에 접근합니다. 어떤 사람은 화면을 보면서 마우스를 움직입니다. 어떤 사람은 화면을 볼 수 없어서 소리로 읽어주는 것을 듣습니다. 어떤 사람은 마우스를 전혀 사용하지 않고 키보드나 음성, 또는 손으로 누르는 스위치로 페이지를 탐색합니다. 접근성이란 이 모든 사람이 사용할 수 있는 페이지를 만드는 실천이며, 그 대부분은 HTML을 원래 의도된 방식대로 작성하는 것으로 귀결됩니다.

접근성이 중요한 이유

**접근성(Accessibility)**이란 각자의 상황이나 브라우징 방식이 무엇이든 모든 사람이 여러분의 페이지를 사용할 수 있도록 하는 것을 의미합니다. 어떤 사람은 화면을 볼 수 없어서 페이지를 소리로 읽어주는 소프트웨어를 통해 이용합니다. 어떤 사람은 마우스를 쓰지 않고 키보드로 페이지를 탐색합니다. 어떤 사람은 편하게 읽으려면 더 큰 글자나 더 강한 색상이 필요합니다.

계단 옆에 경사로가 있는 건물을 떠올려 보세요. 경사로는 계단을 오르기 힘든 사람에게 도움이 되면서, 계단을 이용할 수 있는 사람에게는 아무런 손해도 주지 않습니다. 접근성을 갖춘 HTML도 마찬가지입니다. 더 많은 사람이 페이지를 이용할 수 있게 해주면서도 누구에게도 불리하게 만들지 않습니다.

다행스러운 점은 HTML이 처음부터 접근성을 갖추고 있다는 것입니다. 각 콘텐츠에 맞는 요소를 사용하는 것만으로도 대부분의 작업이 저절로 해결됩니다.

접근성은 흔히 a11y("a" 다음에 열한 글자, 그다음에 "y"라는 뜻)로 줄여 부르며, 여러분의 페이지가 사람들이 웹에 접근하는 모든 방식에서 제대로 동작하는지를 다룹니다. 페이지를 소리로 읽어주는 스크린 리더, 키보드만 사용하는 탐색, 음성 제어, 화면 확대, 색상을 줄이거나 대비를 높인 표시 모드까지 모두 해당됩니다.

가장 도움이 되는 실전 관점은 이것입니다. HTML은 접근성을 나중에 추가하는 것이 아니라 처음부터 갖춘 상태로 제공합니다. 대부분의 작업은 올바른 요소를 고르고, 브라우저가 이미 해주고 있는 일을 망치지 않는 것뿐입니다. 문제가 생기는 원인은 몇 가지로 좁혀집니다. 범용 요소로 다시 만든 커스텀 위젯, 레이블이 없는 폼 필드, 약한 색상 대비, 마우스에만 반응하는 동작이 대표적입니다.

접근성이란 보조 기술(assistive technology)(스크린 리더처럼 페이지를 소리로 읽어주거나, 클릭 대신 누르는 스위치 장치, 음성 제어처럼 누군가가 컴퓨터를 다룰 수 있도록 돕는 소프트웨어나 하드웨어)을 사용하는 사람이 여러분의 페이지를 인지하고, 조작하고, 이해할 수 있는지를 뜻합니다. 기준이 되는 표준은 WCAG(Web Content Accessibility Guidelines)로, 네 가지 원칙을 중심으로 구성됩니다. 콘텐츠는 인지 가능해야 하고, 조작 가능해야 하고, 이해 가능해야 하고, 견고해야 합니다.

여기서 짚어둘 만한 결과가 두 가지 있습니다. 첫째, 보조 기술이 의존하는 것과 동일한, 제대로 갖춰진 구조를 검색 엔진 같은 다른 기계도 DOM(브라우저가 페이지를 메모리에 표현하는 모델)에서 그대로 읽어냅니다. 그러니 접근성과 SEO는 서로 시간을 다투는 경쟁 관계가 아니라 같은 방향을 향합니다. 둘째, 많은 지역에서 접근성은 대중을 대상으로 하는 사이트에 있으면 좋은 요소가 아니라 법적 요구 사항입니다. 이 모든 것을 바라보는 유용한 관점은, 접근성을 갖춘 페이지란 대체로 제대로 만들어진 페이지라는 것입니다. 이 장에서 다루는 내용은 거의 전부가 의도된 방식대로 사용된 표준 HTML입니다.

Juno접근성이 중요한 이유 접근성이란 누구든, 어떤 방식으로 접속하든 페이지를 사용할 수 있게 만드는 것입니다. 좋은 점은 알맞은 요소를 고르는 순간 HTML이 대부분을 공짜로 해결해준다는 것입니다. 계단 옆에 경사로가 있는 모습을 떠올려 보세요. 더 많은 사람이 들어올 수 있고, 누구에게도 손해가 없습니다.
Juno접근성이 중요한 이유 접근성이란 여러분의 페이지가 스크린 리더, 키보드, 확대 기능을 비롯한 모든 사용 방식에서 제대로 동작하는 것입니다. HTML은 원래 접근성을 갖추고 있으므로 좋은 출발점에서 시작하는 셈이고, 대부분의 문제는 커스텀 위젯과 빠진 레이블이 그것을 망가뜨리면서 생겨납니다. 올바른 요소로 만들면 이미 대부분을 해낸 것입니다.
Juno접근성이 중요한 이유 기준이 되는 표준은 WCAG이고 네 가지 원칙은 인지 가능성, 조작 가능성, 이해 가능성, 견고성입니다. 스크린 리더에 도움이 되는 구조는 검색 크롤러가 DOM을 읽는 데도 똑같이 도움이 되므로, 이는 여러분의 시간을 따로 잡아먹는 별도의 비용이 아닙니다. 이 장의 나머지 내용은 그저 의도대로 사용된 평범한 HTML로 여기시면 됩니다. 실제로 대부분이 그렇습니다.

토대가 되는 시맨틱 HTML

접근성을 위해 할 수 있는 가장 효과적인 일은 겉모습만 맞게 스타일을 입힌 범용 요소가 아니라, 콘텐츠의 의미에 맞는 요소를 사용하는 것입니다.

**시맨틱 HTML**이란 콘텐츠가 어떻게 보이는지가 아니라 무엇인지에 맞춰 태그를 고르는 것을 의미합니다. 제목에는 <h1>부터 <h6>까지를 씁니다. 버튼에는 <button>을 씁니다. 링크에는 <a>를 씁니다. 목록에는 <ul>이나 <ol>을 씁니다. 이 요소들은 이미 스크린 리더가 알릴 수 있는 의미를 담고 있으므로, 청취자는 직접 보지 않고도 "이것은 버튼입니다" 또는 "이것은 제목입니다"라는 것을 알 수 있습니다.

이사할 때 상자에 라벨을 붙이는 것과 같습니다. "주방"이라고 적힌 상자는 상자를 싼 사람뿐 아니라 그것을 나르는 누구에게도 도움이 됩니다. 시맨틱 태그도 콘텐츠에 같은 방식으로 라벨을 붙여서, 브라우저와 보조 기술이 각 부분이 무엇인지 알 수 있게 해줍니다.

실제로는 버튼을 만들고 싶을 때 버튼처럼 보이게 스타일을 입힌 <div>가 아니라 <button>을 사용하는 것을 뜻합니다. <div>는 겉모습을 똑같이 만들 수 있지만, 그것이 무엇인지에 대해서는 아무 말도 하지 않습니다. 시맨틱 HTML 장에서 전체 목록을 다룹니다.

시맨틱 요소는 동작과 의미가 이미 붙어 있는 상태로 제공됩니다. <button>은 포커스를 받을 수 있고, Enter와 Space에 반응하며, 버튼으로 안내됩니다. <nav>는 내비게이션 영역을 표시합니다. <h1>부터 <h6>까지의 제목은 개요를 형성하며, 스크린 리더 사용자는 시력이 있는 독자가 목차를 훑듯이 이 개요를 따라 건너뛸 수 있습니다.

가장 많은 수고를 덜어주는 규칙은 이것입니다. 직접 만들기 전에 네이티브 요소를 먼저 쓰세요. 클릭 핸들러가 달린 <div role="button" tabindex="0">도 동작하게 만들 수는 있지만, 이는 포커스, 키보드 지원, 역할을 손수 다시 구현하는 것이며 그중 하나는 빠지기 쉽습니다. 진짜 <button>은 이 모든 것을 한꺼번에 제공합니다. 랜드마크 요소(<header>, <nav>, <main>, <aside>, <footer>)도 페이지 규모에서 같은 역할을 합니다. 스크린 리더 사용자가 위쪽 내용을 전부 듣지 않고 원하는 영역으로 곧장 건너뛸 수 있게 해줍니다. 시맨틱 HTML 장에서 각각을 다룹니다.

시맨틱 HTML이 토대가 되는 이유는 브라우저가 각 시맨틱 요소를 접근성 트리(accessibility tree)(보조 기술이 읽어내는, 페이지를 축약한 구조로, 아래 ARIA 섹션에서 자세히 다룹니다)의 역할에 매핑하기 때문입니다. <button>은 여러분이 아무것도 하지 않아도 버튼 역할, 포커스 동작, 키보드 처리를 받습니다. 이것을 <div>로 다시 만들면 그중 아무것도 물려받지 못합니다. 포커스 가능성, 키 처리, 안내되는 역할을 전부 손수 책임져야 하고, 그중 하나라도 빠지면 그것은 곧 누군가에게 결함이 됩니다.

가장 중요한 두 가지 습관이 있습니다. 첫째, 제목 레벨에 실제 구조를 부여하세요. 페이지 전체에 <h1> 하나를 두고, <h2><h3>을 레벨을 건너뛰지 않고 중첩시켜야 합니다. 스크린 리더 사용자는 제목을 기준으로 탐색하기 때문에, <h2>에서 <h4>로 건너뛰면 하나의 섹션이 사라진 것처럼 읽힙니다. 둘째, 랜드마크 요소(<main>, <nav>, <header>, <footer>, <aside>)를 사용해서 페이지가 탐색 가능한 영역을 드러내도록 하세요. 알아두어야 할 실패 사례는 "div 수프(div soup)"입니다. <div><span>으로 거의 전부를 짜맞춘 페이지는 화면에는 완벽하게 렌더링되지만 보조 기술에는 거의 아무것도 드러내지 않습니다. 이 두 요소는 아무런 역할도 담고 있지 않기 때문입니다.

Juno토대가 되는 시맨틱 HTML 콘텐츠가 어떻게 보이는지가 아니라 무엇인지에 맞춰 태그를 고르세요. 버튼에는 <button>, 제목에는 <h1>, 링크에는 <a>입니다. 각 태그는 이미 스크린 리더에게 자신이 무엇인지 알려주므로 그것을 공짜로 얻는 셈입니다. 스타일을 입힌 <div>는 겉모습은 같아도 아무것도 말해주지 않습니다.
Juno토대가 되는 시맨틱 HTML 네이티브 요소에는 포커스, 키보드 지원, 안내되는 역할이 이미 연결되어 있어서, <button>이 버튼인 척하는 <div>보다 항상 낫습니다. 직접 다시 만들기 전에 실제 요소를 쓰고, <nav><main> 같은 랜드마크에 기대어 사람들이 건너뛸 수 있게 하세요. 그것만으로 일의 대부분이 끝납니다.
Juno토대가 되는 시맨틱 HTML 모든 시맨틱 요소는 접근성 트리의 역할에 매핑됩니다. 그래서 <button>은 역할, 포커스, 키를 한꺼번에 넘겨주지만 <div>는 이 세 가지 모두에 대한 청구서를 넘겨줄 뿐입니다. 사람들은 제목을 기준으로 탐색하므로 레벨을 건너뛰지 말고 순서대로 유지하세요. div 수프는 화면에는 잘 나오지만 보조 기술에는 아무것도 알려주지 않는데, 이것이 바로 그 방식의 근본적인 문제입니다.

텍스트 대체 수단, 레이블, 포커스, 키보드

어떤 콘텐츠는 스스로 말할 수 없습니다. 이미지는 여러분이 설명을 붙이기 전까지 스크린 리더에게 보이지 않습니다. 폼 필드는 레이블이 붙기 전까지는 그저 추측의 대상일 뿐입니다. 그리고 마우스에만 반응하는 페이지는 마우스를 쓰지 않는 모든 사람을 배제합니다. 이 네 가지 영역은 조금만 신경 써도 큰 효과를 얻을 수 있는 곳입니다.

몇 가지 확실한 습관이 대부분의 경우를 해결해줍니다.

  • 이미지에는 alt 텍스트가 필요합니다. alt 속성은 이미지를 볼 수 없는 사람에게 그림을 설명해줍니다. 이미지가 단순히 장식용이라면 빈 alt=""로 스크린 리더가 건너뛰도록 알려줄 수 있습니다.
html
<img src="red-fox.jpg" alt="A red fox curled up asleep in the snow">
  • 폼 필드에는 레이블이 필요합니다. <label>은 방문자와 스크린 리더 모두에게 필드에 무엇을 입력해야 하는지 알려줍니다.
html
<label for="email">Email address</label>
<input id="email" type="email">
  • 버튼과 링크에는 명확한 텍스트가 필요합니다. "더 보기"만 있으면 맥락 없이 읽을 때 무슨 뜻인지 알 수 없지만, "요금 안내 더 보기"는 그 자체로 뜻이 통합니다.
  • 키보드 순서는 읽는 순서와 일치해야 합니다. Tab 키를 누르는 사람은 HTML에 요소가 나타나는 순서대로 페이지를 이동하므로, 그 순서가 자연스러운지 확인하세요.

alt 텍스트와 레이블에 대해서는 이미지와 미디어, 폼과 입력 장에서 더 자세히 다룹니다.

모든 폼 컨트롤을 <label>과 연결하세요. 가장 확실한 방법은 레이블의 for 속성을 입력 요소의 id와 맞추는 것입니다.

html
<label for="postcode">Postcode</label>
<input id="postcode" type="text" name="postcode">

이렇게 하면 레이블을 클릭했을 때 필드에 포커스가 가고, 필드가 포커스를 받을 때 스크린 리더가 레이블을 읽어줍니다. 여러 변형은 폼과 입력 장에서 다룹니다.

**alt 텍스트**는 픽셀이 아니라 목적을 설명해야 합니다. alt="Company logo"가 색상과 도형을 나열하는 것보다 낫고, 장식용 이미지에는 빈 alt=""를 붙여서 파일명으로 읽히는 대신 건너뛰게 만드세요.

포커스 순서는 DOM 안의 순서를 따르므로, 소스 순서가 시각적으로 읽는 순서와 일치하도록 유지하세요. 양수 tabindex 값(tabindex="1" 이상)은 피하세요. 별도의 탭 순서를 만들어내는데 이를 올바르게 유지하기가 어렵습니다. tabindex="0"은 커스텀 컨트롤을 자연스러운 순서에 포함시킬 때 쓰고, tabindex="-1"은 스크립트로만 포커스를 줄 수 있게 만들 때 씁니다.

키보드 조작성에 대한 규칙은 간단합니다. 마우스로 할 수 있는 모든 일은 키보드로도 되어야 합니다. 클릭으로 메뉴가 열린다면 Enter로도 열려야 합니다. 그리고 키보드 사용자가 자신의 위치를 볼 수 있도록 포커스 윤곽선을 항상 보이게 두세요. 색상 대비도 여기서 중요합니다. WCAG는 일반 텍스트와 배경 사이에 최소 4.5:1의 대비 비율을 요구하며, 모든 사람이 같은 색을 구분하지는 못하므로 의미를 절대 색상만으로 전달하지 마세요.

이 네 가지 영역은 모두, 시력이 있는 마우스 사용자에게는 시각적 레이아웃이 전달하는 의미를 DOM이 대신 전달해야 하는 지점입니다.

레이블. for/id로 연결되거나 입력 요소를 감싸는 <label>은 해당 컨트롤에 접근 가능한 이름(accessible name)(보조 기술이 요소에 대해 안내하는 텍스트)을 부여합니다. 레이블이 없으면 스크린 리더는 필드의 타입만 읽을 뿐 그 목적에 대해서는 아무것도 알려주지 않습니다. 플레이스홀더 텍스트는 레이블이 아닙니다. 입력하는 순간 사라지고, 안내되는 방식도 일관적이지 않습니다.

텍스트 대체 수단. alt<img>의 접근 가능한 이름입니다. 겉모습이 아니라 목적에 맞춰 작성하세요. 장식용 이미지는 alt=""(빈 값이지만 존재하는 상태)를 붙여서 접근성 트리에서 제외되도록 합니다. alt를 완전히 생략하는 것은 다른 문제로, 일부 스크린 리더는 파일명을 대신 읽어버려서 누구에게도 도움이 되지 않습니다.

포커스. 포커스 순서는 여러분이 따로 재정의하지 않는 한 DOM 순서를 따르며, 양수 tabindex는 거의 언제나 실수입니다. 시각적 레이아웃과 계속 맞춰 관리해야 하는 두 번째 탭 순서를 만들어내기 때문입니다. tabindex="0"은 커스텀 컨트롤을 자연스러운 순서에 포함시킬 때, tabindex="-1"은 스크립트로만 포커스를 받을 수 있는 요소를 만들 때 씁니다. 어떤 동작 이후 포커스를 옮길 때 이것이 필요합니다. 포커스 표시는 눈에 보이게 유지하세요. 대체할 것을 마련하지 않고 outline: none을 설정하면 키보드 사용자는 자신이 어디 있는지 놓치게 됩니다. 키보드 트랩(키보드 사용자가 들어갈 수는 있지만 빠져나올 수는 없는 포커스)도 조심하세요. WCAG는 이를 구체적으로 명시하고 있습니다.

키보드와 대비. 모든 동작은 논리적인 순서로 키보드를 통해 접근하고 조작할 수 있어야 합니다. 대비에 대해서는 WCAG AA가 본문 텍스트에 4.5:1, 큰 텍스트와 컨트롤의 시각적 경계에는 3:1을 요구하며, 의미는 절대 색상 하나에만 의존해서는 안 됩니다. 필수 입력 필드를 빨간색만으로 표시하면 그 차이를 인지하지 못하는 사람에게는 보이지 않습니다. 텍스트나 아이콘을 함께 사용하세요.

Juno텍스트 대체 수단, 레이블, 포커스, 키보드 네 가지 작은 습관이 대부분을 해결해줍니다. 이미지에는 alt를 주고, 폼 필드에는 <label>을 주고, 버튼과 링크의 텍스트는 그 자체로 뜻이 통하게 쓰고, 탭 순서는 읽는 순서와 맞추세요. 어느 것도 시간이 오래 걸리지 않습니다. 장식용 이미지에는 빈 alt=""를 주어 건너뛰게 하세요.
Juno텍스트 대체 수단, 레이블, 포커스, 키보드 모든 입력을 forid가 맞는 <label>과 연결하고, alt는 목적에 맞춰 쓰고 장식용은 비워두세요. 포커스 순서는 DOM 순서를 유지하고 양수 tabindex는 피하세요. 기억해둘 원칙은 이것입니다. 마우스로 할 수 있는 일은 키보드로도 되어야 하며, 대비가 4.5:1을 넘는지 확인하세요.
Juno텍스트 대체 수단, 레이블, 포커스, 키보드 레이블과 alt는 요소의 접근 가능한 이름을 정하므로, 플레이스홀더는 레이블이 아니고 빠진 alt는 빈 alt가 아닙니다. 포커스는 DOM 순서 그대로 두고, 양수 tabindex는 피하고, 대체 없이 포커스 윤곽선을 없애지 마세요. 텍스트는 4.5:1을 맞추고 색상만을 유일한 신호로 삼지 마세요. 그렇지 않으면 빨간색만 표시된 필수 입력 표시는 빨간색을 보지 못하는 사람에게 전혀 전달되지 않습니다.

ARIA, 그리고 왜 먼저 손대면 안 되는가

접근성을 위해 만들어진 HTML 속성 집합이 있는데, 이를 ARIA라고 부릅니다. 이는 알맞은 곳에서 쓰면 유용하지만, 동시에 이 플랫폼에서 가장 오용되는 부분이기도 합니다. 그러니 무엇을 하는지, 그리고 언제 손대지 말아야 하는지를 함께 이해해둘 가치가 있습니다.

**ARIA**는 Accessible Rich Internet Applications의 줄임말입니다. 요소에 추가로 붙여서 보조 기술에게 더 많은 정보를 알려주는 속성 집합입니다. 이름을 보면 가장 먼저 손을 뻗어야 할 도구처럼 느껴지지만, 실제로는 대개 가장 마지막에 써야 할 도구입니다.

이유는 단순합니다. ARIA가 설명할 수 있는 대부분은 HTML이 이미 스스로 말해주고 있습니다. <button>은 이미 버튼으로 안내됩니다. 여기에 role="button"을 추가해도 아무것도 바뀌지 않습니다. 어떤 요소가 무엇인지를 설명하려고 ARIA를 추가하고 있다면, 그것은 대개 이미 그것을 말해주는 평범한 HTML 요소로 바꿔야 한다는 신호입니다.

이삿짐 상자에 포스트잇을 붙이는 상황을 떠올려 보세요. 상자에 이미 "주방"이라고 인쇄되어 있다면, "주방"이라고 적힌 포스트잇은 그저 잡음을 더할 뿐입니다. 포스트잇은 자체적으로 라벨이 없는 상자에 남겨두세요. ARIA는 HTML에 해당 요소가 없는 페이지 부분을 위한 것이며, 이는 생각보다 훨씬 드뭅니다.

ARIA는 요소에 세 가지 정보를 추가합니다. 역할(roles)(무엇인지, 예를 들어 role="dialog"), 상태(states)(현재 조건, 예를 들어 aria-expanded="false"), 속성(properties)(추가적인 관계, 예를 들어 도움말 텍스트를 가리키는 aria-describedby)입니다. 스크린 리더는 이를 이용해 탭 패널이나 슬라이더처럼 네이티브 HTML로는 대응할 요소가 없는 커스텀 위젯을 안내합니다.

가장 먼저 따라야 할 지침은 ARIA의 첫 번째 규칙입니다. 네이티브 요소가 이미 그 일을 해준다면 ARIA를 쓰지 마세요. 네이티브 <button>은 언제나 <div role="button">보다 낫습니다. 네이티브 요소는 동작까지 가져다주지만 ARIA 속성은 레이블만 가져다주기 때문입니다. 더 나쁜 것은, 잘못되었거나 오래된 ARIA 속성은 없는 것보다 더 나쁘다는 점입니다. 브라우저가 원래 알려줬을 내용을 덮어버리기 때문입니다. 잘못된 요소에 aria-hidden="true"를 붙이면 화면에는 보이는 실제 콘텐츠를 스크린 리더 사용자에게 숨기게 됩니다. ARIA는 HTML에 대응하는 요소가 없는 위젯을 만들 때 손을 뻗으세요. 그리고 속성을 직접 지어내지 말고 정립된 패턴을 따르세요.

ARIA가 편집하는 대상부터 시작하겠습니다. **접근성 트리(accessibility tree)**는 브라우저가 DOM과 함께 별도로 구축하는 구조입니다. 각 요소에 대해 역할(role)(요소가 무엇인지: 버튼, 링크, 제목), 상태와 속성(states and properties)(조건과 관계, 예를 들어 aria-expanded, aria-checked, disabled), 접근 가능한 이름과 설명(accessible name and description)(안내되는 텍스트)을 기록합니다. 보조 기술은 이 트리를 읽으며, 여러분의 CSS나 원본 HTML을 읽는 것이 아닙니다.

ARIA는 이 트리를 직접 편집하기 위한 용어 체계입니다. 역할(role="tablist"), 시간에 따라 변하는 상태(aria-selected="true"), 더 안정적인 관계를 나타내는 속성(aria-labelledby, aria-controls)이 있습니다. **ARIA의 첫 번째 규칙**은, 네이티브 HTML 요소나 속성이 이미 필요한 역할, 상태, 속성을 제공한다면 그것을 쓰고 ARIA는 전혀 추가하지 말라는 것입니다. 이유는 ARIA가 접근성 트리만 바꿀 뿐 자체적으로는 아무런 동작도 추가하지 않기 때문입니다. <div>role="button"을 붙이면 스크린 리더는 그것을 버튼이라고 부르지만, 포커스 가능성도, Enter나 Space 처리도, disabled 지원도 부여하지 않습니다. 이 모든 것을 직접 하나하나 추가해야 하고, 하나라도 빠뜨리는 날에는 버튼이라고 안내되지만 버튼처럼 동작하지 않는 컨트롤을 갖게 되는데, 이는 정직한 <div>보다도 더 나쁩니다.

ARIA가 원래 막으려던 해악을 스스로 일으키지 않도록 몇 가지 규칙을 지키세요. 네이티브 요소를 우선하세요. 네이티브 시맨틱을 덮어쓰지 마세요(<button>role="heading"을 붙이지 않기). aria-hidden="true"로 표시된 서브트리 안에 상호작용 요소를 두지 마세요. 그렇지 않으면 스크린 리더가 볼 수 없는 포커스 가능한 컨트롤을 만들게 됩니다. 그리고 상태를 JavaScript와 계속 맞춰서 동기화하세요. 오래된 aria-expanded는 사용자에게 거짓을 말하는 셈입니다. ARIA가 정말 필요할 때는 속성을 처음부터 지어내지 말고, 일반적인 위젯을 위해 공개된 패턴인 WAI-ARIA Authoring Practices를 바탕으로 만드세요. 이 모든 것을 확인하려면, 브라우저의 접근성 검사기가 특정 요소에 대해 계산된 역할, 이름, 상태를 보여주는데, 이것이 정확히 보조 기술이 받게 될 정보입니다.

JunoARIA, 그리고 왜 먼저 손대면 안 되는가 ARIA는 보조 기술에게 요소를 설명해주는 추가 속성 집합입니다. 가장 먼저 손을 뻗어야 할 것처럼 들리지만 대개는 가장 마지막에 쓰는 것이 맞습니다. 진짜 <button>은 이미 스스로 버튼이라고 말해주기 때문입니다. ARIA는 HTML에 해당 요소가 없는 드문 부분을 위해 아껴두고, 나머지는 평범하게 두세요.
JunoARIA, 그리고 왜 먼저 손대면 안 되는가 ARIA는 HTML에 대응하는 요소가 없는 커스텀 위젯을 위해 역할, 상태, 속성을 추가합니다. ARIA의 첫 번째 규칙은 네이티브 요소가 이미 그 일을 해줄 때는 건너뛰라는 것입니다. 잘못되었거나 오래된 속성은 없는 것보다 더 나쁘기 때문입니다. <button>에 버튼이라고 레이블을 붙이고 있다면, 멈추고 그냥 button을 쓰세요.
JunoARIA, 그리고 왜 먼저 손대면 안 되는가 ARIA는 접근성 트리를 편집합니다. 역할, 상태, 속성뿐이며 그 외에는 아무것도 없기 때문에 어떤 동작도 추가하지 않습니다. 이것이 바로 ARIA의 첫 번째 규칙이 존재하는 이유입니다. <div>role="button"을 붙이면 여러분이 직접 만들어주기 전까지는 키도 포커스도 없는 버튼을 안내하는 셈입니다. 상태는 JavaScript와 계속 동기화하고, 위젯이 정말 필요할 때는 속성을 지어내는 대신 공개된 패턴을 그대로 따르세요.

빠른 자체 점검

가장 흔한 문제를 잡아내는 데 전문 소프트웨어가 필요하지는 않습니다. 이미 여러분의 컴퓨터에 있는 도구로 몇 가지만 확인해도 대부분의 문제를 찾아낼 수 있고, 실행하는 데 몇 분밖에 걸리지 않습니다.

어느 페이지에서든 실행할 수 있는 짧은 체크리스트입니다.

  • 마우스를 내려놓고 Tab 키를 눌러보세요. 모든 링크와 버튼에 자연스러운 순서로 도달할 수 있나요? Enter로 활성화할 수 있나요?
  • 모든 이미지에 alt 속성이 있나요?
  • 모든 폼 필드에 <label>이 있나요?
  • 버튼과 링크가 맥락 없이 그 자체로 읽어도 뜻이 통하나요?
  • 텍스트가 배경과 비교해 또렷하게 읽히나요?

이것들을 자신의 페이지에서 직접 확인하는 데는 오래 걸리지 않으며, 사람들이 가장 자주 겪는 문제를 잡아냅니다. Tab 키가 어딘가에서 걸린다거나 이미지에 alt가 없다면, 고칠 만한 것을 찾은 셈입니다.

반복적으로 실행할 수 있는 점검 과정을 작업 흐름에 넣으세요.

  1. 키보드. 페이지 전체를 Tab으로 훑어보세요. 모든 상호작용 요소에 자연스러운 순서로 도달할 수 있어야 하고, 눈에 보이는 포커스 표시가 있어야 하며, Enter나 Space로 조작할 수 있어야 합니다. 포커스가 사라지거나 걸리는 곳이 있다면 다른 무엇보다 먼저 고치세요.
  2. 제목과 랜드마크. <h1>이 하나만 있는지, 제목 레벨이 건너뛰지 않는지, 주요 영역이 <main>, <nav>, 그 외 랜드마크를 쓰고 있는지 확인하세요.
  3. 이름. 모든 이미지에 alt가 있고, 모든 컨트롤에 레이블이 있고, 모든 링크와 버튼이 맥락 없이도 명확하게 읽히는지 확인하세요.
  4. 대비. 브라우저 개발자 도구에서 텍스트와 배경의 대비를 확인하세요. 도구가 비율을 알려주고 기준을 통과하지 못하는 부분을 표시해줍니다.

Chrome 개발자 도구의 Lighthouse 패널이나 axe 브라우저 확장 프로그램 같은 자동화 검사 도구는 유용한 만큼의 문제를 잡아내지만, 그것은 일부일 뿐입니다. alt 텍스트가 의미 있는지, 탭 순서가 자연스러운지는 판단할 수 없으므로, 수동으로 하는 키보드 점검은 여전히 필수입니다.

제대로 된 점검은 자동화와 수동 점검을 결합합니다. 자동화는 전체 범위의 일부만 다루기 때문입니다. 도구는 빠진 alt, 빠진 레이블, 대비 실패(WCAG 기준의 대략 3분의 1 정도)를 안정적으로 찾아내지만, alt 텍스트가 정확한지 탭 순서가 논리적인지는 판단할 수 없습니다.

  • 자동화. 기계적인 실패를 먼저 걸러내기 위해 axe나 Lighthouse를 실행하세요.
  • 키보드. 마우스를 내려놓고 Tab으로 훑으면서 도달 가능성, 논리적인 순서, 눈에 보이는 포커스 표시, 완전한 조작 가능성, 그리고 포커스가 빠져나올 수 없는 곳이 없는지 확인하세요. 이 점검만으로도 대부분의 커스텀 위젯 결함이 드러납니다.
  • 스크린 리더. 하나를 켜고(VoiceOver는 macOS에 기본 포함되어 Cmd+F5로 켤 수 있고, NVDA는 Windows용 무료 다운로드, TalkBack은 Android에 기본 내장되어 있습니다) 주요 흐름 몇 가지를 직접 들어보세요. 이름이 제대로 안내되는지, 역할이 올바른지, 상태 변화가 실제로 소리로 전달되는지를 확인하는 과정입니다.
  • 접근성 트리. 브라우저 개발자 도구는 어떤 요소에 대해서든 계산된 역할, 이름, 상태를 보여주며, 요소가 겉으로 어떻게 보이는지와는 별개로 보조 기술이 실제로 받게 될 정보를 알려줍니다.

자동화 도구가 모두 통과했다고 나와도 키보드 점검과 스크린 리더 점검은 반드시 실행하세요. 도구가 확인할 수 없는 부분이야말로 실제로 페이지를 사용하는 사람에게 가장 큰 영향을 미치는 부분이기 때문입니다.

Juno빠른 자체 점검 마우스를 내려놓고 페이지를 Tab으로 훑어보세요. 자연스러운 순서로 모든 것에 도달하고 사용할 수 있나요? 그다음 모든 이미지에 alt가 있는지, 모든 필드에 <label>이 있는지, 텍스트가 배경과 비교해 또렷하게 읽히는지 확인하세요. 몇 분만 들이면 사람들이 가장 많이 겪는 문제를 잡아낼 수 있습니다.
Juno빠른 자체 점검 이것을 습관으로 만드세요. Tab으로 도달 가능성과 순서를 확인하고, <h1>이 하나이고 건너뛴 제목이 없는지 확인하고, 이미지와 컨트롤의 이름을 확인하고, 개발자 도구에서 대비를 읽어보세요. axe나 Lighthouse 같은 자동화 도구가 도움이 되긴 하지만 일부만 잡아내므로, 수동 키보드 점검은 계속 직접 하세요.
Juno빠른 자체 점검 자동화는 빠진 alt, 빠진 레이블, 대비 문제 등 WCAG의 대략 3분의 1을 찾아내지만, 의미나 순서에 대해서는 아무것도 판단하지 못합니다. 그러니 키보드 점검, 스크린 리더로 직접 들어보는 점검, 계산된 역할과 이름을 확인하는 접근성 검사기 확인을 함께 하세요. 도구가 실행할 수 없는 검사야말로 가장 중요한 검사이니, 보고서가 통과로 나와도 직접 실행하세요.