UI 위젯과 문서로 가득 차 있는 접근성 아이콘이 그려진 상자

커버 일러스트 출처 – “And So Much More…” ARIA Authoring Practices Guide | W3C

서문

W3C 홈페이지의 내비게이션 항목 중에 사명(Mission) 페이지가 있습니다. 해당 페이지에서는 접근성이 첫 번째 원칙으로 적혀 있습니다. 그런 배경 덕에 웹 표준 명세는 항상 접근성을 같이 고려하고 있습니다.

웹의 힘은 보편성에 있습니다. 장애와 관계없이 모든 사람의 접근은 필수적인 측면입니다.
– Tim Berners-Lee, Accessibility | Our mission | W3C

만들고자 하는 웹 콘텐츠가 HTML의 구조적 의미를 충분히 반영한다면, 대부분의 접근성이 담보되는 이점이 있습니다. 그러나 HTML이 기본 제공하지 않는 복합적 UI 컴포넌트1를 직접 구현할 때는 접근성이 누락되는 한계가 존재합니다.

이 한계는 WAI-ARIA로 보완할 수 있으나, 오히려 잘못 사용한 ARIA는 접근성이 저하될 수 있어 주의가 필요합니다.2 왜냐하면 본래의 의도와는 다르게 동작할 수 있기 때문입니다.

Notes on ARIA Use in HTML | W3C(또는 해당 한국어 초벌 번역본)에서 ARIA를 언제-어떻게 사용하고, 사용하면 안 되는 상황에 대해 잘 소개되어 있습니다. 읽어보시는 걸 권해드립니다.

조금 더 친절한 가이드로 WAI-ARIA를 배울 때 정리해 두고 싶은 것 (일본어)가 있습니다. 일본어로 작성되어 있지만 브라우저 번역 기능을 통해 충분히 읽으실 수 있습니다.

그래서 무엇을 다룰 것인가요?

이 글에서는 복합적인 UI 상태 표현이 필요할 때 WAI-ARIA를 적절히 활용하는 방법을 다룹니다. ARIA State(대표적인 예로 aria-invalid, aria-expanded, aria-selected 등)를 활용해 명시적인 UI 상태 관리를 돕는 두가지 모범 사례를 준비했습니다.

의미론적인 CSS 작성법

그간 CSS에서 픽셀을 움직이는건 꽤 빡셌지! 하지만 이제 논시멘틱(non-semantic) 한 클래스 이름과 HTML안에 쓰는 인라인 CSS, 거기다 자바스크립트 안에 작성하는 CSS 스타일을 쓰는게 진짜로 오지고 지리고 렛잇고인 방법인 것이다! 패밀리 가이 CSS GIF를 여기다 넣어라! 이렇게 ㅋ

(번역) 구닥다리 공룡을 위한 오늘날의 CSS — Steemit
원본 일러스트 출처 - Dinosaur Comics

의미론적인 CSS 작성법은 HTML과 WAI-ARIA의 의미를 활용해 CSS 규칙(Rule)을 설계하는 방법입니다.

영상으로 먼저 이해하고 싶으시면, “How to write Semantic CSS - YouTube“를 보시는 것도 좋습니다.

클래스 선택자는 CSS Specificity3에서 엘리먼트 선택자보다 순위가 높고, ID 선택자보다는 낮아 범용성이 높은 특징을 갖습니다. 이러한 특성 때문에 많은 개발자들이 대부분의 CSS 규칙을 클래스 이름으로 정의하는 것이 흔한 관행이 되었습니다.

그러나 W3C CSS 명세에서는 클래스 이름 위주의 CSS 규칙 작성을 권장하지 않는다고 나와 있습니다. HTML의 구조적 의미를 약화할 수 있기 때문입니다. 개인적 의견으로 HTML을 벗어나 CSS 가상 클래스(Pseudo-classes)에서도 :checked, :default, :disabled, :invalid, :required 등 충분히 참조 가능한 빌트인 상태를 제공합니다.

