🐨CoalaCoding
Docs▾
JavaScriptReactHTML & CSSBackendAI & LLMDev ToolsCreative
B반1
👾숏츠
🙉B반2
게시판
🐨CoalaCoding

개발자를 위한 한국어 웹 기술 문서

문서

  • JavaScript
  • React
  • HTML & CSS
  • Backend
  • AI & LLM
  • Dev Tools
  • Creative

커뮤니티

  • 게시판
  • 예제 모음

기타

  • 관리자

정책

  • 소개
  • 개인정보처리방침
  • 이용약관
  • 연락처
© 2026 CoalaCoding. All rights reserved.
  • 1. aboutweb
  • 2. 개발환경설정
  • 3. 문서구조
  • 4. 문단과텍스트요소
  • 5. 링크요소
  • 6. 미디어요소
  • 7. 테이블요소
  • 8. 폼요소
  • 9. dialog
  • 10. 웹접근성
  1. 홈
  2. 문서
  3. HTML & CSS
  4. HTML
  5. 10. 웹접근성

10. 웹접근성

WCAG 2.2 의 인식·운용·이해 원칙 — 대체 텍스트, 색상 대비, 키보드 접근성, `inert`, `<dialog>` aria-modal 등 모던 패턴 포함.

1. 웹 접근성 교안

Info: 📜 기준 가이드라인

  • 국제 — WCAG 2.2 (W3C, 2023.10 권고). 4대 원칙 POUR (Perceivable / Operable / Understandable / Robust) 와 새로 추가된 9개 기준 (Focus Not Obscured, Focus Appearance, Dragging Movements, Target Size 등).
  • 한국 — KWCAG 2.2 (한국지능정보사회진흥원, 2022.12 개정). WCAG 2.1 을 기반으로 한국 환경에 맞춰 24개 검사 항목 정리.

본 교안은 인식 / 운용 / 이해 세 원칙을 중심으로 기본 패턴을 다룹니다 (네 번째 원칙 Robust 는 시맨틱 마크업·ARIA 역할이라 본 강의 다른 챕터로 분산).

1. 인식의 용이성 (Perceivability)

Info: 📜 WCAG 2.2 Principle 1: Perceivable 에 대응.

1. 대체 텍스트 (Alternative Text)

개념: 이미지나 비텍스트 콘텐츠를 볼 수 없는 사용자를 위해 텍스트 설명을 제공합니다.

1. 예제 코드


<img src="cat.jpg" alt="흰색 고양이가 햇빛 아래 낮잠을 자고 있습니다">


<img src="line.png" alt="">


<div style="background-image: url('logo.png')" 
     role="img" 
     aria-label="회사 로고">
</div>


<button aria-label="검색">
  <img src="search.png" alt="">
</button>

설명:

  • 1번: 의미있는 이미지는 내용을 설명하는 alt 제공
  • 2번: 장식만을 위한 이미지는 alt를 비워둠
  • 3번: CSS 배경 이미지도 role과 aria-label로 설명 가능
  • 4번: 아이콘 버튼은 버튼의 기능을 aria-label로 설명

2. 색상 대비 (Color Contrast)

개념: 텍스트와 배경 사이에 충분한 명도 대비를 제공하여 저시력 사용자도 내용을 읽을 수 있게 합니다.

2. 기준

  • 일반 텍스트: 최소 4.5:1 대비율
  • 큰 텍스트 (18pt 이상): 최소 3:1 대비율

3. 예제 코드


<p style="color: #000; background: #fff">
  읽기 쉬운 텍스트입니다
</p>


<p style="color: #999; background: #fff">
  읽기 어려운 텍스트입니다
</p>


<p style="color: #0056b3; background: #fff">
  충분한 대비가 있는 텍스트입니다
</p>


<h1 style="font-size: 24pt; color: #666; background: #fff">
  큰 제목 텍스트
</h1>

설명:

  • 1번: 검정과 흰색은 최고의 대비율 제공
  • 2번: 연한 회색은 대비가 부족하여 접근성 기준 미달
  • 3번: 진한 색상 사용으로 충분한 대비 확보
  • 4번: 큰 텍스트는 3:1 대비율만 필요

3. 자막 및 수화 (Captions and Sign Language)

개념: 청각 장애인을 위해 오디오 콘텐츠에 자막을 제공합니다.

4. 예제 코드


