웹 접근성 검사·수정 도우미 WCAG 2.1 진단 · 수정 코드 · 작업 지시서
← 접근성 아티클 목록

실습: 17점짜리 페이지를 100점으로 고쳐 보기

실습 · 검사 결과와 수정 코드 전체 공개 · 이 사이트의 검사 엔진으로 직접 측정 · 2026년 9월

접근성 글을 여러 편 읽어도 "그래서 내 페이지에는 어떻게 적용하지?"가 막막할 수 있습니다. 이 글은 일부러 결함을 심은 작은 쇼핑몰 페이지(가상의 예시입니다)를 이 사이트의 검사 엔진에 실제로 돌려 나온 결과를 그대로 싣고, 문제를 하나씩 고쳐 점수가 올라가는 과정을 따라갑니다. 수정 코드는 내 사이트에 그대로 옮겨 쓸 수 있는 패턴으로 골랐고, 각 수정의 배경 원리는 관련 아티클로 연결해 두었습니다.

17점 → 100점수정 전 → 수정 후 (100점 만점, 이 도구 자체 기준)
19건 → 0건치명적 6 · 높음 5 · 보통 7 · 낮음 1
17종걸린 검사 규칙의 종류(같은 규칙이 여러 번 걸린 경우 포함하면 19건)

1. 수정 전 페이지

상품 배너, 알림 신청 폼, 구매 버튼, 재고 표가 있는 단순한 페이지입니다. 겉으로는 평범해 보입니다.