CSS는 클래스 어트리뷰트에 강력한 기능을 부여하여, 고유한 역할이 거의 없는 엘리먼트(예: HTML의 <div><span>)를 기반으로 나만의 “문서 언어"를 설계하고 “class” 어트리뷰트를 통해 스타일을 지정할 수 있습니다. 하지만 문서 언어의 구조적 요소는 일반적으로 정해진 의미가 있지만, 사용자가 임의로 정의한 클래스는 그렇지 않을 수 있습니다. 따라서 이러한 관행을 피하는 것이 좋습니다.“Class Selectors” Selectors Level 3 | W3C

*원문에서 “Authors (작성자)” 키워드를 직역해 보니 어색해서 생략하거나 “사용자"로 대치했습니다.

이 문제는 ARIA State 관점으로도 더욱 깊어질 수 있습니다. 서문의 마지막에서 언급한 aria-invalid(입력이 유효한지 여부), aria-expanded(열림 닫힘 상태), aria-selected(선택되었는지 여부) 어트리뷰트 등을 활용하여 UI 상태를 의미적으로 관리할 수 있기 때문입니다.

사례 1. 유효하지 않은 가격 입력 상태

저는 지난 2023년에 “펜슬컴퍼니"라는 스타트업에서 “글리프“라는 콘텐츠 투고 웹 서비스의 출시 준비 3개월 전부터 프런트엔드 개발을 맡았습니다. 항상 제공하는 기능이 웹 접근성을 제대로 지원 하는지 신경을 쓰며 작업을 했습니다.

주변 동료 또한 HTML의 기본 기능에 충실한 UI 설계와 접근성 표준에 관심을 가지도록 설득하고자 전사적으로 WAI-ARIA 등 접근성 표준에 대한 검수 의견을 꾸준히 공유했습니다. 결과적으로 웹 서비스 개발 가이드에 제 의견이 상당하게 수용되었습니다.4

과거의 작업 내역이 모두 오픈소스로 공개되어 있어 “접근성 및 시멘틱 마크업 – 펜슬컴퍼니 문제별 기여 목록“라는 별도의 페이지로 정리해두었습니다.

첫번째 모범 사례로 “글리프"에서 만든 UI 중에 “콘텐츠 가격을 설정하는 기능"을 준비했습니다.

“콘텐츠 가격을 설정하는 기능"의 UI 요구사항

  1. 100의 배수로만 가격을 입력할 수 있고, 최대 1,000,000까지 설정할 수 있습니다.

  2. 그 외의 입력은 유효하지 않은 입력입니다.

  3. 유효성 검사는 Form 전송 이후로 지연합니다. 유효하지 않은 상태에 대해 아래 피드백이 있습니다.

    • Input UI의 테두리와 배경색이 투명도가 포함된 붉은색으로 바뀝니다.
    • Tooltip UI가 나타나서 유효하지 않은 입력의 상세 이유를 메시지로 알려줍니다.

유효하지 않은 상태 알려주기

위 요구사항 중 유효성 검사 피드백에 대해 임의의 클래스 이름 주입 없이, ARIA State를 선언적으로 활용하여 의미 있는 CSS 규칙을 정의할 수 있습니다.

