Accessibility(접근성)

코더·2019년 2월 1일
8

https://reactjs.org/docs/accessibility.html - 번역 글

웹 접근성 (a11y 라고도 함)은 모든 사람이 사용할 수있는 웹 사이트를 만드는 것입니다. 웹페이지에 대한 접근성을 지원하기 위해서 보조 기술이 필요합니다.

표준 HTML 기술을 이용하여 웹사이트의 접근성 지원이 가능합니다.


Standards and Guidelines(표준 및 지침)

WCAG

웹 사이트를 만들기 위한 웹 콘텐츠 접근성 지침을 제공합니다.

WCAG 체크리스트 관련 내용을 제공합니다.

WAI-ARIA

Web Accessibility Initiative - Accessible Rich Internet Applications 문서에는 접근성을 보장할 수 있는 JavaScript 위젯을 작성하는 기술이 포함되어 있습니다.

모든 aria-*HTML 속성은 JSX에서 완벽하게 지원됩니다. React의 대부분의 DOM 속성은 camelCase로 지정하지만, 이 속성은 일반 HTML과 마찬가지로 하이픈 (cbab-case) 규칙으로 지정합니다. 하이픈 규칙은 리스프 케이스 (lisp-case)라고도 합니다.

<input
  type="text"
  aria-label={labelText}
  aria-required="true"
  onChange={onchangeHandler}
  value={inputValue}
  name="name"
/>

Semantic HTML

웹 애플리케이션 접근성 제공은 시맨틱 HTML을 기반으로 합니다. 웹 사이트의 접근성을 제공하기 위해서는 다양한 HTML 요소를 사용하여 웹 사이트에서 정보의 의미를 강화합니다.

React 코드 작성을위해 간혹 JSX<div>요소를 추가하여 HTML 의미를 깨뜨릴 수 있습니다.

React 코드를 작성하기 위해 JSX에서 시멘틱 HTML을 깨트리는 경우가 있습니다. 특히 <ol>, <ul>, <dl>, <table>를 사용할때 발생하며, 이런 경우 React Fragments를 사용 하여 여러 요소를 그룹화 하여 이를 해결할 수 있습니다.

예를 들어

import React, { Fragment } from 'react';

function ListItem({ item }) {
  return (
    <Fragment>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </Fragment>
  );
}

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        <ListItem item={item} key={item.id} />
      ))}
    </dl>
  );
}

다른 유형의 요소들처럼 dl 관련 태그들을 배열에 매핑 할 수 있습니다.

function Glossary(props) {
  return (
    <dl>
      {props.items.map(item => (
        // Fragments should also have a `key` prop when mapping collections
        <Fragment key={item.id}>
          <dt>{item.term}</dt>
          <dd>{item.description}</dd>
        </Fragment>
      ))}
    </dl>
  );
}

툴링 지원이 있다면 Fragment 태그에 props이 필요 없는 경우 간단한 구문을 사용할 수 있습니다.

function ListItem({ item }) {
  return (
    <>
      <dt>{item.term}</dt>
      <dd>{item.description}</dd>
    </>
  );
}

자세한 내용 은 Fragments 문서를 참조하십시오 .


Accessible Forms(폼 접근성)

Labeling

접근성을 위해 <input>, <textarea> 같은 모든 HTML 폼 컨트롤에는 스크린 리더에 읽히는 설명 라벨을 제공해야합니다.

아래 링크는 관련 방법들을 보여줍니다.

이러한 표준 HTML 사례는 React에서 직접 사용할 수 있지만 for 속성은 JSX에서 htmlFor로 작성해야 합니다.

<label htmlFor="namedInput">Name:</label>
<input id="namedInput" type="text" name="name"/>

Notifying the user of errors(사용자에게 오류 알림)

오류 상황은 모든 사용자가 인지 해야 합니다. 다음 링크는 스크린 리더기에 오류 텍스트를 표시하는 방법을 보여줍니다.


Focus Control(포커스 제어)

웹 응용 프로그램이 키보드로만 완벽하게 작동 할 수 있는지 확인하십시오.

Keyboard focus and focus outline(키보드 포커스와 포커스 아웃라인)

키보드 포커스는 현재 선택된 DOM요소를 나타냅니다. 다음 이미지처럼 포커스가 된 요소를 흔히 볼 수 있습니다.

예시 이미지

이 선택 효과를 제거 하려 한다면 CSS 만 사용하십시오. 예를 들어 다른 포커스 효과를 주길 원한다면 outline: 0를 설정합니다.

Mechanisms to skip to desired content(원하는 내용으로 건너뛰는 매커니즘)

색션을 건너뛰는 매커니즘을 이용하여 사용자의 키보드 탐색을 지원합니다.

