[TIL] 웹 접근성 개선 방법

승민·2025년 4월 25일
0

TIL

목록 보기
17/20

1. 시멘틱 HTML 구조

의미 있는 시멘틱 HTML은 스크린 리더가 콘텐츠를 올바르게 해석하도록 돕고, SEO와 코드 가독성을 개선합니다.

비시멘틱 태그(예: <div>)는 스크린 리더가 버튼, 내비게이션 등의 역할을 인식하지 못합니다. 그래서, <button>, <nav>, <main> 같은 시멘틱 태그를 통해 콘텐츠의 역할과 구조를 명확히 전달해야 합니다.

버튼은 <button>, 링크는 <a>, 내비게이션은 <nav>로 구현.
페이지 구조를 <header>, <main>, <footer>로 정의.
콘텐츠 그룹핑에 <section>, <article> 사용.

예시

<header>
  <nav aria-label="주요 내비게이션">
    <ul>
      <li><a href="/"></a></li>
      <li><a href="/about">소개</a></li>
    </ul>
  </nav>
</header>
<main>
  <section>
    <h1>웹 접근성</h1>
    <article>
      <p>모든 사용자를 위한 설계</p>
    </article>
  </section>
</main>
<footer>
  <p>© 2025</p>
</footer>

검증 방법
Chrome 개발자 도구의 Accessibility Tree로 시멘틱 구조 확인.
NVDA 또는 VoiceOver로 페이지 탐색 테스트(예: 내비게이션, 제목 순서 확인).
Lighthouse의 Accessibility 점수로 구조적 문제 점검.

2. ARIA 속성 사용

ARIA(Accessible Rich Internet Applications)는 동적 콘텐츠와 비표준 UI의 접근성을 개선합니다.
스크린 리더가 복잡한 인터페이스를 이해하도록 역할, 상태, 속성을 명시한다.

SPA(예: React)에서 모달, 알림 등 동적 콘텐츠가 스크린 리더에 전달되지 않을 수 있기에 ARIA는 보조 기술과의 호환성을 높여 접근성을 강화해야 합니다.

적용 방법
role로 요소의 역할 정의(예: alert, dialog, button).
aria-live로 동적 콘텐츠 업데이트 알림(예: polite, assertive).
aria-label, aria-describedby로 추가 설명 제공.
aria-hidden으로 스크린 리더가 무시할 요소 지정.

예시
동적 에러 메시지

<div role="alert" aria-live="assertive">오류: 이메일을 입력하세요</div>

버튼에 설명

<button aria-label="메뉴 열기"></button>

입력 필드 설명

<input id="email" type="email" aria-describedby="email-help">
<span id="email-help">유효한 이메일을 입력하세요</span>
<div role="dialog" aria-labelledby="modal-title" aria-modal="true">
  <h2 id="modal-title">로그인</h2>
  <form>
    <label for="username">사용자 이름</label>
    <input id="username" type="text">
  </form>
  <button aria-label="모달 닫기">X</button>
</div>


<!-- 장식용 요소 숨김 -->
<span aria-hidden="true" class="decorative-icon"></span>

React에서 ARIA 적용

function Modal() {
  return (
    <div role="dialog" aria-labelledby="modal-title">
      <h2 id="modal-title">알림</h2>
      <button aria-label="닫기" onClick={closeModal}>X</button>
    </div>
  );
}

동적 콘텐츠 업데이트

const alert = document.createElement('div');
alert.setAttribute('role', 'alert');
alert.setAttribute('aria-live', 'polite');
alert.textContent = '새 메시지 도착';
document.body.appendChild(alert);

주의점
잘못된 ARIA는 스크린 리더에 혼란을 줄 수 있음.
시멘틱 HTML로 해결 가능한 경우 ARIA 최소화(예: <button>에 role="button" 불필요)

검증 방법
axe DevTools로 ARIA 이슈 진단.
VoiceOver로 ARIA 속성 동작 확인(예: 모달 열림 알림).
NVDA로 aria-live 알림 테스트.

3. 키보드 접근 지원

운동장애인이나 마우스를 사용하지 않는 사용자를 위해 모든 인터랙티브 요소(버튼, 링크, 폼 등)가 키보드로 조작 가능해야 합니다.

WCAG는 모든 기능을 키보드로 사용할 수 있어야 한다고 명시.

