토스의 접근성 문서 A11y Fundamentals 을 소개합니다 (오픈 기념 이벤트 ~9/10)

강민우 · 토스 Frontend Developer
2025년 8월 13일

A11y Fundamentals 이란?

토스는 ‘누구나 금융을 쉽게’ 사용할 수 있는 세상을 꿈꿔요. 그래서 제품을 만들 때도, 문서를 쓸 때도, 접근성을 고민합니다. 접근성(Accessibility, 줄여서 A11y)은 모든 사용자가 더 쉽고 편리하게 웹을 사용할 수 있도록 돕는 기본 원칙이에요.

개발자분들과 이야기하다 보면, 접근성이 중요하다는 건 알지만 어떻게 시작해야 할지 모르겠다는 이야기를 많이 들어요. 그래서 토스는 실제 개발 과정에서 자주 부딪히는 실수와 핵심 개념을 정리한 접근성 문서 A11y Fundamentals 을 오픈했어요.

'접근성은 어려운 것' 이라고 느끼는 분들을 위해 실무에서 바로 적용할 수 있는 접근성의 핵심 개념과 실수하기 쉬운 패턴을 알려줘요. 버튼 안에 버튼을 넣으면 왜 안 되는지, <a> 태그 안에 <button>이 들어가면 어떤 문제가 생기는지, 스크린 리더 사용자는 어떻게 콘텐츠를 읽는지 등을 실제 예시와 함께 알려드려요.

프론트엔드 개발자는 HTML 구조를 만들고 인터랙션을 정의해요. 사용자와 가장 가까이에서 웹 경험을 설계하는 만큼, 접근성의 출발점이자 핵심 역할을 맡고 있죠. 그래서 프론트엔드 개발자가 접근성을 신경 쓰면 누구나 이용할 수 있는 웹을 만들 수 있어요.

접근성을 왜 지켜야 할까요?

장애인, 비장애인, 개발자 모두에게 효용이 있기 때문이에요. 장애인 사용자는 스크린리더 같은 보조기기를 통해 웹사이트를 원활하게 이용할 수 있고, 일반 사용자도 더 빠르고 편리한 웹 경험을 할 수 있어요. 또한 개발자는 더 견고하고 유지보수하기 쉬운 코드를 작성할 수 있어요.

장애인에게 필요한 이유

버튼의 색상, 아이콘 형태, 레이아웃 배치, 차트나 이미지 같은 웹 상의 시각적 정보를 볼 수 없는 사용자는 어떻게 웹사이트를 이용할까요? 바로 스크린리더 같은 보조기기를 사용합니다. 이때, 올바른 역할(role), 레이블(label), 대체 텍스트(alt) 같은 접근성 속성이 제공되지 않으면 원하는 정보를 얻지 못하거나, 버튼·링크 같은 상호작용 요소를 놓쳐 웹사이트 사용에 큰 불편을 겪게 돼요.

예를 들어, 단순히 클릭 이벤트만 달아둔 <div> 는 스크린리더에서 버튼 요소로 인식되지 않아서 사용자가 해당 기능을 사용할 수 없어요.

일반 사용자에게도 유용한 이유

접근성을 지키면 장애가 없는 일반 사용자도 웹을 더 빠르고 편리하게 이용할 수 있어요. 익숙한 웹 동작이 자연스럽게 제공되기 때문이에요.

예를 들어, 링크(<a>)를 제대로 사용하면 마우스 오른쪽 버튼으로 '새 창에서 열기', '링크 복사'와 같은 동작을 할 수 있어요. 하지만 단순히 <div>나 <span>에 클릭 이벤트만 넣으면 이런 기본 기능을 사용할 수 없어요. 또, 폼을 만들 때 올바른 <form> 태그와 <input><button type="submit">을 사용하면 사용자가 Enter 키를 눌러 폼을 제출할 수 있어요. 하지만 그렇지 않으면 사용자는 익숙한 동작을 기대할 수 없어요.

또, 키보드를 주로 사용하는 사용자는 Tab 키와 Shift+Tab, Enter, Space, 방향키 등으로 웹사이트를 탐색해요. 버튼이나 링크, 폼 요소에 올바른 역할과 포커스가 지정되어 있지 않으면, 키보드로는 해당 기능을 사용할 수 없어요.

다음 이미지는 브라우저에서 링크를 우클릭했을 때 나타나는 컨텍스트 메뉴예요. 링크 요소를 제대로 사용하면 사용자가 기대하는 이런 기본적인 기능들을 모두 사용할 수 있어요.

이처럼 접근성은 장애인 사용자 뿐만 아니라 키보드를 사용하는 사용자, 그리고 일반적인 웹 경험을 기대하는 모든 사람들에게 불편함을 주지 않기 위해 꼭 지켜야 하는 기본 원칙이에요. 접근성을 고려하지 않으면 누구나 겪을 수 있는 불편함이 생길 수 있어요.

접근성을 지켰을 때 개발자가 얻는 효용