Skiplink 또는 Skip Navigation Links는 키보드 사용자가 페이지와 상호 작용할 때만 표시되는 숨겨진 탐색 링크입니다. 앵커 태그및 CSS를 사용한다면 쉽게 구현 가능합니다.

  • WebAIM - 탐색 링크 건너 뛰기

    <main>, <aside> 같은 요소를 사용하여 페이지 영역을 구분한다면 사용자는 관련 세션으로 빠르게 이동할 수 있습니다.

    접근성을 높이기 위해 위와 같은 요소를 사용하는 방법에 대해 자세히 알아보십시오.

  • 접근성 랜드마크 요소

Programmatically managing focus(프로그래밍 방식으로 포커스 관리)

React 애플리케이션은 런타임 중에 HTML DOM을 지속적으로 변경합니다. 프로그래밍 방식으로 올바른 포커스 방식으로 이동시켜 키보드 포커스를 잃어 버리거나 의도하지않은 요소로 설정되는 문제를 해결할 수 있습니다. 예를 들어, 모달창을 닫은 후에 모달창을 연 button태그에 포커스를 다시 설정합니다.

MDN Web Docs탐색 가능한 JavaScript 위젯 제작방법을 설명합니다.

React에서 Refs를 사용하여 DOM요소에 대한 포커스를 설정합니다.

이를 참고하여 컴포넌트 클레스의 JSX에서 요소에 대한 참조를 작성합니다.

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    // Create a ref to store the textInput DOM element
    this.textInput = React.createRef();
  }
  render() {
  // Use the `ref` callback to store a reference to the text input DOM
  // element in an instance field (for example, this.textInput).
    return (
      <input
        type="text"
        ref={this.textInput}
      />
    );
  }
}

이렇게 한다면 필요할때마다 컴포넌트의 요소를 포커스할 수 있습니다.

focus() {
  // Explicitly focus the text input using the raw DOM API
  // Note: we're accessing "current" to get the DOM node
  this.textInput.current.focus();
}

간혹 부모 컴포넌트가 자식 컴포넌트의 요소에 포커스 설정이 필요한 경우가 있습니다. 다음과 같이 자식 컴포넌트에 propsDOM Refs를 부모 컴포넌트의 노출을 전달 하여 자식의 DOM노드에 설정할 수 있습니다.

function CustomTextInput(props) {
  return (
    <div>
      <input ref={props.inputRef} />
    </div>
  );
}

class Parent extends React.Component {
  constructor(props) {
    super(props);
    this.inputElement = React.createRef();
  }
  render() {
    return (
      <CustomTextInput inputRef={this.inputElement} />
    );
  }
}

// Now you can set focus when required.
this.inputElement.current.focus();

HOC를 사용하여 컴포넌트를 확장 하는 경우, React의 forwardRef함수를 사용하여 래핑된 컴포넌트로 참조를 전달 하는 것이 좋습니다. 만약 third-party HOC가 ref전달을 구현하지 않은 경우 위 패턴을 폴백으로 사용할 수 있습니다.

좋은 초점 관리 예는 react-aria-modal입니다. 이것은 포커스로 접근이 불가능한 모달 윈도우의 예입니다. 키보드를 이용하여 모달의 취소 버튼에 초기 초첨을 설정할 뿐만 아니라 키보드 사용자가 잘못된 성공 동작을 활성화 하는 것을 방지 합니다. 또한 처음 모달을 트리거한 요소로 포커스를 다시 설정합니다.

노트
이것은 접근성을위해 매우 중요한 것들이며, 현명하게 사용되어야 하는 기술이기도 합니다.
사용자가 키보드를 이용하여 어플리케이션을 사용하는데 방해받지 않도록 하세요.


Mouse and pointer events(마우스 및 포인터 이벤트)

키보드만을 이용하여 마우스 또는 포인터 이벤트를 통해 노출되는 모든 기능을 사용할 수 있는지 확인하세요. 포인터 장치로만 사용할 수 있다면 키보드 사용자가 어플리케이션을 사용할 수 없는 경우가 많습니다.

클릭 이벤트로 인해 접근성이 망가지는 경우가 많습니다. 아래는 외부 클릭 패턴이며, 사용자가 요소 외부를 클릭하여 열린 팝업을 제거 하는 동작을 합니다.

외부 클릭 예시

이것은 보통 window객체의 click이벤트를 이용하여 popover를 닫는 방식으로 구현합니다.

class OuterClickExample extends React.Component {
constructor(props) {
    super(props);

    this.state = { isOpen: false };
    this.toggleContainer = React.createRef();

    this.onClickHandler = this.onClickHandler.bind(this);
    this.onClickOutsideHandler = this.onClickOutsideHandler.bind(this);
  }