<video controls>
  
  <source src="video.mp4" type="video/mp4">
  
  
  <track kind="captions" 
         src="captions-ko.vtt" 
         srclang="ko" 
         label="한국어">
  
  
  <track kind="captions" 
         src="captions-en.vtt" 
         srclang="en" 
         label="English">
</video>


<audio controls aria-describedby="podcast-transcript">
  <source src="podcast.mp3" type="audio/mpeg">
</audio>
<details id="podcast-transcript">
  <summary>전체 대본 보기</summary>
  <p>여기에 오디오의 전체 대본을 텍스트로 제공합니다…</p>
</details>

설명:

  • 1번: video 태그에 controls 속성으로 재생 컨트롤 표시
  • 2번: source로 비디오 파일과 MIME 타입 지정
  • 3번: track으로 자막 파일 연결 (kind="captions")
  • 4번: 여러 언어 자막 제공 가능
  • 5번: <audio>는 사양상 <track> 자막을 받지 않습니다. 오디오 콘텐츠의 자막/대본은 별도 transcript(텍스트 대본) 로 제공하고 aria-describedby 로 연결하는 것이 표준.

4. 콘텐츠 구조화 (Content Structure)

개념: 올바른 HTML 구조로 콘텐츠의 위계와 의미를 명확하게 전달합니다.

5. 예제 코드


<h1>웹 접근성 가이드</h1>


<h2>인식의 용이성</h2>


<h3>대체 텍스트</h3>

<p>이미지에 대한 설명입니다.</p>


<h3>색상 대비</h3>

<p>색상 대비에 대한 설명입니다.</p>


<h2>운용의 용이성</h2>


<ul>
  <li>첫 번째 항목</li>
  <li>두 번째 항목</li>
</ul>


<ol>
  <li>로그인하기</li>
  <li>상품 선택하기</li>
  <li>결제하기</li>
</ol>

설명:

  • 1번: 페이지당 하나의 h1으로 메인 제목 표시
  • 2번: h1 다음에 h2로 하위 섹션 시작
  • 3번: 제목 레벨을 순서대로 사용 (건너뛰지 않음)
  • 4번: 같은 중요도의 내용은 같은 제목 레벨 사용
  • 5번: 새로운 주요 섹션은 h2로 시작
  • 6번: 순서가 없는 목록은 ul 사용
  • 7번: 순서가 중요한 목록은 ol 사용

2. 운용의 용이성 (Operability)

Info: 📜 WCAG 2.2 Principle 2: Operable 에 대응.

5. 키보드 접근성 (Keyboard Accessibility)

개념: 마우스 없이 키보드만으로 모든 기능을 사용할 수 있어야 합니다.

6. 예제 코드


<button onclick="save()">저장</button>


<div onclick="save()">저장</div>


<div tabindex="0" 
     role="button" 
     onclick="save()" 
     onkeypress="if(event.key==='Enter') save()">
  저장
</div>


<a href="page.html">다음 페이지</a>


<input type="text" placeholder="이름 입력">
<select>
  <option>옵션 1</option>
  <option>옵션 2</option>
</select>


<input tabindex="1" type="text">
<input tabindex="2" type="text">


<div tabindex="-1" id="msg">알림 메시지</div>


<div role="dialog" aria-modal="true">
  <h2>알림</h2>
  <p>내용입니다</p>
  <button>확인</button>
</div>

설명:

  • 1번: button은 Tab, Enter, Space 키로 자동 작동
  • 2번: div는 기본적으로 포커스 불가능
  • 3번: tabindex="0"으로 포커스 가능하게 만듦
  • 4번: a 태그는 Tab으로 이동, Enter로 클릭
  • 5번: 모든 input, select 등은 키보드 접근 가능
  • 6번: tabindex 양수는 탭 순서를 복잡하게 만들어 피해야 함
  • 7번: tabindex="-1"은 JS로만 포커스 가능
  • 8번: 모달에서는 포커스가 모달 내부에만 머물러야 함

6. 충분한 시간 제공 (Enough Time)

개념: 사용자가 콘텐츠를 읽고 사용할 충분한 시간을 제공합니다.

7. 예제 코드


<div id="slide">
  <img src="slide1.jpg" alt="첫 번째 슬라이드">
  
  <button onclick="pause()">일시정지</button>
  <button onclick="play()">재생</button>
</div>

<script>
// 3. 자동 슬라이드 변수
let timer;
let paused = false;