당시 구현했던 UI를 약식화해서 보여드립니다. (원본은 penxle/withglyph#1296 에서 확인 가능합니다.)

참고: @ui/Tooltip 모듈은 수도코드 이해를 돕기 위해 가정한 가상의 Tooltip UI 컴포넌트입니다.

<script lang="ts">
  import Tooltip from '@ui/Tooltip';

  interface Props {
    errorMessages: string[];
  }

  let { errorMessages }: Props = $props();

  let invalidPrice = $derived(errorMessages.length > 0);

  const errorTooltipId = 'price-input-error';
</script>

<Tooltip enabled={invalidPrice}>
  <!--
    aria-live="assertive":
    엘리먼트 안의 콘텐츠가 바뀔 때마다 보조 기술(Assistive Technology) 도구가 즉시 읽어줍니다.
    -->
  <span slot="message" id={errorTooltipId} aria-live="assertive">
    {errorMessages.join('<br/>')}
  </span>
  <input
    name="price"
    aria-errormessage={errorTooltipId}
    aria-invalid={invalidPrice}
  />
</Tooltip>

<style>
input[name="price"][aria-invalid="true"] {
  border: 1px solid red;
  background-color: rgb(255, 0, 0, 0.5);
}
</style>

가격 Input UI에 유효하지 않은 값이 입력되면, aria-invalid 어트리뷰트를 ture으로 주입합니다. <style /> 블록 내 코드를 보시면, 가격 Input UI의 aria-invalid 어트리뷰트 값이 true인 경우 red 색상의 외곽선과 rgb(255, 0, 0, 0.5)의 배경색이 스타일링 됩니다.

Input UI와 Tooltip 사이의 관계성

두 번째 하위 항목으로 “오류 메시지를 Tooltip UI로 표시하는 피드백"이 있습니다. Tooltip을 사용하여 상세 오류 메시지를 전달할 때, aria-errormessage의 값을 오류 메시지 엘리먼트 ID인 errorTooltipId 상숫값으로 할당하여 오류 메시지와 입력 필드 간의 관계성을 명시할 수 있습니다.

이런 관계성 명시는 보조 기술 사용자의 접근성 향상뿐만 아니라, 자동화된 UI 컴포넌트 테스트를 구성할 때 유용하게 쓰일 수 있는 단서가 됩니다. 실제로 testing-library라는 대표적인 컴포넌트 테스트 라이브러리에서 접근성 트리를 바탕으로 한 getByRole 쿼리의 우선순위가 가장 높게 명시되어 있습니다.

이와 관련한 국내 모범 사례로 “접근성이 이끄는 웹 프런트엔드 테스트 자동화 : Wonderwall Tech” 글이 있으니, 이 활용 방법에 흥미가 있으시다면 정독을 권해드립니다.

사례 2. 위지윅 에디터 툴바 아이템

또 다른 사례로 “글리프"의 위지윅 에디터 툴바 UI에서 글꼴 서식 Select UI 요구사항 구현 사례를 소개해 드립니다.

Select UI 요구사항

  1. Select UI의 버튼 레이블로 현재 커서에 위치한 글꼴 정보를 표시한다.
  2. Select UI의 버튼을 누르면 목록 상자가 열립니다. 그리고 버튼의 배경색이 회색으로 변경, 버튼 레이블 옆의 🔼 아이콘이 180도 회전합니다.
  3. 목록에서 에디터 내 커서로 선택한 글꼴과 동일한 글꼴 항목의 오른쪽에 체크 ✅ 아이콘을 표시한다.

참고: @ui/Toolbar 모듈은 수도코드 이해를 돕기 위해 가정한 가상의 툴바 UI 컴포넌트입니다.

두번째 예시 마크업
<script lang="ts">
  import Toolbar from '@ui/Toolbar';

  interface Props {
    fonts: { label: string; value: string }[]
    selectedFontName: string;
  }

  let { fonts, selectedFontValue }: Props = $props();
  let isFontListOpen = false;

 const onSelectFontValue = (event: MouseEvent & { target: HTMLLIElement }) =>
  (selectedFontValue = event.target.dataset.value);

  const listboxId = 'font-select-listbox'
  const makeOptionIdByFontValue = (value: string) => `font-option-${value}`
</script>

<Toolbar>
  <button
    aria-expanded={isFontListOpen}
    aria-controls={listboxId}
    aria-activedescendent={makeOptionIdByFontValue(selectedFontValue)}
    onclick={() => isFontListOpen = !isFontListOpen}
  >
    {selectedFontValue} <i class="chevron-icon" />
  </button>
<ul role="listbox" id={listboxId}>
  {#each fonts as font}
    <li role="option"
      tabindex={font.value === selectedFontValue ? 0 : -1}
      aria-selected={font.value === selectedFontValue}
      id={makeOptionIdByFontValue(font.value)}
      data-value={font.value}
      onclick={onSelectFontValue}
    >
      {font.name}
      <i class="selected-icon" />
    </li>
  {/each}
</ul>
</Toolbar>

열림과 닫힘을 ARIA State aria-expanded로 표현하기

aria-expanded는 특정 버튼으로 제어하는 UI가 현재 펼쳐진 상태인지 접힌 상태인지 알려주는 불리언 상태입니다. Select UI의 경우 목록이 접혀 있다면 어트리뷰트 값이 false, 펼쳐져 있다면 true가 됩니다.

Select UI 버튼에 해당 상태를 표현하기
button[aria-expanded='true'] {
  background-color: lightgray;

  & > i.chevron-icon {
    /* 버튼 레이블 옆의 🔼 아이콘을 반대로 돌림 */
    transform: rotate(0.5turn);
  }
}

button > i.chevron-icon {
  transition: transform 0.5s;
}

위 CSS 규칙은 글꼴 선택 버튼이 열림 상태일 때 버튼의 배경색을 lightgray로 스타일링합니다. 그리고 버튼 레이블 옆의 🔼 아이콘을 180도 회전하면서(rotate(0.5turn)) 해당 엘리먼트의 transform 프로퍼티에 대해 0.5초의 전환(transition) 효과를 지정했습니다.

이로 인해 시계 방향으로 회전하며 🔽 아이콘으로 바뀌는 전환 애니메이션이 0.5초 동안 재생됩니다.

목록 상자를 보여주기
ul[role='listbox'] {
  display: none;
}

button[aria-expanded='true'] + ul[role='listbox'] {
  /* top, left 지정 코드 생략: JS 실행 시점에서 popover 라이브러리로 구현함 */
  display: block;
  position: absolute;
}

위 CSS 규칙은 버튼의 aria-expanded 상태를 선택자로 활용하여 목록 상자의 열림 여부를 제어합니다. 버튼의 aria-expanded 어트리뷰트 값이 true일 경우, 인접 형제 선택자(Next-sibling combinator) + 로 바로 다음에 위치한 ul 엘리먼트로 감싸진 목록 상자가 화면에 나타나도록 적용됩니다.

이와 같은 선택자 조합을 통해 목록 상자의 숨김 표시에 관한 제어를 JavaScript 실행 시간에 직접 수행하지 않아 UI 상태 표현을 정적으로 분리할 수 있습니다.

선택한 항목에 대해 aria-selected로 표현하기

li[role='option'] > i.selected-icon {
  visually: hidden;
}

li[role='option'][aria-selected='true'] > i.selected-icon {
  /* 선택된 경우 글꼴 이름 옆에 ✅ 아이콘 표시하기 */
  visually: visible;
}

aria-selected은 어떤 항목이 선택되었는지 여부를 가리키는 데에 사용됩니다. 위의 코드 블록을 보시면, 목록의 모든 옵션 엘리먼트에서 이 어트리뷰트를 바탕으로 ✅ 체크 아이콘을 시각적으로 표시하거나 숨기는 CSS 규칙이 정의되어 있습니다.

따라서 선택한 옵션에 대한 피드백을 ARIA 어트리뷰트와 함께 시각적으로 전달하여 사용자의 장애 여부와 관계없이 동등한 정보를 제공할 수 있습니다.

여담: 저는 특이도에 따라 기본 상태의 CSS 규칙이 다른 규칙에 의해 덮어 씌워지는 것이 나쁜 코드 냄새라고 생각하여, 분기에 따른 스타일을 분리하여 정의하는 것을 선호합니다.

- ul[role='listbox'] {
+ button[aria-expanded='false'] + ul[role='listbox'] {
    display: none;
}

button[aria-expanded='true'] + ul[role='listbox'] {
  /* top, left 지정 코드 생략: JS 실행 시점에서 popover 라이브러리로 구현함 */
  display: block;
  position: absolute;
}

- li[role="option"] > i.selected-icon {
+ li[role="option"][selected="false"] > i.selected-icon {
    visually: hidden;
}

li[role="option"][selected="true"] > i.selected-icon {
  /* 선택된 경우 글꼴 이름 옆에 ✅ 아이콘 표시하기 */
  visually: visible;
}

기타 사용한 ARIA 소개

아래 두 어트리뷰트 모두 첫 번째 사례 내용 중에 Input UI와 Tooltip 사이의 관계성과 동등한 이점으로, 자동화된 웹 브라우저 테스트 구성에 유용하게 쓰이는 단서로 쓰일 수 있습니다.

  • aria-controls는 다른 HTML 엘리먼트를 직접 제어하고 있음을 명시하는 어트리뷰트입니다. 예시의 버튼에서 aria-controls는 버튼을 클릭했을 때 나타나는 목록 상자의 ID를 참조하고 있습니다.
    • 이는 스크린 리더와 같은 보조 기술(Assistive Technology) 사용자가 버튼과 제어 대상 UI의 관계를 명확히 파악할 수 있도록 돕습니다.
  • aria-activedescendent는 복합적인 UI에서 초점(Focus)이 실제로 전환하지 않고 가상적으로 활성화된 자식 엘리먼트를 보조 기술에 전달하는 데에 사용합니다.
    • 목록 내 탐색 시 피드백: 보조 기술 도구를 통한 목록 탐색 시 항상 현재 활성 항목의 정보를 알 수 있게 됩니다.
    • Roving Tabindex: 접근성 표준 가이드에 따르면 목록 상자의 옵션 간의 이동은 방향키로 제한됩니다. 그리고 Tab 키를 누른 경우의 목록 박스를 벗어나는 게 올바른 인터렉션입니다. 따라서 두 번째 예시의 마크업 코드 블록을 유심히 읽어보면 활성화한 옵션만 tabindex0이고, 나머지 옵션은 모두 -1로 설정되어 있습니다.
      • 키보드 조작에 관한 모범 사례에 대해서 궁금하시다면, 제가 직접 외부 오픈소스에 컨설팅하는 과정에서 나눈 penxle/readable#1128 대화를 참고 바랍니다.

특징 정리

이 작성법으로 프런트엔드 UI에서 상태와 CSS 규칙을 명확하게 분리할 수 있다는 것을 알 수 있습니다. 특징을 4가지로 정리하여 요약하면 아래와 같습니다.

  1. 의미론적인 CSS 선택자: ARIA 표준에 맞추어 의미를 내포한 CSS 선택자를 조합하여 어떻게 CSS 규칙을 구성할지에 대한 고민의 빈도가 줄어듭니다.
  2. 상태와 스타일의 명확한 분리: HTML 어트리뷰트 바탕의 상태 명시로 CSS 규칙을 JavaScript 실행 시점에서 벗어나 정적으로 분리할 수 있습니다.
  3. HTML에 확장성 제공: HTML이 기본으로 지원하지 않는 복합적인 UI 패턴에 대한 역할과 의미를 ARIA로 표현할 수 있습니다.
  4. 테스트 자동화에 용이: ARIA를 통해 UI 간 관계(ARIA Relationship)와 상태(ARIA State)를 명시적으로 표현하므로 컴포넌트 테스트 구성에 유용한 단서로 활용할 수 있습니다.

빠르게 적용하기

W3C WAI에서 만든 ARIA 작성 방법 가이드에서 자주 쓰이는 여러 UI 패턴의 사례가 접근성을 염두하여 잘 소개되어 있습니다.

W3C WAI에서 만든 ARIA 작성 방법 가이드에서 자주 쓰이는 여러 UI 패턴의 사례가 접근성을 염두하여 잘 소개되어 있습니다.

모든 접근성을 염두에 둬서 UI를 직접 구현하는 일은 번거로울 수 있는 문제입니다. 아래에 나열한 외부 라이브러리는 Headless UI라고 불리는 도구로 스타일을 제외한 UI 제어 로직과 접근성 기능만 제공하는 공통적인 특징을 갖고 있습니다.

  • Ark UI: Chakra UI 커뮤니티에서 자체적으로 사용하고자 만든 도구입니다.
    • 내부적으로 Zag라고 하는 특정 UI 라이브러리에 구애받지 않는(aka. framework-agnostic) FSM 기반 Headless UI 도구를 제어 로직으로 사용하고 있습니다.
    • 특정 UI 라이브러리에 구애받지 않는 설계 덕분에 React, Solid, Vue, Svelte 등 여러 배포판을 같이 운영하고 있습니다.
  • React Aria: Adobe에서 접근성 표준을 우선시하여 여러 React UI 구현 패턴을 Headless UI로 제공하는 모음입니다.
  • Melt UI: Svelte 사용자 커뮤니티에서 운영하는 Headless UI 도구입니다.

다수의 Headless UI 라이브러리는 자주 쓰이는 여러 UI 패턴의 보일러플레이트 코드(boilerplate code, 반복적으로 사용되는 코드)5 의존성 주입(Dependency Injection)을 지원해 주기에 사용을 권장해 드립니다.

마치며

경사로의 눈을 삽으로 치워주실 수 있을까요? 여기 아이들이 계단을 이용하기 위해 기다리고 있는 것이 안 보이니? 이걸 먼저 하고 나서 너를 위해 경사로의 눈을 치워줄테니 기다리렴. 하지만 경사로의 눈을 바로 치우면 모두가 들어갈 수 있잖아요. 특별한 도움을 필요로 하는 이들을 위해 길을 닦는 것은 모두를 위해 길을 닦는 것과 같습니다.

“특별한 도움을 필요로 하는 이들을 위해 길을 닦는 것은 모두를 위해 길을 닦는 것과 같습니다."
장애를 가진 공립학교 학생에게 영감을 받았습니다 - 일러스트 작가 케빈 앨리

유니버설 디자인을 추구하는 ‘하스미 다카시 씨는 공공시설물의 건축설계 공모에서 심사위원장을 맡았습니다. 공공시설물은 2층 짜리 건물인데도 엘리베이터가 설계에 없었습니다. 그래서 그는 엘리베이터를 당연히 설치해야 하는 것 아니냐는 질문을 심사 위원들에게 던졌습니다. 이 질문을 들은 심사위원들은 부정적인 반응을 보였는데, 어떤 심사위원은 건물 사용자 가운데 장애인이 없다는 이유로 반대했고, 어떤 심사위원은 젊은 사람들이 편한 것만 찾는다고 핀잔을 주었다고 합니다. 다카시는 심사 위원들을 설득하려고 묘안이 없을까 고민하다가 이렇게 말했습니다. “2층에 많은 사람을 수용할 수 있는 회의실이 있습니다. 이 회의실로 짐을 옮길 때 엘리베이터를 사용할 수 있습니다.” 이 말을 듣고서야 심사위원 들의 마음을 조금씩 움직였다고 합니다.

일반인은 지하철에 설치된 장애인 리프트, 공공장소에 있는 장애인 화장실, 장애인용 슬로프를 보면서 자신과 관계없는 것이라고 생각합니다. 이런 인식은 (소프트웨어를 포함한) 제품을 만드는 개발자나 디자이너에게도 찾아 볼 수 있습니다. 즉, 이런 인식을 가진 개발자가 장애인이 사용하는 물건을 만들 때 장애인만이 사용할 수 있는 제품을 만드는 경향이 있습니다. 예를 들어 휠체어를 탄 장애인을 지하철 플랫폼까지 데려다 주는 리프트가 이런 인식에서 출발한 것 입니다. 하지만 장애인만 사용 하는 제품을 만들자는 특수해에서 일반인도 사용할 수 있는 제품을 만들자는 일반해로 전환한다면, 장애인용 휠체어보다는 엘리베이터를 설치했을 겁니다.

(중략) 우리가 필요한 것은 장애인 뿐만 아니라 아이, 어른, 노인 등의 모든 사람이 사용할 수 있는 일반해 혹은 융합해입니다.6 우리는 지금까지 더욱 완벽한 일반해를 이끌어 내기 위한 첫 걸음으로 우리 개발자가 몰랐던 ‘사용자’ 에 대해서 알아봤습니다. 이제부터는 우리가 만들었던 소프트웨어에서 어떤 문제가 있는지 살펴 보겠습니다.

2장 “개발자는 사용자를 모른다”, 『겸손한 개발자가 만든 거만한 소프트웨어』, 2009년, 신승환

이 글을 작성하게 된 이유로 웹 접근성에 대한 제 멘탈 모델7을 글로 옮겨 “웹 접근성이 단순히 스크린리더 전용이(특수해) 아닌 UXDX의 설계 도구로, 포괄적으로(융합해) 쓰일 수 있구나"를 외부에 알리고 싶었습니다.

웹 접근성을 같이 신경 쓰는 것이야말로 더 좋은 경험을 만든다고 생각합니다. 어찌 되었든 웹 페이지를 이루는 기본 구성은 의미론적인 마크업 문서이기도 하고, 스스로 이 글의 짜임새를 구조화하면서 “웹 접근성은 사용자 경험의 부분 집합이다“라는 통찰을 얻게 되었습니다.

웹 접근성 기술은 다른 웹 프런트엔드 기술에 비해 상대적으로 관심과 모범 사례가 흔하지 않은 상황입니다. 여전히 제도적으로 의무화된 항공사 웹 서비스 외에 모범 사례가 흔하지 않은 현실에 안타까움을 느낄 따름입니다. 웹 접근성 또한 중요한 프런트엔드 기술이라는 인식이 퍼졌으면 좋겠습니다.

마지막으로 ARIA 활용을 고려하기 전에, HTML을 통한 기본 접근성을 우선 확보한 상태에서 신중히 결정해야 한다는 “No ARIA is better than Bad ARIA.”2 원칙을 다시 당부드리며 마칩니다.

도움을 주신 분

  • 글 초안을 완성한 뒤 퇴고 과정에서 접근성 전문가이신 현진 님의 의견이 많이 도움이 되었습니다.
    • A11YKR이라고, 접근성 및 포괄적인(Inclusive) 웹 디자인을 다루는 커뮤니티가 있습니다.
    • 이 통로를 통해 현진 님에게 여러 차례 퇴고 의견을 들을 수 있었습니다. 만들어진 지 얼마 되지 않은 커뮤니티로 디스코드 서버를 통해 많은 참여 부탁드립니다.
  • 접근성 트리를 최우선으로 삼는 도구 testing-library에 대한 언급을 msy 님이 제안 주셨습니다.

참고하면 좋은 자료

웹 접근성 학습 자료

접근성 기반 UI 설계

직접 실습으로 익히는 것을 권하고자 바로 실천하기 쉬운 자료를 중심으로 골랐습니다.


  1. <input type="checkbox" /> 엘리먼트를 확장하여 구현하는 Switch UI가 대표적으로 HTML에서 제공하지 않은 UI 패턴에 해당합니다. 이 경우 ARIA Role 중에 switch를 통해 접근성 힌트를 제공할 수 있습니다. ↩︎

  2. “올바르지 못한 ARIA 사용은 애초에 하지 않는 것이 낫다”라는 메시지를 적은 문단은 W3C의 APG Practices 페이지 맨 상단 배너에 소개하는 “No ARIA is better than Bad ARIA.” 원칙과 같이 링크된 문서를 직접 참조해서 작성했습니다.

    갈색 피부의 여성이 희미한 미소를 지으며 손을 오른쪽으로 가리키고 있는 그림

    No ARIA is better than Bad ARIA. Before using any ARIA, read this to understand why

     ↩︎ ↩︎

  3. 혹시나 Specificity라는 CSS 용어에 대해 모르시다면 이전에 제 블로그에서 직접 소개한 “CSS Specificity 이해하기” 게시글이 있으니 참고 바랍니다. ↩︎

  4. 가령 텍스트 입력 상호작용에 기본 Form Web API 기반의 설계를 권장하고, 토글 버튼에 aria-pressed를, 로딩 컴포넌트에는 aria-busy를, 버튼 등 비활성화 상태에 대한 관리와 스타일링을 disabledaria-disabled 어트리뷰트를 바탕으로, 그리고 이미 앞서 소개한 CSS 가상 클래스 활용을 권장하고 있습니다. ↩︎

  5. 보일러플레이트 코드란 여러 가지 상황에서 거의 또는 전혀 변경하지 않고 재사용할 수 있는 코드 조각(Snippet)을 의미합니다. 보일러플레이트 코드란 무엇인가요? | 아마존 웹 서비스(AWS) 참고 ↩︎

  6. 『유니버셜 디자인: 따뜻한 사회 조성을 위한』, 2005, 세종출판사, 하스미 다카시 ↩︎

  7. 멘탈 모델은 사용자가 현재 사용 중인 시스템(웹, 앱 또는 기타 제품)에 대한 개인적인 이해와 믿음을 말합니다. 사용자 경험 연구에서 비롯된 용어입니다. Mental Models and User Experience Design | nngroup 참고 ↩︎

  8. 과거 웹 표준을 W3C와 WHATWG에서 나누어 관리했으나, 지금은 WHATWG에서 단일로 관리하고 있습니다. 둘로 나뉜 웹 표준, 하나로 합쳐진다 | ZDNet korea, 2019년 발행. ↩︎