a11y

star 13

웹 접근성 체크 및 개선 가이드를 실행합니다.

excatt By excatt schedule Updated 4/8/2026

name: "a11y" description: "웹 접근성 체크 및 개선 가이드를 실행합니다." user-invocable: true

A11y (Accessibility) Skill

웹 접근성 체크 및 개선 가이드를 실행합니다.

WCAG 2.1 원칙

P - Perceivable    인식 가능
O - Operable       조작 가능
U - Understandable 이해 가능
R - Robust         견고함

체크리스트

1. 인식 가능 (Perceivable)

이미지 대체 텍스트

<!-- ✅ Good -->
<img src="logo.png" alt="회사 로고">
<img src="chart.png" alt="2024년 매출 추이: 1분기 100억, 2분기 120억...">

<!-- 장식용 이미지 -->
<img src="decoration.png" alt="" role="presentation">

<!-- ❌ Bad -->
<img src="logo.png">
<img src="chart.png" alt="차트">

색상 대비

텍스트: 4.5:1 이상 (일반), 3:1 이상 (큰 텍스트)
UI 컴포넌트: 3:1 이상

도구: WebAIM Contrast Checker

색상만으로 정보 전달 금지

<!-- ❌ Bad: 색상만으로 에러 표시 -->
<input style="border-color: red">

<!-- ✅ Good: 아이콘 + 텍스트 + 색상 -->
<input aria-invalid="true">
<span class="error">⚠️ 이메일 형식이 올바르지 않습니다</span>

2. 조작 가능 (Operable)

키보드 접근성

<!-- 모든 인터랙티브 요소는 키보드로 접근 가능해야 함 -->

<!-- ✅ Good -->
<button onclick="handleClick()">클릭</button>
<a href="/page">링크</a>

<!-- ❌ Bad -->
<div onclick="handleClick()">클릭</div>
<span onclick="navigate()">링크</span>

<!-- 커스텀 요소에 키보드 지원 추가 -->
<div
  role="button"
  tabindex="0"
  onclick="handleClick()"
  onkeydown="if(event.key === 'Enter') handleClick()"
>
  버튼
</div>

포커스 관리

/* 포커스 표시 유지 */
:focus {
  outline: 2px solid #007bff;
  outline-offset: 2px;
}

/* ❌ Bad: 포커스 표시 제거 */
:focus { outline: none; }

건너뛰기 링크

<body>
  <a href="#main-content" class="skip-link">
    본문으로 바로가기
  </a>
  <nav>...</nav>
  <main id="main-content">...</main>
</body>

<style>
.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 0;
}
</style>

3. 이해 가능 (Understandable)

폼 레이블

<!-- ✅ Good -->
<label for="email">이메일</label>
<input id="email" type="email" required>

<!-- 또는 -->
<label>
  이메일
  <input type="email" required>
</label>

<!-- aria-label 사용 -->
<input type="search" aria-label="사이트 검색">

에러 메시지

<label for="email">이메일</label>
<input
  id="email"
  type="email"
  aria-describedby="email-error"
  aria-invalid="true"
>
<span id="email-error" role="alert">
  유효한 이메일 주소를 입력해주세요
</span>

4. 견고함 (Robust)

시맨틱 HTML

<!-- ✅ Good: 시맨틱 태그 사용 -->
<header>...</header>
<nav>...</nav>
<main>
  <article>
    <h1>제목</h1>
    <section>...</section>
  </article>
</main>
<footer>...</footer>

<!-- ❌ Bad: div 남용 -->
<div class="header">...</div>
<div class="nav">...</div>

ARIA 속성

<!-- 랜드마크 -->
<div role="navigation" aria-label="주 메뉴">...</div>
<div role="main">...</div>
<div role="search">...</div>

<!-- 상태 전달 -->
<button aria-expanded="false" aria-controls="menu">메뉴</button>
<ul id="menu" aria-hidden="true">...</ul>

<!-- 라이브 영역 -->
<div aria-live="polite">업데이트된 내용이 여기 표시됩니다</div>
<div aria-live="assertive">긴급 알림!</div>

컴포넌트별 가이드

모달

<div
  role="dialog"
  aria-modal="true"
  aria-labelledby="modal-title"
>
  <h2 id="modal-title">확인</h2>
  <p>정말 삭제하시겠습니까?</p>
  <button>취소</button>
  <button>확인</button>
</div>
// 포커스 트랩
function trapFocus(element) {
  const focusables = element.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusables[0];
  const last = focusables[focusables.length - 1];

  element.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();
      }
    }
    if (e.key === 'Escape') closeModal();
  });
}

<div role="tablist" aria-label="프로필 탭">
  <button
    role="tab"
    aria-selected="true"
    aria-controls="panel-1"
    id="tab-1"
  >
    기본 정보
  </button>
  <button
    role="tab"
    aria-selected="false"
    aria-controls="panel-2"
    id="tab-2"
    tabindex="-1"
  >
    보안 설정
  </button>
</div>
<div
  role="tabpanel"
  id="panel-1"
  aria-labelledby="tab-1"
>
  기본 정보 내용
</div>

드롭다운

<div class="dropdown">
  <button
    aria-haspopup="listbox"
    aria-expanded="false"
    aria-controls="dropdown-list"
  >
    선택하세요
  </button>
  <ul
    id="dropdown-list"
    role="listbox"
    aria-label="옵션"
    hidden
  >
    <li role="option" aria-selected="false">옵션 1</li>
    <li role="option" aria-selected="false">옵션 2</li>
  </ul>
</div>

테스트 도구

자동화

# axe-core
npm install axe-core

# pa11y
npm install pa11y
pa11y https://example.com

# Lighthouse
# Chrome DevTools > Lighthouse > Accessibility

수동 테스트

1. 키보드만으로 모든 기능 사용 가능?
2. 스크린 리더로 내용 이해 가능?
3. 200% 확대해도 사용 가능?
4. 색상 제거해도 정보 전달 가능?

출력 형식

## Accessibility Audit

### Summary
- 전체 점수: XX/100
- Critical: N개
- Major: N개
- Minor: N개

### Issues

#### Critical
| 요소 | 문제 | WCAG | 해결책 |
|------|------|------|--------|
| `<img>` | alt 없음 | 1.1.1 | alt 추가 |

#### Recommendations
```html
<!-- Before -->
<div onclick="...">클릭</div>

<!-- After -->
<button onclick="...">클릭</button>

Testing Checklist

  • 키보드 네비게이션
  • 스크린 리더 테스트
  • 색상 대비 검사
  • 포커스 표시 확인

---

요청에 맞는 접근성 검토를 수행하세요.
Install via CLI
npx skills add https://github.com/excatt/superclaude-plusplus --skill a11y
Repository Details
star Stars 13
call_split Forks 2
navigation Branch main
article Path SKILL.md
More from Creator