// 4. 슬라이드 자동 전환 함수
function autoSlide() {
  // 5. 일시정지 상태가 아닐 때만 실행
  if (!paused) {
    // 슬라이드 전환 코드
  }
  // 6. 5초마다 실행 (충분한 시간 제공)
  timer = setTimeout(autoSlide, 5000);
}

// 7. 일시정지 함수
function pause() {
  paused = true;
  clearTimeout(timer);
}

// 8. 재생 함수
function play() {
  paused = false;
  autoSlide();
}
</script>


<div id="warn" style="display:none">
  
  <p>5분 후 자동 로그아웃됩니다.</p>
  
  <button onclick="extend()">시간 연장</button>
</div>

<script>
// 12. 타임아웃 전 경고 표시
setTimeout(function() {
  document.getElementById('warn').style.display = 'block';
}, 25 * 60 * 1000); // 25분 후 경고
</script>

설명:

  • 1번: 자동 슬라이드를 포함한 div 영역
  • 2번: 사용자가 슬라이드를 제어할 수 있는 버튼
  • 3번: 타이머와 일시정지 상태를 저장하는 변수
  • 4번: 슬라이드를 자동으로 전환하는 함수
  • 5번: 일시정지 중이 아닐 때만 슬라이드 전환
  • 6번: 5초 간격으로 충분한 읽기 시간 제공
  • 7번: 사용자가 일시정지 버튼을 누르면 타이머 중지
  • 8번: 재생 버튼으로 다시 자동 전환 시작
  • 9번: 세션 만료 경고를 위한 숨겨진 div
  • 10번: 남은 시간을 알려주는 메시지
  • 11번: 세션을 연장할 수 있는 버튼
  • 12번: 타임아웃 5분 전에 경고 표시

7. 발작 예방 (Seizure Prevention)

개념: 깜빡이거나 번쩍이는 콘텐츠로 인한 발작을 예방합니다.

8. 예제 코드


<div style="animation: blink 0.3s infinite">
  깜빡임
</div>

<style>
/* 2. 초당 3회 이상 깜빡임은 위험 */
@keyframes blink {
  0% { opacity: 1; }
  50% { opacity: 0; }
  100% { opacity: 1; }
}
</style>


<button onclick="stop()">애니메이션 중지</button>

<div id="anim">
  움직이는 콘텐츠
</div>

<script>
// 4. 애니메이션 중지 함수
function stop() {
  // 5. CSS 애니메이션 제거
  document.getElementById('anim').style.animation = 'none';
}
</script>


<style>
/* 7. 기본 애니메이션 */
.box {
  transition: transform 0.3s;
}

/* 8. 사용자가 애니메이션 줄이기를 선택한 경우 */
@media (prefers-reduced-motion: reduce) {
  .box {
    /* 9. 모든 애니메이션과 전환 효과 제거 */
    transition: none;
    animation: none;
  }
}
</style>

설명:

  • 1번: 0.3초마다 깜빡이는 것은 발작을 유발할 수 있음
  • 2번: 초당 3회 이상의 깜빡임은 접근성 위반
  • 3번: 사용자가 애니메이션을 멈출 수 있는 버튼 제공
  • 4번: 버튼 클릭 시 애니메이션 중지하는 함수
  • 5번: CSS의 animation 속성을 none으로 설정
  • 6번: 미디어 쿼리로 사용자 선호도 확인
  • 7번: 일반 사용자를 위한 기본 애니메이션
  • 8번: 애니메이션 줄이기 설정을 한 사용자 감지
  • 9번: 해당 사용자에게는 모든 움직임 제거

8. 네비게이션 (Navigation)

개념: 사용자가 콘텐츠를 쉽게 탐색할 수 있도록 명확한 네비게이션을 제공합니다.

9. 예제 코드


<a href="#main" class="skip">본문 바로가기</a>


<nav aria-label="주 메뉴">
  
  <ul>
    <li><a href="/">홈</a></li>
    <li><a href="/about">소개</a></li>
    <li><a href="/contact">연락처</a></li>
  </ul>
</nav>


<nav aria-label="주 메뉴">
  <ul>
    <li><a href="/">홈</a></li>
    
    <li><a href="/about" aria-current="page">소개</a></li>
    <li><a href="/contact">연락처</a></li>
  </ul>
</nav>


<nav aria-label="빵부스러기">
  
  <ol>
    <li><a href="/">홈</a></li>
    <li><a href="/products">상품</a></li>
    
    <li aria-current="page">노트북</li>
  </ol>
