웹은 시각 장애나 운동 장애가 있는 사람을 포함해 다양한 사람들이 사용합니다. 이들이 웹 기반 소프트웨어 애플리케이션을 훨씬 쉽게 사용할 수 있도록 다양한 보조 기술이 제공됩니다. 또한 접근성을 높이도록 애플리케이션을 설계하면 대체로 모든 사용자의 사용 경험이 좋아집니다.
접근성 높은 애플리케이션을 설계할 때 고려할 문제와 기법을 자세히 알아보려면 Google web.dev의 접근성 학습 과정을 참고하세요.
이 페이지에서는 보조 기술에 의존하는 사용자를 포함해 모든 사용자가 편리하게 사용할 수 있는 Angular 애플리케이션을 설계하는 모범 사례를 설명합니다.
접근성 어트리뷰트
접근성 높은 웹 경험을 만들려면 의미 정보가 부족한 부분에 Accessible Rich Internet Applications(ARIA) 어트리뷰트를 설정해야 하는 경우가 많습니다. 접근성과 관련된 어트리뷰트의 값은 템플릿의 어트리뷰트 바인딩 문법으로 제어하세요.
ARIA 어트리뷰트와 프로퍼티
Angular에서 ARIA 어트리뷰트를 바인딩할 때는 다른 HTML 어트리뷰트처럼 직접 사용하면 됩니다.
<button [aria-label]="myActionLabel">…</button>
정적인 ARIA 어트리뷰트는 일반 HTML 어트리뷰트처럼 동작합니다.
<button aria-label="Save document">…</button>
도움말: 관례적으로 HTML 어트리뷰트는 소문자 이름(tabindex)을 사용하고, 프로퍼티는 카멜 표기법(tabIndex)을 사용합니다.
일부 ARIA 패턴은 Element 참조 모음과 같은 구조화된 값을 받는 DOM API나 디렉티브 입력을 제공합니다.
이 경우에는 일반적인 프로퍼티 바인딩을 사용해 관련 요소 사이의 관계를 동기화하세요.
@Component({
template: `
<h2 #dialogTitle>Attention</h2>
<p #dialogDescription>Please review your answers before continuing.</p>
<section role="dialog" [ariaLabelledByElements]="[dialogTitle, dialogDescription]">
<ng-content />
</section>
`,
})
export class ReviewDialog {}
여기서 [ariaLabelledByElements]는 요소 배열을 받으므로, 프로퍼티 바인딩을 사용하면 템플릿 데이터가 변경될 때마다 요소 참조도 최신 상태로 유지됩니다.
ARIA 어트리뷰트 문법을 요약한 내용은 바인딩 가이드를 참고하세요.
Angular UI 컴포넌트
Angular 팀이 관리하는 Angular Material 라이브러리는 완전한 접근성을 목표로 하는 재사용 가능한 UI 컴포넌트 모음입니다.
컴포넌트 개발 키트(CDK)에는 접근성의 다양한 영역을 지원하는 도구를 제공하는 a11y 패키지가 포함되어 있습니다.
예를 들면 다음과 같습니다:
LiveAnnouncer는aria-live영역으로 스크린 리더 사용자에게 메시지를 알리는 데 사용합니다. aria-live 영역에 관한 자세한 내용은 W3C 문서를 참고하세요.cdkTrapFocus디렉티브는 Tab 키로 이동하는 포커스를 특정 요소 내부로 제한합니다. 모달 대화 상자처럼 포커스를 제한해야 하는 컴포넌트에 접근성 높은 사용 경험을 제공할 때 사용하세요.
이 도구와 다른 도구에 관한 자세한 내용은 Angular CDK 접근성 개요를 참고하세요.
직접 스타일을 지정하는 컴포넌트에서 재사용 가능한 WAI-ARIA 상호작용 패턴이 필요하다면, Angular Aria가 아코디언, 콤보박스, 목록 상자, 메뉴, 탭, 도구 모음 등의 패턴을 위한 헤드리스 디렉티브를 제공합니다. 애플리케이션의 HTML 구조와 스타일은 직접 작성하고, 키보드 상호작용, ARIA 어트리뷰트, 포커스 관리, 스크린 리더 지원은 이 디렉티브에 맡길 수 있습니다.
기본 HTML 요소 확장하기
기본 HTML 요소에는 접근성에 중요한 여러 표준 상호작용 패턴이 구현되어 있습니다. Angular 컴포넌트를 작성할 때는 잘 지원되는 동작을 다시 구현하는 대신 가능한 한 기본 요소를 직접 재사용하세요.
예를 들어 새로운 종류의 버튼을 만들 때는 커스텀 요소를 만드는 대신 기본 <button> 요소에 어트리뷰트 셀렉터를 적용하는 컴포넌트를 만드세요.
이 방식은 주로 <button>과 <a>에 적용하지만, 다른 여러 요소에도 사용할 수 있습니다.
Angular Material의 MatButton, MatTabNav, MatTable에서 이 패턴의 예제를 확인할 수 있습니다.
기본 HTML 요소에 컨테이너 사용하기
적절한 기본 요소를 사용하기 위해 컨테이너 요소가 필요한 경우도 있습니다.
예를 들어 기본 <input> 요소는 자식 요소를 가질 수 없으므로 커스텀 텍스트 입력 컴포넌트는 <input>을 다른 요소로 감싸야 합니다.
커스텀 컴포넌트의 템플릿 안에 <input>을 넣기만 하면, 컴포넌트 사용자는 <input> 요소에 임의의 프로퍼티와 어트리뷰트를 설정할 수 없습니다.
대신 콘텐츠 프로젝션으로 기본 컨트롤을 컴포넌트 API에 포함하는 컨테이너 컴포넌트를 만드세요.
MatFormField에서 이 패턴의 예제를 확인할 수 있습니다.
사례: 커스텀 진행 표시줄 만들기
다음 예제는 호스트 바인딩으로 접근성과 관련된 어트리뷰트를 제어해 진행 표시줄의 접근성을 높이는 방법입니다.
- 컴포넌트는 표준 HTML 어트리뷰트인
role과 ARIA 어트리뷰트로 접근성을 지원하는 요소를 정의합니다. ARIA 어트리뷰트aria-valuenow는 사용자의 입력값에 바인딩합니다. - 템플릿에서는
aria-label어트리뷰트로 스크린 리더가 컨트롤에 접근하도록 합니다.
라우팅
페이지 이동 후 포커스 관리하기
UI의 포커스를 추적하고 제어하는 것은 접근성을 고려한 설계에서 중요합니다. Angular 라우팅을 사용할 때는 페이지 이동 후 포커스를 어디로 옮길지 결정해야 합니다.
시각적인 단서에만 의존하지 않도록 페이지 이동 후 라우팅 코드에서 포커스를 갱신해야 합니다.
포커스를 갱신할 시점은 Router 서비스의 NavigationEnd 이벤트로 확인하세요.
다음 예제는 페이지 이동 후 DOM에서 주요 콘텐츠의 제목을 찾아 포커스를 맞추는 방법입니다.
router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe(() => {
const mainHeader = document.querySelector('#main-content-header');
if (mainHeader) {
mainHeader.focus();
}
});
실제 애플리케이션에서 포커스를 받을 요소는 애플리케이션의 구조와 레이아웃에 따라 달라집니다.
포커스를 받은 위치에서는 사용자가 라우팅으로 새로 표시된 주요 콘텐츠로 곧바로 이동할 수 있어야 합니다.
라우팅 규칙이 변경된 뒤 포커스가 body 요소로 돌아가는 상황은 피해야 합니다.
활성 링크 식별하기
RouterLinkActive처럼 활성화된 RouterLink 요소에 적용하는 CSS 클래스는 활성 링크를 식별하는 시각적 단서를 제공합니다.
하지만 시각적 단서만으로는 전맹이나 저시력 사용자를 도울 수 없습니다.
요소에 aria-current 어트리뷰트를 적용하면 활성 링크를 식별하는 데 도움이 됩니다.
자세한 내용은 Mozilla Developer Network(MDN)의 aria-current)를 참고하세요.
RouterLinkActive 디렉티브는 링크가 활성화되면 aria-current에 지정한 값을 설정하는 ariaCurrentWhenActive 입력을 제공합니다.
다음 예제는 활성 링크에 active-page 클래스를 적용하고 aria-current 어트리뷰트를 "page"로 설정하는 방법입니다:
<nav>
<a routerLink="home" routerLinkActive="active-page" ariaCurrentWhenActive="page"> Home </a>
<a routerLink="about" routerLinkActive="active-page" ariaCurrentWhenActive="page"> About </a>
<a routerLink="shop" routerLinkActive="active-page" ariaCurrentWhenActive="page"> Shop </a>
</nav>
지연 로딩
Angular의 @defer 블록으로 콘텐츠를 지연 로딩할 때는 보조 기술 사용자에게 미치는 접근성 영향을 고려하세요.
지연된 컴포넌트를 불러올 때 스크린 리더가 콘텐츠 변경을 자동으로 알리지 않으면, 사용자는 새 콘텐츠가 생겼다는 사실을 모를 수 있습니다.
지연된 콘텐츠의 변경 사항이 제대로 전달되도록 적절한 ARIA 라이브 영역이 설정된 요소로 @defer 블록을 감싸세요.
자세한 안내와 예제는 defer 가이드의 접근성 섹션을 참고하세요.
더 알아보기
- 접근성 - Google Web Fundamentals
- ARIA 명세와 작성 지침
- Material Design - 접근성
- Smashing Magazine
- Inclusive Components
- 접근성 리소스와 코드 예제
- W3C - 웹 접근성 이니셔티브
- Rob Dodson A11ycasts
- Angular ESLint는 코드가 접근성 표준에 부합하는지 확인하는 데 도움이 되는 린트 규칙을 제공합니다.
참고 도서
- "A Web for Everyone: Designing Accessible User Experiences", Sarah Horton과 Whitney Quesenbery 저
- "Inclusive Design Patterns", Heydon Pickering 저