클라이언트 앱 접근성 가이드
작성일: 2026-04-06 Last Updated: 2026-04-06 대상: Browser Extension, Tauri Desktop, Flutter Mobile
목차
1. WCAG 2.1 AA 기준
1.1 WCAG 4대 원칙 (POUR)
| 원칙 | 설명 | 주요 지침 |
|---|---|---|
| Perceivable (인식 가능) | 정보와 UI 구성 요소가 인식 가능해야 함 | 대체 텍스트, 자막, 색상 대비 |
| Operable (조작 가능) | UI 구성 요소와 네비게이션이 조작 가능해야 함 | 키보드 접근, 충분한 시간, 발작 방지 |
| Understandable (이해 가능) | 정보와 UI 조작이 이해 가능해야 함 | 가독성, 예측 가능, 입력 도움 |
| Robust (견고함) | 다양한 보조 기술에서 해석 가능해야 함 | 표준 준수, 호환성 |
1.2 핵심 성공 기준 (AA 레벨)
| 기준 번호 | 이름 | 설명 | 적용 대상 |
|---|---|---|---|
| 1.1.1 | 비텍스트 콘텐츠 | 모든 이미지에 대체 텍스트 | 전체 |
| 1.3.1 | 정보와 관계 | 시맨틱 마크업으로 구조 전달 | 전체 |
| 1.4.3 | 대비 (최소) | 텍스트 대비 4.5:1 이상 | 전체 |
| 1.4.4 | 텍스트 크기 조절 | 200%까지 확대 가능 | 전체 |
| 1.4.11 | 비텍스트 대비 | UI 요소 대비 3:1 이상 | 전체 |
| 2.1.1 | 키보드 | 모든 기능 키보드로 접근 가능 | 전체 |
| 2.1.2 | 키보드 함정 없음 | 포커스가 갇히지 않음 | 전체 |
| 2.4.3 | 포커스 순서 | 논리적 탭 순서 | 전체 |
| 2.4.7 | 포커스 표시 | 현재 포커스 위치 시각적 표시 | 전체 |
| 3.2.1 | 포커스 시 | 포커스만으로 컨텍스트 변경 금지 | 전체 |
| 3.3.1 | 에러 식별 | 입력 에러를 텍스트로 설명 | 전체 |
| 3.3.2 | 라벨 또는 지시문 | 입력 필드에 라벨 제공 | 전체 |
| 4.1.2 | 이름, 역할, 값 | 보조 기술이 읽을 수 있는 속성 | 전체 |
1.3 준수 레벨별 목표
| 레벨 | 설명 | 프로젝트 목표 |
|---|---|---|
| A | 최소 준수 (필수) | 100% |
| AA | 권장 준수 (법적 기준) | 95% 이상 |
| AAA | 최고 준수 (선택) | 핵심 화면만 |
2. 키보드 네비게이션
2.1 기본 키보드 인터랙션
| 키 | 동작 | 비고 |
|---|---|---|
Tab | 다음 포커스 가능 요소로 이동 | 순방향 |
Shift + Tab | 이전 포커스 가능 요소로 이동 | 역방향 |
Enter | 버튼/링크 활성화 | - |
Space | 체크박스 토글, 버튼 활성화 | 스크롤과 구분 |
Escape | 모달/드롭다운 닫기 | 이전 포커스로 복원 |
Arrow Keys | 라디오 그룹, 탭, 메뉴 내 이동 | 컨테이너 내부 |
Home / End | 목록의 처음/끝으로 이동 | - |
2.2 포커스 관리 규칙
| 규칙 | 설명 | 구현 |
|---|---|---|
| 논리적 순서 | DOM 순서 = 시각적 순서 | tabindex 사용 최소화 |
| 포커스 표시기 | 모든 포커스 가능 요소에 visible focus ring | CSS outline, :focus-visible |
| 포커스 트랩 | 모달 내에서만 Tab 순환 | focus-trap 라이브러리 |
| 포커스 복원 | 모달 닫기 시 트리거 요소로 복귀 | 상태 저장/복원 |
| 스킵 링크 | 메인 콘텐츠로 바로 이동 | 첫 번째 Tab에 "본문으로 이동" |
2.3 포커스 표시기 CSS
/* 모든 포커스 가능 요소 기본 스타일 */
:focus-visible {
outline: 2px solid var(--color-focus-ring, #4F46E5);
outline-offset: 2px;
border-radius: 2px;
}
/* 마우스 클릭 시 포커스 링 숨기기 (키보드만 표시) */
:focus:not(:focus-visible) {
outline: none;
}
/* 고대비 모드 대응 */
@media (forced-colors: active) {
:focus-visible {
outline: 2px solid Highlight;
}
}
2.4 플랫폼별 키보드 지원
| 항목 | Browser Extension | Tauri | Flutter |
|---|---|---|---|
| Tab 네비게이션 | HTML 기본 | HTML 기본 (WebView) | FocusTraversalGroup |
| 포커스 트랩 | focus-trap 라이브러리 | focus-trap 라이브러리 | FocusScope |
| 글로벌 단축키 | chrome.commands API | Tauri GlobalShortcut | Shortcuts 위젯 |
| 키보드 이벤트 | addEventListener('keydown') | 동일 | RawKeyboardListener |
Browser Extension 단축키
// manifest.json
{
"commands": {
"_execute_action": {
"suggested_key": {
"default": "Ctrl+Shift+Y",
"mac": "Command+Shift+Y"
},
"description": "확장 프로그램 열기"
},
"toggle-feature": {
"suggested_key": {
"default": "Alt+Shift+F"
},
"description": "기능 토글"
}
}
}
Flutter 포커스 관리
// FocusTraversalGroup으로 탭 순서 관리
FocusTraversalGroup(
policy: OrderedTraversalPolicy(),
child: Column(
children: [
FocusTraversalOrder(
order: const NumericFocusOrder(1),
child: TextField(decoration: InputDecoration(labelText: '이름')),
),
FocusTraversalOrder(
order: const NumericFocusOrder(2),
child: TextField(decoration: InputDecoration(labelText: '이메일')),
),
FocusTraversalOrder(
order: const NumericFocusOrder(3),
child: ElevatedButton(
onPressed: () {},
child: const Text('제출'),
),
),
],
),
);