기본 포커스 가능 요소(<a>, <button>, <input>) 사용.
tabindex로 포커스 순서 관리:
tabindex="0": 자연스러운 포커스 가능.
tabindex="-1": JavaScript로만 포커스 가능.

동적 콘텐츠 추가 시 포커스 이동 관리.
:focus 스타일로 시각적 피드백 제공.

예시
포커스 가능한 링크

<a href="/home" tabindex="0"></a>

동적 포커스

<div id="new-content" tabindex="-1">새 콘텐츠</div>
<script>
  document.getElementById('new-content').focus();
</script>

포커스 스타일

a:focus, button:focus, [tabindex="0"]:focus {
  outline: 2px solid #005FCC;
  outline-offset: 2px;
}

드롭다운 메뉴

<div role="menu" tabindex="0" aria-label="옵션 메뉴">
  <div role="menuitem" tabindex="-1">옵션 1</div>
  <div role="menuitem" tabindex="-1">옵션 2</div>
</div>
<script>
  const menu = document.querySelector('[role="menu"]');
  menu.addEventListener('keydown', (e) => {
    if (e.key === 'Enter') {
      console.log('메뉴 항목 선택');
    }
  });
</script>

모달 열릴 때 포커스 이동

function openModal() {
  const modal = document.querySelector('[role="dialog"]');
  modal.setAttribute('aria-modal', 'true');
  modal.querySelector('button').focus();
}

Tab 트랩(Tab Trap)으로 모달 내 포커스 유지

const modal = document.querySelector('[role="dialog"]');
const focusableElements = modal.querySelectorAll('a, button, input');
const first = focusableElements[0];
const last = focusableElements[focusableElements.length - 1];

modal.addEventListener('keydown', (e) => {
  if (e.key === 'Tab') {
    if (e.shiftKey && document.activeElement === first) {
      e.preventDefault();
      last.focus();
    } else if (!e.shiftKey && document.activeElement === last) {
      e.preventDefault();
      first.focus();
    }
  }
});

검증 방법
Tab 키로 내비게이션 테스트(논리적 순서 확인).
포커스 스타일이 시각적으로 명확한지 확인.
NVDA로 포커스 이동 및 알림 확인.

4. 색상 대비 최적화

낮은 대비는 색맹(예: 적록색맹)이나 저시력 사용자가 텍스트를 인식하지 못하게 해 텍스트와 배경 간 색상 대비를 WCAG 기준(최소 4.5:1)으로 유지해 색맹 및 저시력 사용자가 콘텐츠를 쉽게 읽을 수 있도록 해야합니다.

텍스트와 배경 색상 대비 4.5:1 이상 유지(큰 텍스트는 3:1).
색상만으로 정보 전달 피하기(예: 빨간색으로만 에러 표시 X).
고대비 모드 지원.

예시
적절한 대비

.text {
  color: #000000; /* 검정 */
  background-color: #FFFFFF; /* 흰색 */
}

고대비 모드

@media (prefers-contrast: high) {
  .text {
    color: #FFFFFF;
    background-color: #000000;
  }
}

색상 외 단서

<span style="color: red; border: 1px solid red;" aria-live="polite">오류: 입력 필요</span>

버튼 스타일

button {
  background-color: #005FCC;
  color: #FFFFFF;
  border: 2px solid transparent;
}
button.error {
  background-color: #D32F2F;
  border-color: #FFFFFF; /* 색상 외 단서 */
}

WebAIM Contrast Checker로 색상 대비 확인.
색맹 시뮬레이터(예: Stark)로 테스트.
CSS 변수로 색상 관리:

:root {
  --text-color: #000000;
  --bg-color: #FFFFFF;
}
.text {
  color: var(--text-color);
  background-color: var(--bg-color);
}

검증 방법
Lighthouse의 Accessibility 탭으로 대비 점수 확인.
색맹 시뮬레이터로 가독성 테스트.
고대비 모드에서 스타일 확인(Windows: Win + Ctrl + C).

핵심 정리

시멘틱 HTML: <button>, <nav>로 구조를 명확히 하고 스크린 리더 호환성을 높인다.
ARIA 속성: aria-live, aria-label로 동적 콘텐츠를 보조 기술에 전달.
키보드 접근: tabindex, 포커스 스타일, Tab 트랩으로 모든 기능을 키보드로 조작 가능하게.
색상 대비: 4.5:1 대비 유지, 색상 외 단서 제공, 고대비 모드 지원.

0개의 댓글