searchgithubemail

웹 접근성 (A11y)

웹 접근성(A11y)에 대한 이해와 실천 방법

2025-08-29

웹 접근성이란?

웹 접근성이란 장애가 있는 사람을 포함해 모든 사용자가 동등하게 웹에 접근하고 이용할 수 있도록 보장하는 것을 의미

더 많은 사용자에게 도달할 수 있고, 성능 최적화, 사용자 경험(UX)을 개선하며, 검색엔진 최적화(SEO)에도 긍정적인 효과가 있음

웹 접근성은 “특정 집단(장애인)”이 아닌 모든 사람을 위한 기본 설계 원칙

시멘틱 마크업

mdn

div와 span 대신 header, main, nav, article, section, footer와 같은 시맨틱 태그 활용.

버튼은 반드시 <button> 태그를 사용. (div에 onClick 대신)

<!-- X -->
<div onclick="submitForm()">제출</div>

<!-- O -->
<button type="submit">제출</button>

대체 텍스트

이미지에는 항상 alt 속성을 제공

장식용 이미지는 alt=""로 설정하여 스크린 리더가 읽지 않도록 함

    <img src="logo.png" alt="pass 로고" />

상호작용 요소 목록

상호작용 요소 중 하나를 포함하는 요소 안에는 또 다른 상호작용 요소를 넣을 수 없다

    <!-- X -->
    <a href="/">
      <Button>확인</Button>
    </a>

    <!-- X -->
    <button>
      시설관리
      <button>
        x
      </button>
    </button>

a 태그와 button 태그

라우팅시에는 <a> 태그 사용

<a> 태그: 웹 표준상 “다른 리소스로 이동”을 의미 → 페이지 이동, 라우팅에 적합

<button> 태그: 현재 페이지 내에서 특정 동작(폼 제출, 모달 열기 등)을 실행하는 요소

// react-router-dom

// O
<Link to="/profile">프로필</Link>

// X
<button onClick={() => navigate('/profile')}>프로필</button>

시맨틱 태그에 따라 마우스 오른쪽 버튼을 클릭했을때 나타나는 컨텍스트 메뉴가 다르다

a 태그 컨텍스트 메뉴button 태그 컨텍스트 메뉴
<a> 태그
<button> 태그

ARIA

ARIA (Accessible Rich Internet Applications)는 웹 애플리케이션을 보조기기(스크린리더 등)에서도 이해할 수 있도록 돕는 속성들의 모음

HTML의 시맨틱 태그만으로는 표현하기 어려운 상태, 역할, 속성을 전달할 때 사용

👉 ARIA는 보완 수단, HTML 기본 시맨틱 요소로 표현할 수 있다면 ARIA보다 태그를 우선 사용하는 게 원칙

주요 구성 요소

예시

    <button
        type="button"
        role="switch"
        aria-checked={checked}
        disabled={disabled}
        onClick={handleCheckedClick}
        {...rest}
    >
    {...}
    </button>
  1. role="switch"

HTML에는 토글 스위치(Switch)라는 시맨틱 태그가 존재하지 않음

role="switch"를 주면, 스크린리더는 “스위치”로 읽고, 켜짐/꺼짐 상태를 인지할 수 있음

  1. aria-checked=checked

스위치의 현재 상태를 전달

true → “켜짐(on)”, false → “꺼짐(off)” 으로 읽어줌

스크린리더 사용자는 버튼의 현재 상태를 바로 알 수 있음

  1. disabled=disabled

네이티브 HTML 속성. 버튼이 비활성화되어 있음을 알려줌

스크린리더는 “비활성화됨”이라고 읽어줌

  1. onClick=handleCheckedClick

스위치를 토글하는 이벤트 핸들러

보조기기 사용자도 키보드 Enter / Space로 조작할 수 있음 (버튼의 기본 기능)


키보드 접근성

    <!-- 비대화형 요소에 포커스 필요할 때만 -->
    <div tabindex="-1" id="result" aria-live="polite"></div>

포커스 표시와 스타일

    button:focus-visible,
    a:focus-visible {
        outline: 2px solid currentColor;
        outline-offset: 2px;
    }

링크 텍스트

    <a href="/docs" aria-label="문서 센터 바로가기">문서</a>
    <a href="/pricing" aria-label="요금제 안내 바로가기">문서</a>

폼과 에러 처리

    <label for="email">이메일</label>
    <input id="email" name="email" type="email" aria-describedby="email-hint email-err" required>
    <p id="email-hint">회사 이메일 형식 권장</p>
    <p id="email-err" class="visually-hidden" role="alert"></p>

    <script>
        const input = document.getElementById('email');
        const err = document.getElementById('email-err');
        input.addEventListener('invalid', () => { err.textContent = '올바른 이메일 주소를 입력'; });
    </script>

헤딩 구조

    <h1>제품</h1>
    <h2>개요</h2>
    <h3>주요 기능</h3>

모달/다이얼로그

<div role="dialog" aria-modal="true" aria-labelledby="dlg-title" aria-describedby="dlg-desc">
    <h2 id="dlg-title">설정</h2>
    <p id="dlg-desc">알림 설정을 변경</p>
    <button type="button">저장</button>
</div>