  componentDidMount() {
    window.addEventListener('click', this.onClickOutsideHandler);
  }

  componentWillUnmount() {
    window.removeEventListener('click', this.onClickOutsideHandler);
  }

  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }

  onClickOutsideHandler(event) {
    if (this.state.isOpen && !this.toggleContainer.current.contains(event.target)) {
      this.setState({ isOpen: false });
    }
  }

  render() {
    return (
      <div ref={this.toggleContainer}>
        <button onClick={this.onClickHandler}>Select an option</button>
        {this.state.isOpen ? (
          <ul>
            <li>Option 1</li>
            <li>Option 2</li>
            <li>Option 3</li>
          </ul>
        ) : null}
      </div>
    );
  }
}

이것은 마우스와 같은 포인터 장치를 사용하는 사용자에게 적합니다. window객체가 click이벤트를 받지 못하기 때문에 다음 요소로 이동할때 기능이 키보드 만으로는 모달레이어를 닫을 수없습니다. 때문에 사용자가 어플리케이션을 사용못하게됩니다.

키보드 사용예

onBluronFocus와 같은 적절한 이벤트 처리기를 이용한다면 이를 해결할 수 있습니다.

class BlurExample extends React.Component {
  constructor(props) {
    super(props);

    this.state = { isOpen: false };
    this.timeOutId = null;

    this.onClickHandler = this.onClickHandler.bind(this);
    this.onBlurHandler = this.onBlurHandler.bind(this);
    this.onFocusHandler = this.onFocusHandler.bind(this);
  }

  onClickHandler() {
    this.setState(currentState => ({
      isOpen: !currentState.isOpen
    }));
  }

  // We close the popover on the next tick by using setTimeout.
  // This is necessary because we need to first check if
  // another child of the element has received focus as
  // the blur event fires prior to the new focus event.
  onBlurHandler() {
    this.timeOutId = setTimeout(() => {
      this.setState({
        isOpen: false
      });
    });
  }

  // If a child receives focus, do not close the popover.
  onFocusHandler() {
    clearTimeout(this.timeOutId);
  }

  render() {
    // React assists us by bubbling the blur and
    // focus events to the parent.
    return (
      <div onBlur={this.onBlurHandler}
           onFocus={this.onFocusHandler}>

        <button onClick={this.onClickHandler}
                aria-haspopup="true"
                aria-expanded={this.state.isOpen}>
          Select an option
        </button>
        {this.state.isOpen ? (
          <ul>
            <li>Option 1</li>
            <li>Option 2</li>
            <li>Option 3</li>
          </ul>
        ) : null}
      </div>
    );
  }
}

이 코드는 포인터 장치와 키보드 사용자 모두에게 기능을 제공합니다. 스크린 리더 사용자를 지원하기 위해 추가된 aria-* props도 참고 하세요. 간략하게 사용하기위해 popover옵션의 화살표를 이용한 이벤트 처리를 구현되지 않았습니다.

키보드 지원 성공예시

포인터 및 마우스 이벤트만으로 키보드 사용자의 기능을 지원하지 않는 경우의 예시 입니다. 키보드로 항상 테스트를 한다면 문제가되는 부분을 쉽게 찾을수 있습니다.


More Complex Widgets(복잡한 위젯)

복잡한 위젯이 안좋은 사용자 경험은 아닙니다. 복잡한 위젯이라도 HTML을 이용하여 보다 쉽게 접근성을 지원할 수 있습니다.

여기서 우리는 ARIA RolesARIA 상태및 속성에 대한 지식이 필요합니다. JSX에서 완벽하게 지원되는 HTML속성으로 접근성이 우수한 React 컴포넌트를 만들 수 있습니다.


Other Points for Consideration(기타 고려사항)

Setting the language(언어 설정)

스크린 리더기가 페이지에서 사용된 언어의 선택합니다.

Setting the document title(문서 제목 설정)

현재 페이지 내용을 정확하게 설명하도록 <title>를 설정한다면 사용자는 현재페이지 문맥을 알 수 있습니다.

React Document Title Component를 사용하여 설정가능합니다.

Color contrast(색 대비)

시력이 약한 사용자가 읽을 수 있도록 웹 사이트에서 읽을 수있는 텍스트의 색 대비가 충분한 지 확인하십시오.

웹 사이트의 모든 경우에 대한 적절한 색상 조합을 수동으로 계산하는 것이 지루할 수 있습니다. 이런경우Colorable을 사용하여 접근 가능한 색상 팔레트 전체를 계산할 수 있습니다.

아래 언급된 aXeWAVE도구는 색상 대비 테스트를 포함하고 오류를 알려줍니다.

대비 테스트 기능에 다음 도구를 사용할 수 있습니다.


Development and Testing Tools(개발 및 테스트 도구)

