OPEN HYPER STEP
← 목록으로 (stack-analysis)
STACK-ANALYSIS · 25 / 90
stack-analysis
CHAPTER 25 / 90
읽기 약 2
FUNCTION

접근성(a11y): WCAG 2.2 + ARIA


핵심 개념

aria-label·focus management·키보드 네비·screen reader — Lighthouse a11y 100점.

본문

시맨틱 HTML 우선

TSX📋 코드 (24줄)
// ❌ div 남발
<div onClick={handleClick}>버튼</div>

// ✅ 시맨틱
<button onClick={handleClick}>버튼</button>


// ❌
<div className="header">
  <div className="logo">로고</div>
  <div className="nav">
    <div onClick={...}>메뉴1</div>
  </div>
</div>

// ✅
<header>
  <a href="/" aria-label="홈">로고</a>
  <nav aria-label="주요 메뉴">
    <ul>
      <li><a href="/about">메뉴1</a></li>
    </ul>
  </nav>
</header>

ARIA 속성

TSX📋 코드 (34줄)
// 모달
<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="dialog-title"
  aria-describedby="dialog-desc"
>
  <h2 id="dialog-title">삭제 확인</h2>
  <p id="dialog-desc">정말 삭제하시겠습니까?</p>
  <button>취소</button>
  <button>확인</button>
</div>


// 토글 버튼
<button
  aria-pressed={isPressed}
  aria-label={isPressed ? '음소거 해제' : '음소거'}
  onClick={() => setIsPressed(!isPressed)}
>
  {isPressed ? '🔇' : '🔊'}
</button>


// 진행 상태
<div
  role="progressbar"
  aria-valuenow={progress}
  aria-valuemin={0}
  aria-valuemax={100}
  aria-label="업로드 진행률"
>
  <div style={{ width: `${progress}%` }} />
</div>

Focus Management

TSX📋 코드 (35줄)
import { useEffect, useRef } from 'react';

function Modal({ isOpen, onClose }: Props) {
  const closeBtnRef = useRef<HTMLButtonElement>(null);
  const previousFocus = useRef<HTMLElement | null>(null);

  useEffect(() => {
    if (isOpen) {
      previousFocus.current = document.activeElement as HTMLElement;
      closeBtnRef.current?.focus();
    } else {
      previousFocus.current?.focus();  // 모달 닫고 원래 위치로
    }
  }, [isOpen]);

  // ESC로 닫기
  useEffect(() => {
    const handler = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    if (isOpen) document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [isOpen, onClose]);

  if (!isOpen) return null;

  return (
    <FocusTrap>
      <div role="dialog" aria-modal="true">
        <button ref={closeBtnRef} onClick={onClose} aria-label="닫기">×</button>
        {/* ... */}
      </div>
    </FocusTrap>
  );
}

Skip Link

TSX📋 코드 (16줄)
// Tab 첫 번째 — 본문 바로가기
<a
  href="#main-content"
  className="
    sr-only focus:not-sr-only
    focus:absolute focus:top-4 focus:left-4
    focus:z-50 focus:bg-white focus:px-4 focus:py-2
  "
>
  본문 바로가기
</a>


<main id="main-content">
  {children}
</main>

키보드 네비게이션

TSX📋 코드 (36줄)
// 드롭다운 메뉴
function Menu() {
  const [activeIndex, setActiveIndex] = useState(0);
  const items = ['프로필', '설정', '로그아웃'];

  const handleKey = (e: React.KeyboardEvent) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setActiveIndex(i => Math.min(i + 1, items.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setActiveIndex(i => Math.max(i - 1, 0));
        break;
      case 'Home': setActiveIndex(0); break;
      case 'End': setActiveIndex(items.length - 1); break;
      case 'Enter': handleSelect(items[activeIndex]); break;
    }
  };

  return (
    <ul role="menu" onKeyDown={handleKey}>
      {items.map((item, i) => (
        <li
          key={item}
          role="menuitem"
          tabIndex={i === activeIndex ? 0 : -1}
          aria-current={i === activeIndex}
        >
          {item}
        </li>
      ))}
    </ul>
  );
}

색상 대비 (WCAG AA)

📋 코드 (14줄)
일반 텍스트: 4.5:1
큰 텍스트(18pt+): 3:1
UI 컴포넌트: 3:1


// 검증
import { getContrast } from 'polished';
const ratio = getContrast('#6366f1', '#ffffff');  // 4.71 ✅


// Tailwind 안전 조합
text-gray-900 + bg-white  → 통과
text-gray-500 + bg-white  → 5.85 통과
text-gray-400 + bg-white  → 3.94 ❌ (4.5 미만)

다음 챕터

CH.26 "스토리북 디자인 시스템" — 컴포넌트 카탈로그.


AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 코드의 웹 접근성 부분을 분석해서
실전 분석 + 개선 우선순위를 알려줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

웹 접근성 관련 인기 라이브러리/패턴 5개를
비교 분석해서 패턴 추출를 알려줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 프로젝트 전체에서 웹 접근성
최적화 가능 위치를 보고해줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 프론트엔드 시장의
웹 접근성 트렌드를 솔직히 알려줘.

⭐ 이것만 기억하세요
접근성(a11y): WCAG 2.2 + ARIA 이 3가지만 확실히 잡으세요
1.시맨틱 HTML 우선 — div 대신 button/nav/header 등
2.aria-* 보조 + role + focus management = 스크린리더 친화
3.키보드만으로 모든 기능 사용 가능 — Tab/화살표/ESC


공유하기
진행도 25 / 90