Skip to content

[FE] 땅콩 접근성 개선기

Gyuhan Park edited this page Oct 27, 2024 · 1 revision

우리 서비스의 핵심 영역

방 참여 → 게임 초대 → 게임 시작 → 옵션 선택 → 라운드 결과

스크린 리더 사용자가 게임이 시작되고 라운드가 진행될 때, 화면이 전환되더라도 현재 상황을 이해할 수 있는 것을 목적으로 하였다.

해당 핵심 영역에서의 접근성 문제 정의 및 개선 계획

스크린 리더 개선 목표 및 계획

개선 최종 목표: 땅콩을 스크린리더로 무리 없이 사용할 수 있다.

1차 스프린트 : 핵심 기능이 포함된 페이지 개선

  • 게임 화면, 투표 결과 화면

2차 스프린트 : 그 외 기능이 포함된 페이지 개선

  • 닉네임 설정 화면, 대기 방 화면, 매칭 결과 화면

우선 순위 설정

개선 기준

  1. Semantic tag를 쓰자

  2. ARIA 속성은 꼭 필요한 경우에만 사용한다

  3. 문서를 잘 읽자

  4. 스크린리더 전용 컴포넌트를 사용하자

✅ 닉네임 화면

문제 상황

  • 닉네임이 최대 12 글자인데 최대 글자에 도달한 것을 리더기에서 인지할 수 없는 상황.
    • 닉네임이 12 글자가 되어 더 이상 입력하지 못하는 경우 이를 사용자에게 알려주고 싶다.
  • 닉네임에 focus가 되어도 리더기에서 제대로 인지하지 못함
    • 현재 닉네임에 focus가 되었는지 여부를 리더기 사용자에게 알리고 싶음

개선 결과

  • 닉네임이 최대 글자에 도달하면 “최대 길이에 도달했습니다“라는 안내 메세지가 나온다.
  • “aria-label”과 “aria-live” 닉네임에 focus 될 때와 닉네임을 입력할 때 알 수 있도록 설정하였다.

✅ 대기 화면

문제 상황

  • 방 설정 컴포넌트에 focus가 되었을 때 설정 내용들이 여러 태그에 흩어져 있어 내용이 한 번에 읽히지 않는 상황
    • 리더기 사용자에게 카테고리/라운드 수/제한 시간을 한 번에 읽게 하고 싶다.
  • 방 설정 모달
    • 카테고리 선택 목록
      1. 어떤 선택 목록인지 알 수 없다.
      2. 목록이 열려있고 스와이프 했을 때 요소로 넘어가지 못한다.
      3. 목록 중 몇 번째인지 알 수 없다.
      4. 목록 중 어느 것이 선택되어 있는지 알 수 없다.
      5. 선택 후 포커스를 잃는다.
    • 라운드, 제한 시간
      1. 어떤 설정 값이 선택되어 있는지 알 수 없다.
      2. 몇 개의 목록 중 몇 번째인지 알 수 없다.

개선 결과

  • 공통으로 만든 “A11Only” 컴포넌트를 사용하여 방 정보를 한 번에 읽을 수 있도록 수정하였다.
  • 방 설정 모달
    • 카테고리 선택 목록
      • 어떤 선택 목록인지 알 수 있다.

        📢 카테고리 선택 목록, 현재 선택: 연애, 팝업 버튼, 상자 팝업, 피커를 활성화 하려면 이중탭 하십시오.

      • 목록이 열려있고 스와이프를 했을 때 다음 요소를 읽을 수 있다.

        📢 카테고리 선택 목록 -> 연애 -> 만약에 -> MBTI -> 음식

      • 목록의 시작과 끝을 알 수 있다.

        📢 연애 목록 시작 -> ... -> 음식 목록 끝

      • 해당 옵션이 선택되어 있는지 알 수 있다.

        📢 선택됨 음식

      • 옵션 선택 후 포커스가 다시 선택 목록이 된다.

    • 라운드, 제한 시간
      • 어떤 설정 값이 선택되어 있는지 알 수 있다.

        📢 5 선택 버튼 선택됨

      • 몇 개의 옵션 중 몇 번째인지 알 수 없다.

        📢총 3개 중 1번째

✅ 게임 화면