</nav>


<main id="main">
  <h1>페이지 제목</h1>
  <p>본문 내용입니다.</p>
</main>


<nav aria-label="목차">
  <ul>
    
    <li><a href="#sec1">섹션 1</a></li>
    <li><a href="#sec2">섹션 2</a></li>
    <li><a href="#sec3">섹션 3</a></li>
  </ul>
</nav>


<section id="sec1">
  <h2>섹션 1</h2>
</section>

<section id="sec2">
  <h2>섹션 2</h2>
</section>

설명:

  • 1번: 페이지 최상단에 본문으로 바로 가는 링크 제공
  • 2번: nav 태그와 aria-label로 네비게이션 영역 명확히 구분
  • 3번: 메뉴는 ul, li로 구조화하여 개수 파악 용이
  • 4번: 네비게이션 영역 정의
  • 5번: aria-current="page"로 현재 페이지 표시
  • 6번: 빵부스러기는 사용자의 현재 위치 표시
  • 7번: 순서가 중요하므로 ol 사용
  • 8번: 현재 위치는 링크가 아닌 텍스트로 표시
  • 9번: main 태그로 주요 콘텐츠 영역 표시
  • 10번: 페이지 내 섹션으로 이동하는 목차
  • 11번: href="#id"로 같은 페이지 내 이동
  • 12번: 각 섹션에 고유한 id 값 부여

3. 이해의 용이성 (Understandability)

Info: 📜 WCAG 2.2 Principle 3: Understandable 에 대응.

9. 읽기 쉬운 텍스트 (Readable Text)

개념: 명확하고 이해하기 쉬운 언어를 사용합니다.

10. 예제 코드


<html lang="ko">


<p>
  
  안녕하세요. 
  
  <span lang="en">Hello</span>입니다.
</p>


<p>
  
  <abbr title="하이퍼텍스트 마크업 언어">HTML</abbr>은 
  웹 페이지를 만드는 언어입니다.
</p>


<p>
  
  <dfn title="웹 페이지를 모두가 사용할 수 있게 만드는 것">
    웹 접근성
  </dfn>은 중요합니다.
</p>


<ruby>
  
  漢字
  
  <rt>한자</rt>
</ruby>

설명:

  • 1번: html 태그에 lang 속성으로 페이지 언어 지정
  • 2번: 문장 안에 다른 언어가 섞여 있는 경우
  • 3번: 기본 언어는 한국어로 설정됨
  • 4번: 영어 부분에만 lang="en" 추가
  • 5번: 약어는 의미를 모를 수 있음
  • 6번: abbr 태그의 title로 전체 명칭 제공
  • 7번: 어려운 용어에 설명 필요
  • 8번: dfn 태그의 title로 용어 정의
  • 9번: 한자나 어려운 글자에 읽는 법 표시
  • 10번: 원래 글자 (한자)
  • 11번: rt 태그로 읽는 방법 (한글) 표시

10. 예측 가능성 (Predictability)

개념: 웹 페이지가 예측 가능한 방식으로 작동해야 합니다.

11. 예제 코드


<input type="text" 
       onfocus="openPopup()">


<input type="text" id="inp">
<button onclick="openPopup()">도움말 보기</button>


<select onchange="location.href=this.value">
  <option value="page1.html">페이지 1</option>
  <option value="page2.html">페이지 2</option>
</select>


<select id="sel">
  <option value="page1.html">페이지 1</option>
  <option value="page2.html">페이지 2</option>
</select>

<button onclick="go()">이동</button>

<script>
// 6. 사용자가 버튼을 눌러야 이동
function go() {
  const sel = document.getElementById('sel');
  location.href = sel.value;
}
</script>


<a href="page.html" 
   target="_blank">
  
  외부 사이트 (새 창)
</a>


<a href="page.html" 
   target="_blank"
   aria-label="외부 사이트, 새 창에서 열림">
  외부 사이트
</a>

설명:

  • 1번: 포커스만으로 팝업이 열리면 예측 불가
  • 2번: 별도 버튼으로 사용자가 의도적으로 실행
  • 3번: select 변경만으로 페이지 이동은 혼란스러움
  • 4번: select는 선택만 함
  • 5번: 이동 버튼을 따로 제공하여 명확한 의도 표현
  • 6번: 버튼 클릭 시에만 페이지 이동 실행
  • 7번: 새 창으로 열릴 때 텍스트로 명시
  • 8번: 괄호 안에 "새 창" 표시
  • 9번: 또는 aria-label로 스크린리더 사용자에게 알림

