WAI-ARIA(3) aria-*

Jimin Lee·2024년 12월 15일

WAI-ARIA

목록 보기
3/3

그외 aria-속성들에 대해 알아보자.

element간 관계를 나타내는 속성들

aria-controls

콤보박스, 탭, 버튼과 같이 특정 element(controlling element)가 다른 element(controlled element)를 변경할 수 있다면 controlling element에 aria-controls를 정의한다.
aria-controls가 정의하는 값은 이 element가 컨트롤하고 있는 element의 id이다.

aria-owns와의 차이?

둘다 element 간의 관계를 보여주기 위해 사용한다. 차이점은, aria-controls는 controlled-controlling 관계에 초점이 맞춰져있고 aria-owns는 DOM에서는 아니지만 문맥적으로 부모-자식 관계일 때 이를 표현하기 위해 사용한다.

사용 예시

  • 아코디언에서 아코디언을 펼치는 버튼이 있다면 해당 버튼에 aria-controls = ‘아코디언의 panel id’를 추가한다.
  • element의 role='scrollbar'일 때 aria-controls에 스크롤을 컨트롤하는 대상 id를 정의한다.
  • element의 role='tab'일 때 aria-controls에 tab에 상응하는 tabpanel id를 정의한다.

aria-owns

실제 DOM에서는 부모-자식 관계가 아닌 element 사이에서 부모-자식 관계를 표현하기 위해 사용한다. (하지만 이 역시 가능하다면 DOM에서 부모 자식으로 표현하는 게 베스트이다.)
부모로 생각되는 element에 aria-owns='자식으로 생각되는 element id'를 정의한다.
만약 DOM 상에서 자식 element가 존재한다면 focus 순서는 자식 element → aria-owns로 지정된 element 순이다.

사용 예시

  • 팝업 메뉴: 팝업 메뉴를 띄운 후 다시 그 옆에 서브 팝업 메뉴를 띄울 때 DOM에서는 두 개의 다른 팝업 메뉴를 띄울 수 있다. 이 때 처음에 열린 팝업 메뉴에 aria-owns=‘서브 팝업 메뉴 id’를 추가하면 된다.

aria-expanded

aria-expanded는 controlled element가 expanded 상태인지를 표현한다. aria-controls와 함께 사용하는 경우가 많다.

사용 예시

  • 버튼에서: 버튼으로 위젯(다이알로그나 메뉴)을 연다면 aria-controls에 해당 위젯의 id를, aria-expanded에 위젯 상태를 정의한다.
    <button aria-expanded="false" aria-controls="widget1">Show widget</button>
  • 그외 아코디언, 팝업, 콤보박스, multi-selectable 탭에서 사용할 수 있다.

aria-haspopup

해당 element가 interactive popup element를 트리거할 수 있음을 알려준다. 여기서 interactive popup element는 menu, listbox, tree, grid, dialog가 해당하고 tooltip은 interactive하지 않아서 제외된다.

계속 언급하지만 popup 기능이 있는건 아니라서 popup이 되는 기능은 직접 정의해야 한다.

가능한 value

  • menu, listbox, tree, grid, dialog
  • true: true일 경우 menu와 동일하다.

사용 예시

  • menu에서: 누르면 menu가 보여지는 button에 aria-haspopup='true'를 설정할 수 있다.
  • dialog에서: 누르면 dialog가 띄워지는 버튼에 aria-haspopup='dialog'를 설정할 수 있다.

접근성 이름을 표기하기

aria-label

interactive element는 accessible name이 있어야 한다. 예를 들어 button의 accessible name은 버튼 태그 안의 텍스트이다. <label for…>와 함께 사용되는 element에서는 label에 들어가는 텍스트가 accessible name 역할을 한다.

<!-- 아래 버튼의 accessible name은 ok -->
<button> ok </button>

<!-- 아래 input의 accessible name은 Kraken -->
<input type="radio" id="kraken" name="monster" value="K" />
<label for="kraken">Kraken</label>

몇몇 경우에 이 accessible name을 지정할 수 없는 경우가 있는데 이 때 aria-label을 사용할 수 있다. 예를 들어 button 안에 text 대신 svg가 들어있다면 aria-label을 사용해서 accessible name을 지정할 수 있다.

