WCAG 성공 기준 · Level AA
WCAG 2.4.7: 포커스 표시됨
WCAG 2.4.7은 키보드로 조작 가능한 모든 사용자 인터페이스에 대해, 사용자가 현재 어떤 요소에 키보드 포커스가 있는지 항상 볼 수 있도록 눈에 보이는 포커스 표시기를 갖출 것을 요구합니다. 이는 키보드만 사용하는 사용자, 운동 장애가 있는 사람들, 그리고 마우스를 사용할 수 없는 모든 사람에게 필수적입니다.
- Level AA
- Wcag
- Wcag 2 2 aa
- 작동 가능한
- 접근성
이 규칙의 의미
WCAG 2.4.7 Focus Visible은 웹 페이지의 모든 인터랙티브 요소 — 링크, 버튼, 폼 입력, 커스텀 위젯, 그리고 키보드로 조작 가능한 기타 모든 구성 요소 — 가 키보드 포커스를 받을 때 눈에 보이는 포커스 표시를 제공할 것을 요구합니다. 쉽게 말해, 사용자가 Tab 키를 눌러 페이지를 이동할 때, 현재 어떤 요소가 활성 상태인지 정확히 볼 수 있어야 합니다.
이 기준은 포커스 표시의 특정한 시각적 스타일을 강제하지는 않습니다. 단지 어떤 형태로든 눈에 보이는 변화가 일어나야 한다는 것만 요구합니다. 그렇다고 해도, 예를 들어 배경과 섞여 거의 보이지 않는 1픽셀 점선 테두리처럼, 간신히 인지 가능한 표시만 있는 경우는 기술적으로는 2.4.7을 통과할 수 있지만, WCAG 2.2에서 도입된 더 엄격한 WCAG 2.4.11(포커스 외형) 기준에는 미달할 수 있습니다. 2.4.7만 놓고 보면, 식별 가능한 시각적 변화가 있으면 충분합니다.
통과로 인정되는 경우: 시력이 있는 사용자가 페이지를 Tab으로 이동할 때, 스크린 리더 알림이나 비시각적 단서에 의존하지 않고도 어떤 요소에 포커스가 있는지 식별할 수 있으면 포커스 표시는 기준을 충족합니다. 일반적으로 허용되는 구현 방식에는 브라우저 기본 테두리, 커스텀 CSS outline 또는 box-shadow 규칙, 밑줄 변화, :focus 또는 :focus-visible 상태에서 적용되는 배경색 변경 등이 있습니다.
실패로 인정되는 경우: 개발자가 CSS에서 outline: none 또는 outline: 0과 같이 기본 브라우저 포커스 링을 제거하고, 동등한 커스텀 표시를 제공하지 않을 때 실패가 발생합니다. 또한 <div>나 <span> 요소로 만든 커스텀 컴포넌트에 tabindex를 부여해 키보드 포커스를 받을 수 있게 했지만, 포커스 시 시각적 스타일 변화가 전혀 없는 경우도 실패입니다.
공식 예외: WCAG는 이 기준이 키보드로 조작 가능한 인터페이스에만 적용된다고 명시합니다. 순수하게 장식용이거나 tabindex='-1'을 통해 탭 순서에서 명시적으로 제외된 구성 요소는 일반적인 키보드 탐색으로 포커스를 받을 수 없기 때문에 포커스 표시를 제공할 필요가 없습니다.
왜 중요한가
포커스 가시성은 키보드 접근성의 기초이며, 키보드 접근성은 다양한 장애 집단을 위한 접근성의 관문입니다. CDC에 따르면 미국 성인의 약 26%가 어떤 형태로든 장애를 가지고 있으며, 이들 중 상당수는 포인팅 장치 대신 키보드나 키보드 에뮬레이션 보조 기술에 의존합니다.
운동 장애가 있는 사용자 — ALS, 뇌성마비, 반복성 긴장 손상, 파킨슨병 등의 상태를 가진 사람들을 포함 — 는 종종 키보드, 스위치 장치, sip-and-puff 컨트롤러, 시선 추적 소프트웨어에 의존합니다. 이러한 모든 입력 방식은 브라우저의 키보드 포커스 모델에 의존합니다. 포커스 표시가 보이지 않으면, 이 사용자는 페이지에서 자신의 위치를 파악할 수 없고, 올바른 컨트롤을 활성화할 수 없으며, 폼 제출, 구매 완료, 메뉴 탐색과 같은 중요한 작업에서 완전히 배제될 수 있습니다.
스크린 리더를 사용하지 않지만 화면을 확대해서 보는 저시력 사용자 역시 눈에 보이는 포커스에 의존합니다. 페이지의 일부를 확대했을 때, 눈에 보이는 포커스 링이 어떤 요소가 활성 상태인지 알려주고 상호작용을 안내합니다.
인지 및 주의 관련 장애가 있는 사용자도 명확한 포커스 표시의 혜택을 봅니다. ADHD나 기억력 문제를 가진 사용자는 복잡한 페이지에서 자신의 위치를 쉽게 잃어버리는데, 눈에 띄는 포커스 표시는 신뢰할 수 있는 시각적 기준점을 제공합니다.
구체적인 실제 사례를 들어보면: 다발성 경화증이 있는 한 사용자가 마우스 조작이 어려워져 키보드만으로 전자상거래 사이트를 탐색한다고 가정해 봅시다. 이 사용자는 제품 페이지에서 Tab 키를 눌러 "Add to Cart" 버튼에 도달합니다. 그런데 개발자가 포커스 링을 숨겨두었다면, 사용자는 포커스가 어디에 있는지 전혀 볼 수 없습니다. Enter 키를 눌렀을 때 아무 일도 일어나지 않거나(포커스가 비인터랙티브 요소에 있었던 경우), 엉뚱한 동작이 실행될 수 있습니다. 그 결과는 좌절, 작업 포기, 그리고 비즈니스 입장에서는 매출 손실입니다 — 단 하나의 CSS 규칙으로 충분히 예방할 수 있는 문제입니다.
장애 여부와 상관없이, 포커스 표시는 마우스 사용이 불편한 모든 사용자에게 도움이 됩니다. 키보드 단축키로 탐색하는 파워 유저, 외장 마우스 없이 노트북을 사용하는 사람, 긴 폼을 작성하는 사용자 등이 그 예입니다. 눈에 보이는 포커스는 시맨틱 HTML과 올바른 탭 순서를 장려함으로써 간접적으로 SEO를 개선하기도 하는데, 검색 엔진 크롤러는 이러한 점을 긍정적으로 평가합니다.
관련 Axe-core 규칙
WCAG 2.4.7은 포커스 표시가 실제로 보이는지를 자동화 도구가 신뢰성 있게 판단할 수 없기 때문에 수동 테스트가 필요합니다. Axe-core와 유사한 엔진은 outline: none과 같은 CSS 규칙의 존재는 감지할 수 있지만, 모든 테마, 고대비 모드, 브라우저 렌더링 엔진에 걸쳐 렌더링된 시각적 결과를 평가할 수는 없습니다. 다음은 테스트 환경에 대한 설명입니다.
- 수동 테스트 필요 — focus-visible 억제: Axe-core는 2.4.7 실패를 확실히 표시하는 전용 규칙을 제공하지 않습니다. 그렇게 하려면 페이지를 렌더링하고, 모든 요소를 Tab으로 이동해 보고, 포커스 표시의 픽셀 단위 대비를 분석해야 하는데, 이는 정적 또는 DOM 수준 분석을 넘어서는 작업이기 때문입니다. 대신, 테스터가 페이지를 직접 Tab으로 이동하며 각 인터랙티브 요소가 포커스 시 시각적 변화를 보이는지 확인해야 합니다.
css-orientation-lock및 스타일 검사에서 얻는 부분적 신호: 일부 axe-core 설정은 스타일시트에outline: 0또는outline: none이 존재할 경우 모범 사례 경고로 표시하지만, 이는 확정적인 위반 검사가 아니라 휴리스틱에 불과합니다. 다른 곳에서 유효한 커스텀 포커스 스타일이 캐스케이드 상에서 이를 덮어쓸 수 있기 때문입니다.- 자동화가 부족한 이유: 포커스 표시는 특정 상태(예: 모달이 열려 있을 때)에만 숨겨져 있을 수도 있고, 특정 요소 유형에만 적용되거나, 특정 색상 테마에서만 문제가 될 수도 있습니다. 이러한 조건부 실패는 실제 렌더링 환경에서 각 인터랙티브 요소를 사람이 직접 탐색하고 가시성을 확인해야 합니다. axe DevTools Pro와 같은 도구는
outline: none이 적용된 요소를 하이라이트해 도와줄 수 있지만, 최종적인 통과/실패 판단은 사람이 내려야 합니다.
테스트 방법
- 자동 사전 스캔: 페이지에서 axe DevTools(브라우저 확장 또는 CLI)나 Google Lighthouse를 실행합니다. 포커스 스타일과 관련된 모범 사례 또는 실험적 경고가 있는지 확인합니다. 이 경고들이 2.4.7 실패를 확정적으로 의미하는 것은 아니지만, 점검할 가치가 있는 요소를 드러냅니다. Lighthouse에서는 "Accessibility" 카테고리에서 포커스 관련 항목을 확인합니다. 보고서를 내보내고, 표시된 모든 인터랙티브 요소를 기록합니다.
- 수동 키보드 Tab 테스트: 마우스를 분리하거나 멀리 치웁니다. 페이지 상단에서 Tab 키를 반복해서 눌러 링크, 버튼, 입력 필드, 드롭다운, 모달, 탭, 아코디언, 날짜 선택기 등 모든 인터랙티브 요소를 탐색합니다. 각 지점에서, 포커스를 받은 요소가 포커스를 받지 않은 주변 요소와 시각적으로 구분되는지 확인합니다. 포커스가 도착했을 때 아무런 시각적 변화가 없는 요소는 모두 기록합니다.
- 역방향 Tab 테스트: Shift+Tab을 사용해 페이지를 역방향으로 탐색하며 동일한 시각적 확인을 반복합니다. 일부 구현에서는 CSS 특이성 문제로 인해 한 방향에서만 포커스 가시성이 깨지는 경우가 있습니다.
- NVDA + Firefox 테스트: NVDA를 실행한 상태에서 Firefox를 엽니다. Browse Mode(화살표 키)를 사용한 뒤, 폼 컨트롤과 상호작용하기 위해 Forms Mode(Enter)를 사용합니다. NVDA가 포커스되었다고 알리는 모든 요소가 화면에서도 눈에 보이는 포커스 표시를 갖는지 확인합니다. 이는 보조 기술 포커스와 브라우저 포커스 간의 불일치를 발견하는 데 유용합니다.
- VoiceOver + Safari 테스트(macOS/iOS): VoiceOver를 활성화하고 Tab 또는 VO+오른쪽 화살표를 사용해 인터랙티브 요소를 이동합니다. 화면에 보이는 포커스 링이 VoiceOver가 알리는 대상과 일치하는지 시각적으로 확인합니다.
- JAWS + Chrome 테스트: JAWS를 가상 커서 모드로 사용한 뒤 애플리케이션 모드로 전환합니다. 인터랙티브 컨트롤을 Tab으로 이동하며, 포커스를 받은 모든 요소에 눈에 보이는 포커스 표시가 나타나는지 확인합니다.
- 고대비 모드 테스트: Windows 고대비 모드(또는 macOS 대비 증가)를 활성화하고 Tab 테스트를 반복합니다. 일부 포커스 표시는 고대비 테마에서 사라지는 색상에 의존합니다. 이 모드에서도 포커스 표시는 계속 눈에 보여야 합니다.
- CSS 검사: 브라우저 DevTools를 열고, 인터랙티브 요소를 선택한 뒤 Tab을 눌러 해당 요소에 포커스를 맞추고 계산된 스타일을 검사합니다.
outline: none또는outline: 0이 보상용 포커스 스타일 없이 설정된 규칙이 없는지 확인합니다. 또한:focus-visible과:focus를 모두 확인해 키보드로 발생한 포커스가 제대로 커버되는지 점검합니다.
수정 방법
대체 스타일 없이 전역 outline 제거 — 잘못된 예
<!-- CSS 리셋에서 모든 포커스 표시를 전역적으로 제거하는 경우 -->
<style>
* {
outline: none; /* 모든 요소에서 포커스 링 제거 */
}
</style>
<a href='/products'>View Products</a>
<button type='submit'>Buy Now</button>
대체 스타일 없이 전역 outline 제거 — 올바른 예
<!-- 전역 outline: none 리셋을 제거하고,
시각적으로 명확한 커스텀 포커스 스타일을 제공 -->
<style>
/* 모션 감소를 선호하는 사용자를 존중 */
:focus-visible {
outline: 3px solid #005fcc;
outline-offset: 2px;
}
</style>
<a href='/products'>View Products</a>
<button type='submit'>Buy Now</button>
<!-- 이제 두 요소 모두 키보드 포커스를 받으면 대비가 높은 파란색 테두리가 표시됨 -->
포커스 스타일이 없는 커스텀 div 기반 버튼 — 잘못된 예
<!-- 버튼처럼 스타일링하고 포커스 가능하게 만든 div이지만 :focus CSS가 없음 -->
<style>
.fake-btn {
display: inline-block;
padding: 10px 20px;
background: #e00;
color: #fff;
cursor: pointer;
}
/* :focus 또는 :focus-visible 규칙이 정의되지 않음 */
</style>
<div class='fake-btn' tabindex='0' role='button'
onclick='addToCart()' onkeydown='handleKey(event)'>
Add to Cart
</div>
포커스 스타일이 없는 커스텀 div 기반 버튼 — 올바른 예
<!-- 커스텀 컴포넌트에 :focus-visible을 추가해
키보드 사용자가 이 요소에 포커스가 갔을 때 명확한 표시를 보도록 함 -->
<style>
.fake-btn {
display: inline-block;
padding: 10px 20px;
background: #e00;
color: #fff;
cursor: pointer;
}
.fake-btn:focus-visible {
outline: 3px solid #ffcc00;
outline-offset: 3px;
}
</style>
<div class='fake-btn' tabindex='0' role='button'
onclick='addToCart()' onkeydown='handleKey(event)'>
Add to Cart
</div>
<!-- 노란색 테두리는 마우스 클릭이 아니라 키보드 포커스일 때만 나타남 -->
모달 오버레이 안에서 숨겨진 포커스 링 — 잘못된 예
<!-- 모달이 overflow:hidden과 스태킹 컨텍스트를 적용해
기본 outline이 잘려 보이지 않게 만드는 경우 -->
<style>
.modal-body {
overflow: hidden; /* 요소 밖으로 나가는 outline을 잘라냄 */
border-radius: 8px;
}
</style>
<div class='modal-body'>
<button>Confirm Order</button>
<button>Cancel</button>
</div>
모달 오버레이 안에서 숨겨진 포커스 링 — 올바른 예
<!-- outline 대신 box-shadow를 사용해
스태킹 컨텍스트 안에서 렌더링되도록 하고 잘리지 않게 함 -->
<style>
.modal-body {
overflow: hidden;
border-radius: 8px;
}
.modal-body button:focus-visible {
/* box-shadow는 overflow:hidden에 의해 잘리지 않고
요소 자신의 박스 안에 머무름 -->
box-shadow: 0 0 0 3px #005fcc;
outline: none; /* 기본 포커스를 제거해 이중 링을 방지 */
}
</style>
<div class='modal-body'>
<button>Confirm Order</button>
<button>Cancel</button>
</div>
자주 발생하는 실수
- 어떤 요소에 영향을 미치는지 검토하지 않고 기본 CSS 리셋에
outline: none을 추가하는 경우. normalize.css의 예전 버전이나 Bootstrap 유틸리티 등 많은 인기 있는 리셋이 포커스 링을 전역적으로 제거합니다. 항상 명시적인:focus-visible규칙을 추가해 키보드 사용자를 위해 가시성을 복원해야 합니다. :focus-visible이 더 적절한 상황에서:focus만 사용하거나, 그 반대로 하는 경우.:focus만 사용하면 마우스 클릭 시에도 포커스 표시가 적용되어 어색해 보일 수 있습니다. 반대로:focus없이:focus-visible만 사용하면 오래된 브라우저에서는 포커스 표시가 전혀 보이지 않을 수 있습니다. 대상 브라우저 전반에서 테스트해야 합니다.- 캐스케이드를 이해하지 못한 채 컴포넌트 라이브러리 테마 오버라이드 안에서
outline: none을 적용하는 경우. 테마 파일의 단 한 줄 오버라이드가, 이를 상속하는 모든 컴포넌트(서드파티 위젯 포함)의 포커스 표시를 조용히 지워버릴 수 있습니다. - 요소나 페이지 배경과의 대비가 부족한 포커스 색상을 사용하는 경우. 흰 배경 위의 연한 회색 테두리는 기술적으로는 outline을 추가하지만 거의 보이지 않을 수 있습니다. 2.4.7은 특정 대비 비율을 요구하지 않지만, 2.4.11은 요구하며, 개발자가 기준을 지켰다고 생각하는 상황에서도 대비가 낮은 포커스 표시 때문에 감사에서 자주 실패합니다.
- 컨테이너에
overflow: hidden또는clip-path를 설정해 브라우저 기본 outline을 잘라내는 경우. 해결책은 포커스 표시를box-shadow기반으로 전환하는 것입니다. box-shadow는 요소 자신의 박스 안에서 렌더링되며 상위 요소의 overflow 규칙에 의해 잘리지 않습니다. - SVG나 Canvas 컴포넌트 내부의 인터랙티브 요소에 포커스 표시를 잊는 경우. 커스텀 차트 툴팁, SVG 기반 아이콘 버튼, 캔버스 기반 드로잉 도구 등은 기본 포커스 스타일이 없는 경우가 많습니다. 이러한 요소에는 명시적인 ARIA role,
tabindex,:focus-visibleCSS 또는 JavaScript 기반 시각적 피드백이 필요합니다. - 개발 환경에서는 포커스가 보이지만, 프로덕션 CSS(예: 포스트 프로세서나 빌드 단계)를 통해서만 포커스 가시성을 제거하는 경우. 이로 인해 개발팀은 로컬 QA를 통과했다고 생각하지만, 실제 사용자에게는 접근성이 깨진 상태를 배포하게 됩니다.
- SPA 내비게이션 링크에 사용되는
role='link'span 요소에는 포커스 표시를 적용하지 않고,<a>요소에만 포커스 표시를 적용하는 경우. 네이티브 태그가 무엇이든, 키보드로 포커스 가능한 모든 요소에는 눈에 보이는 포커스 상태가 필요합니다. - 모바일 사용자는 항상 터치만 사용할 것이라고 가정하고, 특정 뷰포트 너비에서만 미디어 쿼리로 포커스 링을 숨기는 경우. Bluetooth 키보드를 사용하는 태블릿 사용자나, 가로 모드에서 키보드 입력에 의존하는 사용자는 포커스 표시 없이 남겨지게 됩니다.
- 포커스 링이 나타나지 않도록, 프로그래매틱 포커스 직후 JavaScript로
.blur()를 호출하는 경우. 이는 포커스 가시성을 완전히 제거하는 심각한 오류이며, 디자인상의 편의를 위해 절대 사용해서는 안 됩니다.
터키 접근성 규정과의 관계
터키의 Cumhurbaşkanlığı Genelgesi 2025/10(대통령령 2025/10)은 2025년 6월 21일 관보(Resmî Gazete) 제32933호에 게재되었으며, 터키에서 운영되는 광범위한 주체에 대해 웹 및 모바일 접근성 요구사항을 법적으로 규정합니다. 이 대통령령은 해당 기관이 WCAG 2.2 AA 레벨에 부합할 것을 의무화하며, 이로 인해 WCAG 2.4.7 Focus Visible은 단순한 모범 사례 권고가 아니라 직접적인 준수 의무가 됩니다.
이 대통령령의 적용 대상에는 공공 기관 및 단체, 전자상거래 플랫폼, 은행 및 금융 서비스 제공자, 병원 및 의료 기관, 가입자 200,000명 이상인 통신사, 여행사, 민간 운송 회사, 그리고 교육부(MoNE)의 인가를 받은 사립학교 등이 포함됩니다. 이러한 모든 조직에 대해, 디지털 인터페이스에서 눈에 보이는 포커스 표시를 제공하지 않는 것은 단순한 사용성 부족이 아니라 규제 위반 문제입니다.
Erişilebilirlik Logosu(접근성 로고)는 가족·사회서비스부가 발급하는 공식 인증 마크로, 해당 기관이 이를 표시함으로써 준수 여부를 보여줄 수 있습니다. 접근성 로고를 획득하려면 WCAG 2.2 AA 레벨 기준에 대한 공식 감사를 통과해야 합니다. WCAG 2.4.7은 감사자가 평가하는 AA 기준 중 하나이며, 일반적으로 위의 테스트 섹션에서 설명한 것처럼 수동 키보드 테스트를 통해 확인합니다. 사이트가 포커스 링을 숨기거나 커스텀 컴포넌트에 눈에 보이는 포커스를 구현하지 않은 조직은 로고 획득을 위한 감사를 통과할 수 없습니다.
특히 터키의 전자상거래 플랫폼의 경우, 포커스 가시성은 직접적인 상업적 영향을 미칩니다. 접근 가능한 사이트는 키보드나 스위치 접근만으로 쇼핑하는 운동 장애 고객을 포함해 더 넓은 사용자층에 도달할 수 있으며, 대통령령 2025/10을 준수함으로써 행정 제재로부터 조직을 보호합니다. 컴포넌트 라이브러리를 구축할 때부터 focus-visible 패턴을 내장해 두는 것이, 감사 이후에 뒤늦게 수정하는 것보다 훨씬 비용 효율적으로 Erişilebilirlik Logosu를 유지하고 터키의 접근성 의무를 충족하는 길입니다.
출처 및 참고자료
- W3C Understanding 2.4.7 Focus Visible
- W3C Techniques for 2.4.7
- WebAIM: Keyboard Accessibility
- MDN: :focus-visible pseudo-class
- MDN: :focus pseudo-class
- W3C Technique C15: Using CSS to change the presentation of a user interface component when it receives focus
- W3C Technique G149: Using user interface components that are highlighted by the user agent when they receive focus
