CSS/스타일 접근성
display: none vs visibility: hidden vs .sr-only: 보조공학 숨김 처리 3대 기법 비교
화면과 스크린리더 양쪽의 노출 여부에 따라 완벽히 분기되는 3대 CSS 숨김 테크닉의 원리와 접근성 트리 반영 메커니즘을 상세히 분석합니다.
실무 검증 기록
실무 판단 기준 및 판정 조건
본 기록은 공개 fixture와 재현 조건을 기준으로 정리한 기술 설명입니다. 실제 브라우저·스크린리더 조합의 동작은 별도 수동 검토가 필요합니다.
| 검증 상태 | 공개 fixture 기반 재현 완료 |
|---|---|
| 검증 기준 | 공개 fixture 및 재현 조건 |
| 검증 범위 | CSS 3대 숨김 처리 기법의 접근성 트리 매핑 검증 및 명시된 입력값에 한정 |
| 수동 확인 | 실제 브라우저·키보드·스크린리더 환경에서 별도 확인 필요 |
| fixture에서 확인한 기대 결과 | [실패 상태] 스크린리더용 텍스트를 display:none으로 숨겨 누락 ➔ [수정 목표] .sr-only 클리핑 기법으로 온전한 낭독 보존 |
검증에 사용된 실제 픽스처 / 재현 조건
display:none vs visibility:hidden vs .sr-only vs aria-hidden='true'- sr-only 요소 내부에 링크가 있을 경우 포커스 시 화면에 시각적으로 노출되도록 스타일링 필요
- aria-hidden='true'를 인터랙티브 버튼 자체에 걸지 않도록 수동 확인 필요
웹 퍼블리싱 작업을 진행할 때 특정 요소를 화면에서 감추는 요구사항은 일상적으로 발생합니다. 반응형 모바일 햄버거 메뉴를 접어두었을 때, 모달 팝업이 닫혀 있을 때, 혹은 반대로 시각적으로는 아이콘만 보이지만 스크린리더 사용자에게는 풍부한 텍스트 설명을 읽어주고 싶을 때가 대표적입니다. 그러나 많은 개발자가 CSS의 display: none, visibility: hidden, 그리고 접근성 전용 숨김 클래스(.sr-only)가 브라우저의 '시각적 렌더 트리(Render Tree)'와 '보조공학 접근성 트리(Accessibility Tree)'에서 각각 어떻게 다르게 처리되는지 정확한 차이를 모른 채 혼용하고 있습니다. 이로 인해 스크린리더에게만 읽어주려던 중요한 안내 문구가 통째로 증발해 버리거나, 화면에서 감춘 팝업 메뉴로 키보드 초점이 제멋대로 침범하는 치명적인 접근성 사고가 발생합니다. 이 글에서는 웹 접근성 표준에 부합하는 3대 숨김 처리 기법의 메커니즘과 정확한 용처를 완벽히 정리합니다.
브라우저의 2가지 트리: 렌더 트리와 접근성 트리의 숨김 처리 원리
웹 브라우저는 HTML 문서를 해석하여 화면을 그릴 때 시각적 박스 배치를 위한 '렌더 트리(Render Tree)'를 만들고, 보조공학 기기에 정보를 전달하기 위한 '접근성 트리(Accessibility Tree)'를 별도로 구축합니다.
CSS의 display: none 속성은 해당 요소를 시각적 렌더 트리뿐만 아니라 접근성 트리에서도 '완전히 물리적으로 삭제'합니다. 즉, 화면에서도 1픽셀도 보이지 않고 공간도 차지하지 않으며, 스크린리더 역시 해당 요소를 아예 존재하지 않는 것으로 취급하여 0.1초도 읽어주지 않습니다. 키보드 Tab 키 포커스 역시 완벽하게 차단됩니다. 따라서 아코디언이 접혀 있거나 모달이 닫혀 있을 때처럼 '누구에게도 지금 당장 노출되어서는 안 되는 콘텐츠'에 사용하는 것이 완벽한 용법입니다.
반면 visibility: hidden 속성은 화면에서 시각적으로 투명해지며 접근성 트리에서도 제외되지만, 해당 요소가 차지하던 '물리적 너비와 높이 공간'은 화면에 그대로 보존(공백 상태로 유지)된다는 중요한 레이아웃 차이가 있습니다.
스크린리더 전용 숨김 클래스(.sr-only / .visually-hidden)의 완벽한 CSS 스니펫
시각적으로는 깔끔한 UI를 위해 텍스트를 숨기되, 스크린리더 사용자에게는 충실하게 낭독되어야 하는 콘텐츠(예: 아이콘 버튼의 보이지 않는 텍스트 레이블, 헤딩 구조 보완용 타이틀, 건너뛰기 링크 등)에는 특별한 CSS 클리핑 테크닉이 필요합니다.
- 1. 잘못된 옛날 방식의 위험성: 과거에 자주 쓰이던 text-indent: -9999px;이나 left: -9999px; 기법은 거대한 레이아웃 렌더링 부하를 일으키거나 키보드 포커스가 화면 밖 우주로 튕겨 나가는 치명적인 스크롤 버그를 유발하므로 절대 사용해서는 안 됩니다.
- 2. W3C 공식 권장 .sr-only 클래스: 요소를 1×1 픽셀의 미세한 크기로 줄이고, clip: rect(0, 0, 0, 0); 및 clip-path: inset(50%); 속성을 통해 시각적으로 완벽히 오려내어 감춥니다. 동시에 margin: -1px;과 overflow: hidden;을 주어 레이아웃 공간을 단 1px도 차지하지 않게 만듭니다.
- 3. 접근성 트리 보존: 이 마크업은 display: none이 아니므로 브라우저 접근성 트리에 100% 온전하게 살아남습니다. 스크린리더는 이 텍스트를 마치 화면에 크게 적혀 있는 일반 글자처럼 가장 자연스럽고 명확하게 읽어줍니다.
반대로 화면에는 보이지만 스크린리더에서는 숨겨야 할 때: aria-hidden="true"
시각적으로는 아이콘이나 장식용 그래픽이 화려하게 노출되어 있지만, 스크린리더 사용자에게는 불필요한 청취 피로를 주지 않기 위해 침묵시켜야 하는 상황도 있습니다.
예를 들어 텍스트 링크 옆에 붙어 있는 단순 장식용 화살표 아이콘(➔)이나, 뱃지 옆의 장식용 SVG 점(Dot) 등입니다. 이때는 HTML 속성으로 aria-hidden='true'를 선언합니다. 이 속성은 시각적인 렌더 트리에는 단 0.1%의 영향도 주지 않아 화면에는 완벽하게 예쁜 그래픽으로 남아있으면서도, 오직 스크린리더를 위한 접근성 트리에서만 해당 요소를 깨끗하게 지워줍니다.
주의할 점은 앞선 아티클에서도 다루었듯이 aria-hidden='true' 컨테이너 내부에 키보드 포커스를 받을 수 있는 버튼이나 링크가 포함되어서는 절대 안 된다는 철칙입니다.
3대 숨김 처리 기법의 최종 실무 결정 매트릭스
퍼블리싱 실무에서 어떤 기법을 적용해야 할지 1초 만에 판단할 수 있는 황금 기준표는 다음과 같습니다.
첫째, 화면(눈)에서도 안 보이고, 스크린리더(귀)에서도 안 들려야 한다면 ➔ display: none 또는 HTML hidden 속성을 사용합니다.
둘째, 화면(눈)에서는 안 보이지만, 스크린리더(귀)에서는 명확히 들려야 한다면 ➔ .sr-only (또는 .visually-hidden) CSS 클래스를 사용합니다.
셋째, 화면(눈)에서는 예쁘게 보여야 하지만, 스크린리더(귀)에서는 무시하고 지나쳐야 한다면 ➔ aria-hidden='true' 속성을 사용합니다.
이 명쾌한 3원칙을 엄격하게 지키면 어떠한 복잡한 모던 컴포넌트 환경에서도 보조공학 소음이나 포커스 유실 없는 완벽한 접근성을 달성할 수 있습니다.
예외 조건 및 수동 검토 범위
- sr-only 요소 내부에 링크나 버튼이 들어가는 경우(예: 스킵 내비게이션), 포커스를 받았을 때는 화면에 시각적으로 튀어나오도록 :focus 상태 스타일을 필히 정의해야 합니다.
- aria-hidden='true'는 텍스트를 감출 때만 쓰고 조작 가능한 버튼 자체에 걸면 스크린리더 침묵 오류가 발생합니다.