접근성을 잘 지키면 UI 테스트 코드에서 요소를 특정하기가 매우 쉬워져요. 예를 들어, testing-library에서는 ByRole 이라는 쿼리를 이용해 요소를 선택하는 것을 권장하고 있어요. 이 방법을 사용하면 버튼, 입력창, 링크 등 역할(role)이 명확하게 정의된 요소를 쉽게 찾을 수 있어요.

예를 들어, 다음과 같이 명확하게 "저장" 이라는 이름을 가진 "버튼" 을 선택할 수 있게 돼요.

// 접근성을 잘 지킨 경우
render(<button>저장</button>);
expect(screen.getByRole('button', { name: '저장' })).toBeInTheDocument();

같은 이름을 가진 여러 요소가 있을 때도, 상위 요소의 접근성 레이블을 활용하면 구분도 쉽고, 사용자가 쉽게 선택할 수 있어요.

// 같은 이름의 요소를 상위 접근성 역할 설정을 통해 특정 짓기
render(
  <ul>
    <li aria-labelledby="item1-title">
      <span id="item1-title">사과</span>
      <button>저장</button>
    </li>
    <li aria-labelledby="item2-title">
      <span id="item2-title">복숭아</span>
      <button>저장</button>
    </li>
  </ul>
);
const 복숭아 = screen.getByRole('listitem', { name: '복숭아' });
const 복숭아저장버튼 = getByRole(복숭아, 'button', { name: '저장' })
expect(복숭아저장버튼).toBeInTheDocument();

반면, querySelector를 사용해서 요소를 선택하면 마크업 구조가 조금만 바뀌어도 테스트가 쉽게 깨질 수 있어요. ByTestId 는 테스트를 위해 별도의 속성을 추가해야 하고, 이 값이 서비스 코드에 남는다는 단점이 있어요. 하지만 ByRole을 사용하면 실제 사용자와 동일한 방식으로 요소를 찾을 수 있고, 유일한 역할을 가진 요소를 쉽게 특정할 수 있어요. 이는 접근성을 잘 지킨 마크업 구조에서만 가능한 일이에요.

// querySelector를 사용하는 경우 (마크업 구조가 바뀌면 깨질 수 있어요)
expect(document.querySelector('ul > li:nth-child(2) > button')).toBeInTheDocument();

// getByTestId를 사용하는 경우 (테스트용 속성이 서비스 코드에 남아요)
render(<button data-testid="save-btn">저장</button>);
expect(screen.getByTestId('save-btn')).toBeInTheDocument();

즉, 접근성은 사용자 모두를 위한 것이면서, 개발자에게도 더 견고하고 유지보수하기 쉬운 코드를 만들 수 있게 도와줘요.


주요 원칙

웹 콘텐츠 접근성을 높이기 위해 네 가지 핵심 원칙과 각 원칙을 지킬 수 있는 구체적인 방법을 제안볼 수 있어요. 자세한 내용은 눌러서 확인해보세요.

1. 구조를 명확하게 만들기

버튼 안에 버튼 넣지 않기

테이블 행에 직접 onClick 붙이지 않기

2. 의미를 정확히 전달하기

인터렉티브 요소에 이름 붙이기

같은 이름의 요소에는 설명 추가하기

3. 예상 가능한 동작 만들기

버튼의 역할과 동작이 일치하게 만들기

입력 요소는 <form> 으로 감싸기

4. 시각 정보 보완하기

이미지와 아이콘에 적절한 대체 텍스트 제공하기


🔊 토스 송금 스크린리더 체험 이벤트 ( ~9/10 )

A11y Fundamentals 문서 오픈을 기념해, 특별한 체험 이벤트도 함께 준비했어요.

스크린리더 환경에서 소리만으로 송금하기, 직접 경험해보세요.

참여 방법

1.[체험하기 페이지]에서 스크린리더 환경으로 송금 서비스를 사용해보세요.

2.체험 완료 스크린샷을 깃허브 페이지에 댓글로 남겨주세요.

3.참여해주신 분 중 추첨을 통해 선물을 드립니다!

🎁 당첨자분에게는 9월 10일에 GitHub에 등록된 이메일로 개별 안내드려요.
  • 관련 메시지를 받는 경우 반드시 정식 계정 여부를 확인 부탁드려요. (본 이벤트는 카드 등록 및 결제 관련 정보 등을 절대로 요구하지 않아요.)
  • 당첨 안내 시 사용되는 이메일은 안내 목적으로만 이용되며, 별도로 저장하지 않아요.

접근성이 왜 중요한지, 그리고 스크린리더 환경이 어떤지, 직접 체험해보면 훨씬 더 깊이 이해할 수 있어요. 이번 이벤트가 그런 작은 계기가 되어주길 바랍니다.

댓글 0댓글 관련 문의: toss-tech@toss.im
㈜비바리퍼블리카 Copyright © Viva Republica, Inc. All Rights Reserved.