11. 입력 지원 (Input Assistance)

개념: 사용자가 오류를 방지하고 수정할 수 있도록 도와줍니다.

12. 예제 코드


<form>
  
  <label for="name">이름</label>
  <input type="text" id="name" required>

  
  <label for="email">
    이메일 
    
    <span aria-label="필수">*</span>
  </label>
  
  <input type="email" 
         id="email" 
         placeholder="example@email.com"
         required
         aria-describedby="tip">
  
  <small id="tip">이메일 형식으로 입력해주세요</small>

  
  <div id="err" 
       role="alert" 
       style="display:none; color:red">
  </div>

  <button type="submit">제출</button>
</form>

<script>
// 8. 폼 제출 시 유효성 검사
document.querySelector('form').addEventListener('submit', function(e) {
  // 9. 기본 제출 동작 막기
  e.preventDefault();
  
  const name = document.getElementById('name').value;
  const email = document.getElementById('email').value;
  const err = document.getElementById('err');
  
  // 10. 이름이 비어있는지 확인
  if (!name) {
    // 11. 오류 메시지 표시
    err.textContent = '이름을 입력해주세요';
    err.style.display = 'block';
    // 12. 해당 필드로 포커스 이동
    document.getElementById('name').focus();
    return;
  }
  
  // 13. 이메일 형식 확인
  if (!email.includes('@')) {
    err.textContent = '올바른 이메일 형식이 아닙니다';
    err.style.display = 'block';
    document.getElementById('email').focus();
    return;
  }
  
  // 14. 모두 정상이면 제출
  alert('제출 완료');
});
</script>


<label for="pw">비밀번호</label>
<input type="password" 
       id="pw" 
       aria-describedby="pwrule">

<ul id="pwrule">
  <li>8자 이상</li>
  <li>영문, 숫자 포함</li>
</ul>

설명:

  • 1번: 폼 요소들을 form 태그로 감싸기
  • 2번: label의 for와 input의 id를 동일하게 연결
  • 3번: label 안에 필수 표시 포함
  • 4번: 별표(*)로 필수 필드 표시, aria-label로 의미 전달
  • 5번: placeholder로 입력 예시 표시
  • 6번: aria-describedby로 연결된 설명 텍스트
  • 7번: role="alert"로 오류 메시지 영역 지정
  • 8번: submit 이벤트로 유효성 검사 실행
  • 9번: preventDefault로 바로 제출되지 않게 함
  • 10번: 입력값이 비어있는지 확인
  • 11번: 오류 메시지를 사용자에게 표시
  • 12번: 오류가 있는 필드로 포커스 이동
  • 13번: 이메일에 @가 있는지 간단히 확인
  • 14번: 모든 검사 통과 시 실제 제출 진행
  • 15번: 비밀번호 필드
  • 16번: 비밀번호 규칙을 미리 안내

12. 오류 식별 및 제안 (Error Identification)

개념: 오류를 명확하게 표시하고 수정 방법을 제안합니다.

13. 예제 코드

<form id="frm">
  
  <div>
    <label for="user">사용자명</label>
    
    <input type="text" 
           id="user" 
           aria-invalid="false"
           aria-describedby="user-err">
    
    <span id="user-err" 
          role="alert" 
          style="display:none; color:red">
    </span>
  </div>

  <div>
    <label for="age">나이</label>
    <input type="number" 
           id="age" 
           aria-invalid="false"
           aria-describedby="age-err">
    <span id="age-err" 
          role="alert" 
          style="display:none; color:red">
    </span>
  </div>

  <button type="submit">제출</button>
</form>