접근성을 제공하는 웹 어플리케이션을 만드는데 도움이되는 다양한 도구들이 있습니다.

The keyboard(키보드)

가장 쉬운 방법은 전체 웹사이트를 키보드만을 사용하여 테스트하는 것입니다. 다음을 참고 하세요

  1. 마우스를 꽂습니다.
  2. Tab, Shift + Tab을 사용하여 검색 할 수 있습니다.
  3. Enter를 사용하여 요소를 활성화 합니다.
  4. 필요한 경우 키보드 화살표키를 사용하여 메뉴 및 드롭 다운 같은 일부 요소와 상호작용할 수 있습니다.

Development assistance(개발 보조)

JSX코드에서 접근성 기능을 확인할 수 있습니다. IDE툴에서 JSX코드에서 ARIA역할과 state, props를 인지하여 인텔리 센스 검사 기능을 제공합니다. 관련된 다음도구를 사용할 수 있습니다.

eslint-plugin-jsx-a11y

eslint-plugin-jsx-a11y ESLint용 플러그인, JSX에서 접근성문제에 관련된 AST linting 피드백을 제공합니다. 많은 IDE가 이런 결과를 코두 분석 및 코드 소스 창에 직접 통합할수 있도록 합니다.

React Create App은 subset rule로 이러한 플러그인을 갖고 있습니다. 더 많은 접근성 규칙을 사용하길 원한다면 프로젝트 루트에 다음과 같은 .eslintrc파일을 만들 수 있습니다.

{
  "extends": ["react-app", "plugin:jsx-a11y/recommended"],
  "plugins": ["jsx-a11y"]
}

Testing accessibility in the browser(브라우저에서 접근성 테스트)

브라우저에서 웹 페이지의 접근성 검사를 할 수 있는 여러 도구가 있습니다. HTML 접근성만 테스트 할 수 있으므로 여기에 언급 된 다른 접근성 검사와 함께 사용하십시오.

aXe, aXe-core and react-axe

Dequq Systems가 제공하는 aXe-core는 자동화된 어플리케이션 end-to-end 접근성 테스트를 수행합니다. 이 모듈은 Selenium과 통합되어 있습니다.

접근성 앤진 또는 aXeax-core를 기반으로 만들어진 접근성 검사 브라우저 확장도구 입니다.

또한 react-ax 모듈을 사용하여 개발 및 디버깅 하는동안 접근성 결과를 콘솔에 직접 노출할 수 있습니다.

WebAIM WAVE

웹 접근성 평가도구는 또 다른 접근성 브라우저 확장 도구 입니다.

Accessibility inspectors and the Accessibility Tree(접근성 검사 및 접근성 트리)

접근성 트리는 스크린 리더기와 같이 보조 기술에 노출되어야하는 모든 DOM 요소에 대한 접근 가능한 객체를 포함하는 DOM 트리의 subset입니다.

일부 브라우저에서 접근성 트리의 각 요소에 대한 접근성 정보를 쉽게 볼 수 있습니다.

Screen readers(스크린 리더)

스크린 리더를 사용한 테스트는 접근성 테스트의 일부를 구성해야합니다.

브라우저 / 스크린 리더 조합은 중요합니다. 선택한 스크린 리더에 가장 적합한 브라우저에서 응용 프로그램을 테스트하는 것이 좋습니다.

Commonly Used Screen Readers(일반적으로 사용되는 스크린 리더)

NVDA in Firefox(Firefox의 NVDA)

NonVisual Desktop Access 또는 NVDA는 널리 사용되는 오픈 소스 Windows 스크린 리더기 입니다.

NVDA를 사용하는 방법에 대한 다음 가이드를 참조하십시오

VoiceOver in Safari(Safari의 VoiceOver)

VoiceOverApple 기기의 통합 스크린 리더입니다.

VoiceOver를 활성화및 사용하는 방법에 대한 다음 가이드를 참조하십시오.

JAWS in Internet Explorer(Internet Explorer의 JAWS)

Job Access Speech 또는 JAWS를 사용하여 Windows에서 자주 사용되는 스크린 리더입니다.

JAWS 사용 방법에 대해서는 다음 안내서를 참조하십시오.

Other Screen Readers(기타 스크린 리더기)

ChromeChromeVox

ChromeVoxChromebook의 통합 스크린 리더이며 Chrome확장 프로그램으로 제공 됩니다 .

ChromeVox를 사용하는 가장 좋은 방법에 대한 다음 가이드를 참조하세요.

2개의 댓글

comment-user-thumbnail
2019년 2월 2일

번역 감사합니다!

답글 달기
comment-user-thumbnail
2022년 9월 5일

정말 글을 잘 쓰시는군요. waffle game

답글 달기