문제 상황

  • 게임이 시작되었는데 게임이 시작되었는지 알 수 없었다.
    • 게임 화면으로 넘어갔을 때 전체 라운드와 현재 라운드를 알려주면 좋겠다.
  • 헤더의 텍스트를 끊어서 읽고 불필요한 정보까지 전달한다.
    • 헤더에서 게임 정보를 알려주면 좋겠다.
  • 옵션이 선택된 옵션인지 알 수 없었다.
    • 옵션 중 하나만 선택 가능하고, 선택 가능한 옵션인지 알려주면 좋겠다.
  • 현재 타이머가 몇초 남았는지 알 수 없었다.
    • 기준을 세우고, 기준에 따라서 사용자에게 현재 타이머를 알려주면 좋겠다.

개선 결과

  • 게임 화면으로 넘어갔을 때 전체 라운드, 현재 라운드, 질문, 제한 시간을 안내하여 게임을 수월하게 진행하도록 개선하였다.
  • 처음 라운드 시작되었을 때, 절반 지났을 때, 5초 남았을 때로 총 3번으로 나눠서 제한시간을 알려주었다. role=”alert” 를 사용하여 특정 지점에서 제한 시간을 안내하도록 설정하였다.
  • 옵션이 이미 선택된 경우 선택됨 이라고 안내 음성이 나오며, radioradiogroup 을 사용하여 두 개 중 몇 번째라는 안내 음성을 제공한다.

실제 개선 과정과 결과(개선 후 재측정)

before / afer 좀 더 직관적으로 확인할 수 있게 영상을 같이 첨부해주세요

✅ 시각적으로 보이지 않는 요소 A11yOnly 컴포넌트를 사용하여 개선

import { ElementType, AriaRole, PropsWithChildren } from 'react';

import { a11yOnlyLayout } from './A11yOnly.styled';

interface A11yOnlyProps<T extends ElementType = 'span'> {
  as?: T;
  role?: AriaRole;
}

const A11yOnly = <T extends ElementType = 'span'>({
  as,
  children,
  ...props
}: PropsWithChildren<A11yOnlyProps<T>>) => {
  const Component = as || 'span';
  return (
    <Component css={a11yOnlyLayout} {...props}>
      {children}
    </Component>
  );
};

export default A11yOnly;

접근성 전용 컴포넌트를 사용한 이유

두 가지 방향으로 코드를 작성해 보고, A11yOnly 컴포넌트를 적용한 코드가 가독성이 더 좋고 유지 보수를 하기에 용이하다고 생각했기 때문이다.

✅ 방 설정 모달

개선 전

_.mov

개선 후

_._.mov

✅ 타이머

개선 전

_.mov

개선 후

_.mov

✅ 매칭 결과

개선 전

_.mov

개선 후

_.mov

✅ 공통

Modal Focus 개선

Modal을 열고 닫을 때 focus가 제대로 된 위치를 찾지 못하고 있는 상황

  • 문제점: Modal이 mount 되었을 때 focus가 Modal의 내부가 아닌 Modal의 바깥쪽에서 움직이고 있는 상황
  • 해결: Modal이 mount 되었을 때 useRef 사용하여 Modal에 ref를 넣고 useEffect 내부에서 Modal ref의 focus 함수를 실행시켜 Focus가 Modal로 오게 만듦
modal-focus.mp4
  • 문제점: Modal이 unmount 될 때 focus 기존에 있었던 위치로 돌아가지 않고 엉뚱한 곳으로 focus가 돌아가는 상황
  • 해결: 현재 구현 방식은 Modal이 특정 버튼을 클릭하면 Modal 호출 함수가 실행되고 Modal이 뜨는 방식이다. 그래서 호출 함수에 인자로 “특정 버튼의 ref”를 넣어주어 Modal 에서 unmount 될 때 인자로 전달해준 ref로 focus가 되도록 구현해서 리더기 사용자가 Modal 닫히더라도 계속해서 서비스를 이용할 수 있게 만듦
modal-close.mp4

페이지 로드 시 Header에 focus

  • 문제점: 버튼을 눌러 다음 페이지로 넘어갈 경우 다음 페이지에서의 fosuc가 맨 위로 올라오는 것이 아닌 이전 페이지의 버튼 위치에 계속 머물러 있어. 리더기 사용자 입장에서는 당황스러운 상황
  • 해결: Header 태그에 ref를 넣고 useEffect 내부에서 매 페이지가 첫 로딩 될 때 마다 ref의 focus 함수를 실행시킨다.
header-focus.mp4
Clone this wiki locally