ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [React Conf 2024] Demystifying Accessibility in React Apps
    Study/개발 2024. 7. 3. 22:37

    https://youtu.be/0ckOUBiuxVY

     

    React Conf 2024에서 Demystifying Accessibility in React Apps라는 발표가 있었다.

    이번 포스팅에서는 발표 내용을 정리하며 React 앱에서 접근성을 어떻게 구현할 수 있는지 알아본다.

    접근성의 정의

    • Accessibility: 장애가 있는 사람들도 동일하게 접근하고 사용할 수 있도록 하는 것.
    • 실생활 예시: 휠체어 경사로, 점자 블록 등.
    • 디지털 환경: 스크린 리더 등이 해당됨.

    접근성의 동작 방식

    • 웹 문서는 HTML로 받아 DOM 트리로 파싱하고 UI로 사용자에게 보여진다.
    • 이 때, DOM 트리를 기반으로 접근성 트리(Accessibility Tree)가 생성된다.
    • 접근성 트리는 개발자 도구에서 확인할 수 있다.

    출처: 하단 발표 자료 링크
    개발자 도구 접근성 트리 캡쳐

    • DOM 노드처럼 접근성 tree의 노드도 name, role, focusable, description 등 다양한 속성을 가진다.
    • 이 트리를 통해 보조 기술(Assistive Technology)이 동작한다.
    • ex) 스크린 리더는 접근성 트리를 순회하며 각 노드의 정보를 읽는다.

     

    • Semantic HTML이 중요한 이유는 여기에 있다.
    • 모든 요소가 <div>로만 구성되어 있다면 각 노드의 의미를 알기 힘들어지고 접근성이 떨어진다.

     

    ARIA - Accessible Rich Internet Applications

    • ARIA는 접근성 트리를 제어할 수 있는 도구이다.
    • 요소의 동작이나 외관을 변경하지 않고도 접근성을 향상시킬 수 있다.
    • ex) aria-placeholder, aria-label 등

    주의!

    대부분의 경우 기본 HTML만 잘 사용해도 충분하다.
    통계적으로 ARIA를 사용하는 곳에서 접근성 오류가 더 많이 발생한다.

     

    예시 1: 아이콘 버튼

     

    icon + text

    • 아이콘의 경우 접근성 관점에서 불필요할 수 있다.
    • 이 경우 icon을 aria-hidden을 통해 접근성 tree에서 숨길 수 있다.
    <button>
      <span aria-hidden="true">🔍</span>
      Submit
    </button>

     

    icon만 있는 버튼

    • 텍스트가 없는 아이콘 버튼 UI는 접근 가능한 이름이 없어서 스크린 리더가 "button"이라고만 읽는다.
    • aria-label을 통해 이름을 줄 수 있지만 번역은 되지 않는다.
    • 대신 버튼 안에 span 태그로 텍스트를 넣고 CSS로 숨길 수 있다.
    const VisuallyHidden = ({ children }) => (
      <span style={{
        position: 'absolute',
        height: '1px',
        width: '1px',
        padding: 0,
        margin: '-1px',
        overflow: 'hidden',
        clip: 'rect(0 0 0 0)',
        whiteSpace: 'nowrap'
        border: 0,
      }}>
        {children}
      </span>
    );
    
    const IconButton = () => (
      <button>
        <span aria-hidden="true">🔍</span>
        <VisuallyHidden>Submit</VisuallyHidden>
      </button>
    );
    
    

     

    예시 2: 텍스트 입력

    • input 만으로는 어떤 값을 입력하는지 알 수 없기 때문에 반드시 연관된 label이 필요하다.
    • input과 label을 연결하기 위해 htmlFor 속성을 사용해야 한다.
    // input의 name을 찾지못함.
    <label>Username</label>
    <input type="text" name="username" />
    
    // input이 label과 연결되어 어떤 input인지 찾을 수 있음.
    <label htmlFor={inputId}>Username</label>
    <input type="text" name="username" id={inputId} />
    

     

    • 라벨을 UI에서 숨기고 placeholder를 통해 노출하는 경우도 있다.
    • 이때, 아까 만든 VisuallyHidden 컴포넌트를 활용할 수도 있다.
    // as를 통해 태그 다형성 지원
    const VisuallyHidden = ({ as: Tag = "span", ...props }) => {
      return <Tag className="visually-hidden" {...props} />;
    }
    
    <VisuallyHidden as="label" htmlFor={inputId}>Username</VisuallyHidden>
    <input type="text" name="username" id={inputId} placeholder="Username" />

     

    • 인풋 하단에 인풋에 대한 설명을 보여줄 때가 있다.
    • ARIA를 활용해 이 설명이 해당 인풋의 설명인 것을 명시해줄 수 있다.
    • 접근성 트리의 input 노드의 description 속성에 해당 설명이 들어가서 스크린 리더가 읽을 수 있다.
    <label htmlFor={inputId}>Username</label>
    <input
      type="text"
      name="username"
      id={inputId}
      aria-describedby={hintId}
    />
    <span id={hintId}>
      Must be between 3 and 20 characters long
    </span>

     

    • input의 오류 상태는 aria-invalid를 통해 나타내줄 수 있다.
    • aria-invalid는 스타일링에도 사용할 수 있다.
    • 오류 메시지또한 aria-describedby에 추가해줄 수 있다. 여러 id가 가능하다.
    <input
      type="text"
      name="username"
      id={inputId}
      aria-describedby={[errorId, hintId].join(' ')}
    />
    <span id={errorId}>
      Must be between 3 and 20 characters long
    </span>
    .input[aria-invalid="true"] {
      border-color: red;
    }

     

    예시 3: 알림

    • 알림은 보통 어떤 동작이 일어날 때 화면에 나타난다.
    • 스크린 리더는 화면을 순차적으로 읽기 때문에 이를 바로 읽지 못할 수 있다.
    • 이때 aria-live 영역을 사용할 수 있다.
    • 페이지의 특정 부분을 라이브 영역으로 지정하면, 그 부분은 모니터링되며 스크린 리더에 의해 읽혀진다.
    • aria-live="polite"와 aria-atomic="true"가 합쳐진role="status" 을 사용해도 된다.
    aria-live = 
    	| "off"
    	| "polite" // user가 idle 한 경우. 가장 많이 사용
    	| "assertive" // 변화 시 즉각적으로 읽기. 즉시 전달해야할 때 사용
    

     

    // 이 영역에 변화가 생기면, screen reader에 전달되어 내용이 읽어진다.
    <div aria-live="polite">
      {message}
    </div>
    
    // 또는, 
    <div role="status">
      {message}
    </div>
    

     

    맺음말

    접근성은 하나의 스펙트럼이다. 완벽하게 구현하지 않아도 조금씩 개선해 나가는 것이 중요하다. 접근성을 고려하여 React 앱을 개발하면 더 많은 사용자가 편리하게 이용할 수 있다. 모두가 접근 가능한 웹을 함께 만들어 나가자.

    발표 자료

    Demystifying accessibility in React apps

     

    728x90

    'Study > 개발' 카테고리의 다른 글

    타입스크립트 5.5 베타 요약  (0) 2024.07.02
    Tmux 마우스 드래그 오류  (0) 2024.07.01
    Regular Expression 종류, 동작 방식, 성능  (2) 2024.03.23
    React 18 - Suspense 분석하기  (0) 2024.02.21
    Neovim  (2) 2023.12.28
Designed by Tistory.