<script>
// 4. 폼 제출 이벤트 처리
document.getElementById('frm').addEventListener('submit', function(e) {
  // 5. 기본 제출 막기
  e.preventDefault();
  
  // 6. 오류 여부 추적
  let hasError = false;
  
  // 7. 사용자명 검증
  const user = document.getElementById('user');
  const userErr = document.getElementById('user-err');
  
  // 8. 빈 값 체크
  if (!user.value.trim()) {
    // 9. aria-invalid를 true로 변경
    user.setAttribute('aria-invalid', 'true');
    // 10. 오류 메시지 표시
    userErr.textContent = '사용자명을 입력해주세요';
    userErr.style.display = 'block';
    hasError = true;
  } else {
    // 11. 정상이면 aria-invalid를 false로
    user.setAttribute('aria-invalid', 'false');
    userErr.style.display = 'none';
  }
  
  // 12. 나이 검증
  const age = document.getElementById('age');
  const ageErr = document.getElementById('age-err');
  
  // 13. 나이 범위 체크
  if (age.value < 1 || age.value > 120) {
    age.setAttribute('aria-invalid', 'true');
    // 14. 구체적인 수정 방법 제시
    ageErr.textContent = '나이는 1~120 사이로 입력해주세요';
    ageErr.style.display = 'block';
    hasError = true;
  } else {
    age.setAttribute('aria-invalid', 'false');
    ageErr.style.display = 'none';
  }
  
  // 15. 오류가 없으면 제출
  if (!hasError) {
    alert('제출 완료');
  } else {
    // 16. 오류가 있으면 첫 오류 필드로 포커스
    if (user.getAttribute('aria-invalid') === 'true') {
      user.focus();
    } else {
      age.focus();
    }
  }
});
</script>

설명:

  • 1번: 각 필드에 고유한 id를 부여하여 구분
  • 2번: aria-invalid로 현재 입력값의 오류 여부 표시
  • 3번: role="alert"로 오류 메시지가 즉시 읽히도록 함
  • 4번: 폼 제출 시 검증 로직 실행
  • 5번: 검증 전에 제출되지 않도록 preventDefault
  • 6번: 오류 발생 여부를 추적하는 변수
  • 7번: 사용자명 필드와 오류 메시지 요소 가져오기
  • 8번: 입력값이 비어있는지 확인 (공백 제거 후)
  • 9번: 오류가 있으면 aria-invalid를 true로 설정
  • 10번: 화면에 오류 메시지 표시
  • 11번: 정상이면 aria-invalid를 false로 돌림
  • 12번: 나이 필드 검증 시작
  • 13번: 나이가 유효한 범위인지 확인
  • 14번: 어떻게 수정해야 하는지 구체적으로 안내
  • 15번: 모든 필드가 정상이면 제출 진행
  • 16번: 오류가 있으면 첫 번째 오류 필드로 포커스 이동

4. 요약

웹 접근성의 세 가지 핵심 원칙:

  1. 인식의 용이성: 모든 사용자가 콘텐츠를 인식할 수 있어야 합니다

    • 대체 텍스트 제공
    • 충분한 색상 대비
    • 자막 제공
    • 명확한 구조
  2. 운용의 용이성: 모든 사용자가 인터페이스를 사용할 수 있어야 합니다

    • 키보드 접근성
    • 충분한 시간 제공
    • 발작 예방
    • 명확한 네비게이션
  3. 이해의 용이성: 콘텐츠와 인터페이스가 이해하기 쉬워야 합니다

    • 읽기 쉬운 텍스트
    • 예측 가능한 동작
    • 입력 지원
    • 오류 식별 및 제안

5. ▪ 2026 보완: WCAG 2.2 신규 + 모던 패턴

13. WCAG 2.2 신규 9개 기준 (2023.10 W3C 권고)

Info: 📜 WCAG 2.1 → 2.2 에서 추가 된 9개 기준. 기존 2.1 기준은 모두 유지되며 추가 된 항목들이다.

번호기준핵심 요구사항
2.4.11Focus Not Obscured (Min)포커스 받은 요소가 다른 콘텐츠(고정 헤더·쿠키 배너) 에 완전히 가려져선 안 됨
2.4.12Focus Not Obscured (Enhanced)포커스 요소가 전혀 가려져선 안 됨 (강화판)
2.4.13Focus Appearance포커스 표시는 충분한 크기·대비를 가져야 함
2.5.7Dragging Movements드래그로만 가능한 동작은 단일 포인터 대안 (탭·클릭) 도 제공
2.5.8Target Size (Min) — 24×24 CSS px클릭 가능 요소의 터치 영역 은 최소 24×24 CSS 픽셀
3.2.6Consistent Help도움말 링크·연락처 는 모든 페이지에서 같은 위치 에
3.3.7Redundant Entry같은 정보를 다시 입력하라고 강요하지 않음 (자동 채움 또는 선택)
3.3.8Accessible Authentication (Min)인지 기능 테스트 (퍼즐·암호 외움) 가 유일한 인증 수단이면 안 됨
3.3.9Accessible Authentication (Enhanced)객체 인식·개인 콘텐츠 테스트도 유일 하면 안 됨