<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<style>
  body { background: #ffffff; color: #333333; font-size: 16px; }
  .sub { color: #aaaaaa; font-size: 14px; }
  .btn { background: #f4b400; color: #ffffff; font-size: 16px; }
  a:focus, button:focus { outline: none; }
</style>
</head>
<body>
<div class="top">
  <img src="/logo.png">
  <a href="/cart"><svg width="20" height="20"><path d="M0 0h20v20z"/></svg></a>
</div>
<h3>오늘의 특가</h3>
<img src="/banner.jpg" alt="image">
<p class="sub">배송은 평일 오후 2시 이전 주문 건까지 당일 출고됩니다.</p>
<form>
  <input type="text" name="email" placeholder="이메일">
  <input type="text" name="tel" placeholder="연락처">
  <button class="btn"><img src="/arrow.png" alt=""></button>
</form>
<div class="buy" onclick="buy()">바로 구매</div>
<a href="#" >더보기</a>
<div id="menu" tabindex="3">메뉴</div>
<div id="menu">중복</div>
<table><tr><td>사이즈</td><td>재고</td></tr><tr><td>M</td><td>3</td></tr></table>
</body>
</html>

2. 검사 결과: 17점, 19건

검사 엔진이 반환한 결과를 심각도 순으로 정리하면 다음과 같습니다. (줄 번호는 위 코드 기준)

심각도규칙위치무슨 문제인가
치명적html-lang-missing1행 html문서 언어가 없어 한국어를 영어 음성으로 읽을 수 있음
치명적title-missing2행 head탭·낭독기가 읽을 페이지 제목이 없음
치명적img-alt-missing13행 로고 이미지alt 속성 자체가 없어 파일명이 읽힘
치명적link-no-name14행 장바구니 아이콘 링크아이콘만 있는 링크라 이름이 없음
치명적button-no-name22행 화살표 버튼장식 이미지(alt="")만 있어 이름이 없음
치명적click-not-focusable24행 "바로 구매"div onclick: 탭으로 접근 불가, Enter로 실행 불가
높음contrast-low18행 안내 문구#aaaaaa / #ffffff = 2.32:1 (기준 4.5:1)
높음focus-outline-removed ×2CSS a:focus, button:focus포커스 테두리를 지워 위치를 알 수 없음
높음positive-tabindex26행 메뉴tabindex="3"으로 탭 순서가 뒤엉킴
높음viewport-no-zoom3행 meta viewport확대 차단(user-scalable=no)
보통duplicate-id27행id="menu" 중복
보통form-placeholder-only ×220·21행 입력창placeholder만으로 레이블 대신
보통heading-none본문h1이 없음 (h3만 존재)
보통img-alt-suspicious17행 배너alt가 "image"라 내용 설명이 아님
보통link-vague-text25행"더보기"만으로는 목적지를 알 수 없음
보통table-no-header28행 표th 없는 표
낮음landmark-missing본문main 영역 표시 없음

분야별로 보면 구조·탐색 54점, 키보드 조작 56점, 버튼·링크 이름 60점이 특히 낮았고, 색상 대비(91점)와 입력창(91점)은 문제 수가 적어 상대적으로 높았습니다. 점수는 문제 개수보다 심각도에 민감합니다. 치명적 문제 6건만으로 이미 48점이 깎입니다(치명적 1건당 8점, 이 도구 기준).

3. 고치는 순서: 치명적 → 높음 → 보통 → 낮음

한꺼번에 다 고치려 하지 말고 영향이 큰 것부터 처리합니다. 특히 <head>의 세 줄은 한 번에 끝나고 효과가 페이지 전체에 미칩니다.

3-1. 문서 기본 정보 (치명적 2 + 높음 1) — 3줄

<!DOCTYPE html>
<html lang="ko">                                              ← 언어
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">   ← 확대 허용
<title>오늘의 특가 - 예시 쇼핑몰</title>                        ← 페이지 제목

3-2. 이름 없는 이미지·링크·버튼 (치명적 3)

<!-- 전 -->
<img src="/logo.png">
<a href="/cart"><svg width="20" height="20">…</svg></a>
<button class="btn"><img src="/arrow.png" alt=""></button>

<!-- 후 -->
<img src="/logo.png" alt="예시 쇼핑몰 홈">
<a href="/cart" aria-label="장바구니"><svg width="20" height="20" aria-hidden="true">…</svg></a>
<button class="btn"><img src="/arrow.png" alt="">알림 신청</button>

세 곳 모두 "이름이 없다"는 같은 병입니다. 이미지는 alt로, 아이콘 링크는 aria-label로, 버튼은 눈에 보이는 텍스트("알림 신청")로 이름을 붙였습니다. 버튼의 화살표 이미지는 장식이므로 alt=""를 유지해 중복 낭독을 피했습니다. (원리는 대체 텍스트 가이드ARIA 가이드 참고)

3-3. 키보드로 못 누르는 "바로 구매" (치명적 1)

<!-- 전 -->
<div class="buy" onclick="buy()">바로 구매</div>

<!-- 후 -->
<button type="button" class="buy" onclick="buy()">바로 구매</button>

divtabindex, role, 키 이벤트를 하나씩 붙이는 대신 요소만 button으로 바꿨습니다. 이 한 줄로 탭 이동, Enter·Space 실행, 역할 전달이 모두 해결됩니다. 이 실습에서 가장 이득이 큰 수정입니다.

3-4. 눈에 안 보이는 포커스와 뒤엉킨 순서 (높음 3)

/* 전: 포커스 테두리 삭제 */
a:focus, button:focus { outline: none; }

/* 후: 마우스 클릭 때는 조용히, 키보드 이동 때는 또렷하게 */
a:focus-visible, button:focus-visible {
  outline: 3px solid #0f5f8f;
  outline-offset: 2px;
}

tabindex="3"과 중복 id="menu"가 걸린 두 <div>는 예시용 자리표시자라 제거했습니다. 실제 메뉴라면 <button>·<a href>로 만들어 tabindex 없이 마크업 순서 = 탭 순서가 되게 하고, id는 페이지 안에서 하나씩만 씁니다.

3-5. 색상 대비 (높음 1)

.sub { color: #aaaaaa; }   /* 흰 배경 대비 2.32:1  ✗ */
.sub { color: #595959; }   /* 흰 배경 대비 7.00:1  ✓ (AAA까지 통과) */

4.5:1만 넘기면 통과지만, 회색 계열은 한 단계 짙게 잡으면 여유가 생깁니다. 버튼 배경도 #f4b400(흰 글씨와 1.85:1)에서 #8a5a00(흰 글씨와 5.93:1)로 미리 바꿨습니다. 이 버튼은 수정 전에는 안에 글자가 없어 대비 검사가 걸리지 않았지만, 글자를 넣는 순간 문제가 될 조합이었습니다. (원리는 색상 대비 가이드)

3-6. 입력창 레이블·제목·링크·표·영역 (보통 7 + 낮음 1)

<!-- 입력창: label을 붙이고 type과 autocomplete를 맞춘다 -->
<label for="email">이메일</label>
<input type="email" id="email" name="email" autocomplete="email">
<label for="tel">연락처</label>
<input type="tel" id="tel" name="tel" autocomplete="tel">

<!-- 제목: h3 → h1 -->
<h1>오늘의 특가</h1>

<!-- 배너 alt: 이미지가 전달하는 정보를 문장으로 -->
<img src="/banner.jpg" alt="가을 시즌 아우터 최대 40% 할인">

<!-- 링크: 목적지를 담은 문구 -->
<a href="/products/outer">아우터 상품 전체 보기</a>

<!-- 표: th + scope -->
<table><tr><th scope="col">사이즈</th><th scope="col">재고</th></tr>…</table>

<!-- 본문 영역 -->
<main id="main"> … </main>

입력창에는 typeemail, tel로 맞추면 모바일에서 알맞은 키보드가 뜨는 부수 효과도 있습니다. 헤더에는 함께 "본문 바로가기" 링크와 <header>를 추가했습니다(구조 가이드).

4. 결과: 100점, 0건

수정한 페이지를 같은 엔진으로 다시 검사하면 100점, 문제 0건이 나옵니다. 하지만 여기서 멈추면 안 됩니다.

5. 100점이 "접근성 100%"는 아니다

이 실습의 진짜 교훈은 오히려 여기에 있습니다. 자동 검사가 만점을 준 페이지에도 다음은 확인되지 않았습니다.

그래서 이 도구는 점수 옆에 항상 "법적 준수 여부를 보증하지 않는다"는 문구를 표시합니다. 자동 검사는 기본기 점검과 회귀 방지에 쓰고, 실제 접근성은 사람이 쓰는 방식으로 확인해야 합니다. 업계에서는 자동 도구가 잡는 문제를 전체의 일부(대략 30~40%)로 보는 것이 일반적입니다.

6. 내 사이트에 적용하는 순서

  1. 검사 도구에 주소를 넣고 결과를 봅니다. 결과 화면의 이전 점수 비교 기능 덕분에 고친 뒤 다시 검사하면 점수 변화가 표시됩니다.
  2. 치명적·높음부터 고칩니다. 대부분 한 줄~몇 줄 수정입니다.
  3. 같은 유형이 반복된다면 개별 페이지가 아니라 템플릿·컴포넌트를 고칩니다(로고 이미지, 아이콘 버튼 등).
  4. 수동 점검(키보드, 화면낭독기)으로 자동 검사가 못 잡는 부분을 확인합니다.
  5. 규칙별 이유와 수정 방법이 궁금하면 검사 규칙 사전을 찾아봅니다.
관련 글
· 대체 텍스트(alt) 제대로 쓰는 법
· 접근 가능한 입력 양식 만들기
· 키보드만으로 쓸 수 있는 사이트 만들기
· 검사 규칙 사전 — 35개 검사 항목 해설
문의: dkdnj123@gmail.com