<button aria-label="Close" onclick="myDialog.close()">
  <svg
    aria-hidden="true"
    focusable="false"
    .../>
</button>

aria-labelledby

aria-label과 마찬가지로 대상의 accessible name을 지정하는 역할이다. aria-labelledby에 다른 element의 id를 지정하면 aria-labelledby로 지정된 element가 해당 element의 accessible name을 지정하는 대상이 된다.

<span
  role="checkbox"
  aria-checked="false"
  tabindex="0"
  aria-labelledby="tac"></span>
<span id="tac">I agree to the Terms and Conditions.</span>

사용 예시

  • interactive content: link, video, form controls(input, textarea …)
  • <main>,<nav>

사용하지 말아야 하는 경우 혹은 사용해도 의미없는 경우

  • <footer>, <article>, <header>
  • heading element: h1, h2, …등
  • non-interative content: p, li, ul 등
  • role이 없는 span 혹은 div
  • 가능하면 <img>에서는 alt, <input><label>과 함께 사용하자

선택 표기

aria-selected, aria-checked, aria-current, aria-pressed 모두 element의 ‘현재 상태’에 대해 설명하고, role에 따라 다른 attributes를 적용한다.

aria-selected

role이 gridcelll, options, row, tab인 경우 현재 ‘선택된’ 상태를 표현할 때 사용한다. 두 개 이상의 element가 동시에 선택 가능할 땐 aria-multiselectable='true'을 같이 적용해준다.

사용 예시

  • option에서: role='option'의 경우 aria-checked와 aria-selected가 모두 적용 가능하다. single-select 리스트에 aria-selected를 적용하고 multi-select 리스트에 aria-checked를 사용한다.
  • tab에서: role='tab'에서 현재 선택된 탭을 나타낼 때 aria-selected='true’를 설정한다.

aria-checked

role이 radio button, checkbox일 때 현재 checked된 상태를 나타내기 위해 사용한다. 마찬가지로 input태그의 type='checkbox', type='radio'를 사용한다면 필요없다.

<span
  role="checkbox"
  id="checkBoxInput"
  aria-checked="false"
  tabindex="0"
  aria-labelledby="chk15-label"></span>
<label id="chk15-label">Subscribe to the newsletter</label>

value

  • aria-checked='true': 체크됨
  • aria-checked='false': 체크되지 않음
  • aria-checked='mixed': 아직 결정되지 않음. 체크도 체크아닌 상태도 아니다. mixed는 checkbox, menitemcheckbox에서만 지원되고 radio, switch에서는 지원하지 않는다.

aria-current

여러 element 중에서 현재 활성화된 무언가를 정의하기 위해 사용한다. aria-current= page, step, location, date, time, true, false가 가능하다. 디폴트는 false이고 빈값으로 정의하거나 빈 문자열일 경우에도 false로 설정된다. 반면에 non-null 문자열은 aria-current='true'로 취급된다.

사용 예시: breadcrumb list 혹은 페이지네이션

페이지 링크가 여러 개 있을 때 유저가 현재 있는 페이지의 링크 element에 aria-current='page'를 정의한다.

<nav aria-label="Breadcrumb" class="breadcrumb">
  <ol>
    <li>
      <a href="../../../../">Accessibility</a>
    </li>
    <li>
      <a href="../../../">ARIA</a>
    </li>
    <li>
      <a href="../../">ARIA States and Properties</a>
    </li>
    <li>
      <a href="./" aria-current="page">ARIA: `aria-current` attribute</a>
    </li>
  </ol>
</nav>

서베이 혹은 여러 단계로 구성된 프로세스에서 현재 단계에 해당하는 element에 aria-current='step'을 표시한다.


aria-pressed

토클 버튼에서 현재 눌린 상태임을 나타낸다. role='button'에서 aria-pressed를 정의하면 토클 버튼이 된다.

value

  • aria-pressed='true': 눌린 상태
  • aria-pressed='false': 눌리지 않은 상태
  • aria-pressed='mixed'

이 역시 aria-pressed를 사용하기 보단, <button>을 사용하여 직접 label을 변경한다거나 style을 변경해주는 게 좋다.


접근성 숨기기