Target Size 예시 — 24×24 CSS px 확보

<button class="icon-btn">
  <span aria-hidden="true">🗑</span>
  <span class="sr-only">삭제</span>
</button>
.icon-btn {

  min-width: 24px;
  min-height: 24px;

  padding: 8px;
}

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

Info: 💡 간격 예외 — 작은 아이콘이라도 주변에 24×24 만큼의 여백 이 있어 인접 타겟과 겹치지 않으면 통과. 모바일 권장은 44×44 (Apple HIG·Material).


14. inert 속성 — 모달 바깥 비활성화

Info: 👁️‍🗨️ 요소와 그 자손 전체 를 "사용자가 만질 수 없는 상태" 로 만든다. 포커스 차단 + 클릭 차단 + 보조 기술이 없는 것처럼 처리.


<main id="page" inert>
  <h1>본문</h1>
  <button>저장</button>
  <a href="#">링크</a>
</main>


<dialog id="alert" open>
  <p>정말 삭제하시겠습니까?</p>
  <button>확인</button>
  <button>취소</button>
</dialog>

자바스크립트로 모달을 열 때 main.inert = true / 닫을 때 false 만 토글하면 수동 포커스 트랩 코드가 사라진다.

Info: 💡 <dialog> 의 showModal() 은 나머지 페이지를 자동으로 inert 처리 한다. 직접 만든 모달(role="dialog" div) 일 때 inert 가 진짜 빛난다.

const dialog = document.getElementById('alert');
const main = document.getElementById('page');

function openAlert() {
  main.inert = true;
  dialog.show();
}
function closeAlert() {
  dialog.close();
  main.inert = false;
}
비교inertaria-hidden="true"tabindex="-1"
포커스 차단✓✗✓ (자기 자신만)
클릭 차단✓✗✗
보조 기술 차단✓✓✗
자손까지 적용✓✓✗

15. <dialog> 와 aria-modal

본문 2.1 키보드 접근성 의 마지막 예제는 수동 모달(<div role="dialog" aria-modal="true">) 패턴이다. 모던 권장은 <dialog> 요소 + showModal() — 9 챕터 참고.

<dialog id="confirm">
  <h2>알림</h2>
  <p>저장하시겠습니까?</p>
  <form method="dialog">
    <button value="ok">확인</button>
    <button value="cancel">취소</button>
  </form>
</dialog>

showModal() 이 다음을 자동 처리:

  • 페이지 나머지 영역 inert 처리
  • 포커스를 dialog 내부 첫 포커스 가능 요소로 이동
  • ESC 키로 닫기 (cancel 이벤트 발생)
  • ::backdrop 으로 배경 표시

<form method="dialog"> 의 버튼이 값을 가지고 dialog 를 닫는다 — 결과는 dialog.returnValue 로 회수.

document.getElementById('confirm').showModal();
document.getElementById('confirm').addEventListener('close', e => {
  console.log('결과:', e.target.returnValue);  // "ok" 또는 "cancel"
});

목차

  • 1. 인식의 용이성 (Perceivability)
  • 1. 대체 텍스트 (Alternative Text)
  • 2. 색상 대비 (Color Contrast)
  • 3. 자막 및 수화 (Captions and Sign Language)
  • 4. 콘텐츠 구조화 (Content Structure)
  • 2. 운용의 용이성 (Operability)
  • 5. 키보드 접근성 (Keyboard Accessibility)
  • 6. 충분한 시간 제공 (Enough Time)
  • 7. 발작 예방 (Seizure Prevention)
  • 8. 네비게이션 (Navigation)
  • 3. 이해의 용이성 (Understandability)
  • 9. 읽기 쉬운 텍스트 (Readable Text)
  • 10. 예측 가능성 (Predictability)
  • 11. 입력 지원 (Input Assistance)
  • 12. 오류 식별 및 제안 (Error Identification)
  • 4. 요약
  • 5. ▪ 2026 보완: WCAG 2.2 신규 + 모던 패턴
  • 13. WCAG 2.2 신규 9개 기준 (2023.10 W3C 권고)
  • 14. `inert` 속성 — 모달 바깥 비활성화
  • 15. `<dialog>` 와 `aria-modal`