aria-hidden, role='presentation' 모두 접근성 트리에서 무언가를 숨긴다는 공통점이 있다. aria-hidden은 element 자체를 숨기고 presentation은 element의 semantic을 숨긴다.

aria-hidden

non-interactive한 컨텐츠 자체를 접근성 트리에서 숨기는데 사용하는 속성이다. (hidden처럼 실제로 숨기는 건 아니다.)

사용 예시

  • 순수 데코 목적의 컨텐츠(ex.아이콘이나 이미지). 가장 많이 사용하는 예시이다.

    <button type="button" aria-label="Previous section" class="previous-button">
       <VarcoIcon name="doubleChevronLeft" class="icon" aria-hidden="true" />
    </button>

    만약 <img>를 사용한다면 alt를 사용해서 해결 가능하다.

    <button><img src="doubleChevronLeft.svg" alt=""></button>
  • 중복된 컨텐츠 ex) 반복되는 텍스트

  • 스크린을 벗어났거나 열고 닫히는 컨텐츠 ex) 메뉴

사용하지 말아야 하는 경우

  • HTML 속성인 hidden이 존재할 때

  • element 혹은 element 조상이 display:none 혹은 visitbility: hidden 상태일 때

  • element 혹은 element 조상이 focusable할 때

  • role='presentation'과 함께

    <!-- 잘못된 예시 -->
    <div aria-hidden="true">
      <button>press me</button>
    </div>
    
    <!-- 아래 예시에서 aria-hidden은 무의미하다. -->
    <span id="msg" style="display:none" aria-hidden="true">hidden message</span>

    반면에 아래와 같이 focusable하지 않은 element라면 interactive하더라도 사용 가능하다.

    <!--사용 가능 -->
    button {opacity:0}
    <button tabindex="-1" aria-hidden="true">press me</button>

role='presentation' (role='none')

role='none'이 없어지고 대체되었다. aria-hidden은 아예 접근성 트리에서 element를 숨긴다면 presentiation은 element의 ARIA sematic을 제거한다.

해당 role은 사용을 지양하는게 좋다. 아래 둘은 같은 의미이므로 처음부터 후자로 작성하는게 맞다.

<!-- avoid -->
<h2 role="presentation">Democracy Dies in Darkness</h2>

<!-- instead -->
<div>Democracy Dies in Darkness</div>

사용 예시

그럼에도 불구하고 사용되는 케이스가 있는데, 과거에 레이아웃 잡을 때 <table> 혹은 <ul>, <ol>, <li>을 사용해서 space 간격을 잡아줬다. 이 때 css를 위해 사용된 태그들의 의미를 제거하는 용도로 사용했다.

아래 코드도 a 태그 외에 ul과 li는 의미상 크게 중요하지 않다. 이 경우에 ul에 presentation을 적용하여 li의 ARIA semantic까지 제거한다.

<ul role="presentation">
  <li><a href="#">Link1</a></li>
  <li><a href="#">Link2</a></li>
  <!-- etc. -->
</ul>

사용해도 의미없는 경우

  • element 혹은 element 조상이 focusable할 때
  • a 태그와 같이 link가 있거나 input, 혹은 tabindex를 지닌 focusable element는 role='presentation'을 무시한다.
  • aria-hidden과 함께

aria-disabled

aria-disabled='true'일 경우 HTML의 disabled와 동일하게 사용이 불가하다는 걸 나타내지만 기능까지 disabled 상태로 만들진 않으므로 개발자가 직접 정의해야 한다.

사용 예시

  • element가 disabled 상태지만 포커스 순서 지키는게 중요해서 Tab 키를 사용해서 접근은 가능해야 할 때 (=키보드 네비게이션은 가능해야 할 때)
  • disabled이 없는 경우
  • div를 사용해서 직접 버튼을 제작했을 때 (div엔 disabled가 없다.)
    <div role="button" aria-disabled="true" tabindex="-1">Edit</div>
  • 메뉴, 다이알로그, 아코디언과 같이 열고 닫히는 위젯을 컨트롤하는 element에 적용한다. 컨트롤 대상이 열려있는지 닫혀있는지를 표현한다.

참고

https://w3c.github.io/using-aria/#third

https://developer.mozilla.org/en-US/docs/Web/Accessibility

https://www.scottohara.me/blog/2018/05/05/hidden-vs-none.html

0개의 댓글