"하루 동안 마우스 뽑아. 본인 사이트를 써 봐. 발견하는 버그는 키보드만 쓰는 사용자가 매일 사는 거."
키보드가 접근성 너머에서도 중요한 이유
키보드 네비는 운동 장애 가진 사용자만을 위한 게 아니야. 모든 파워 유저가 키보드 단축키 써. 모든 screen reader 사용자는 정의상 키로 네비해. 모든 dev tool, 모든 IDE, 모든 생산성 앱이 키보드 속도로 살거나 죽어. 처음부터 키보드를 위해 설계하면 모두에게 사이트가 더 빨라.
기본 Tab 순서
기본적으로 Tab 이 문서 순서대로 focusable element 전부를 통과. Focusable element 에 포함:
<a href>(href 가진 앵커)<button>(어떤 type 이든 버튼)<input>,<textarea>,<select>(폼 필드)<details>/<summary>(disclosure 위젯)tabindex="0"가진 어떤 element
페이지가 semantic element 로 지어져 있으면 tab 순서가 자동으로 맞아. 반대도 참: 인터랙티브 것들이 <div> 면 Tab 에 보이지 않아.
tabindex: 말이 되는 세 값
tabindex="0"— "이거 자연 Tab 순서에 포함." 비-focusable element 를 focusable 하게 만들 때 (custom 인터랙티브 위젯). Tabindex 의 가장 흔한 정당한 사용.tabindex="-1"— "JavaScript 로 focus 가능, Tab 으로는 안 됨." 프로그래밍적으로 focus 하고 싶지만 Tab 순서에 안 넣고 싶은 element (제출 후 에러 메시지, 방금 연 modal 의 제목).- 아무 양수 (1, 2, 5...) — 나빠. 자연 문서 순서를 override 하는 custom 순서 강제. DOM 바뀌면 유지 불가; Tab 이 시각 순서 따라가길 기대하는 사용자 놀라게. 하지 마.
Focus 관리: 의도적으로 focus 이동
사용자가 페이지를 크게 바꾸는 행동 취할 때, focus 가 따라가야 해. 예:
- Modal 열기 — modal 안으로 focus 이동 (보통 heading 이나 첫 input). 닫으면 열었던 element 로 focus 되돌리기.
- 에러 있는 폼 제출 — 첫 유효하지 않은 필드, 또는 요약 에러 영역으로 focus 이동.
- 저장 성공 — live region 에서 "저장됨" announce; 큰 action 은 확인 heading 으로 focus 이동.
- SPA route 변경으로 네비 — 새 페이지의
<h1>으로 focus 이동 (SPA 는 브라우저의 자동 focus-to-top 행동을 못 받아).
element.focus() 로 focus 이동. 타깃이 native 로 focusable 안 하면 (heading, 단락) tabindex="-1" 과 페어 — -1 이 Tab 순서에 안 넣고 프로그래밍적으로 focusable 하게 만들어.
:focus vs :focus-visible
수십 년간, focus 받은 모든 element 가 모든 focus 이벤트에 focus ring 받았어 — 마우스 클릭 포함. 디자이너가 싫어했고 ("내 버튼 클릭하면 못생긴 outline"); CSS 한 세대가 outline: none 으로 ring 제거하면서 출시 → 키보드 사용자 박살.
:focus-visible 이 해결했어. 브라우저가 결정: 키보드 네비 → ring 보임; 마우스 클릭 → 안 보임. 접근성 안 깨고 마침내 focus ring 을 아름답게 스타일링할 수 있어:
outline: none 절대 쓰지 마. 기본 focus ring 제거하면, 똑같이 보이는 걸로 대체 (custom outline, box-shadow, 배경 변경). 마우스 클릭이 트리거 안 하게 selector 로 :focus-visible 써. 대체 없는 outline: none 출시한 페이지는 키보드 사용자한테 횡단 불가.Skip Link: 60 초 접근성 승리
모든 페이지가 <main> 전에 header, navigation, 때로 사이드바 가져. 키보드 사용자는 페이지 로드마다 그 다 Tab 해야 함. Skip link 가 첫 번째 focusable element 야 — 보통 숨어 있다가 focus 받으면 보이고 사용자를 메인 콘텐츠로 직접 점프시켜:
Modal 의 Focus Trap
Modal 열리면 focus 가 그 안에 갇혀야 — 마지막 element 에서 Tab 하면 첫 번째로 loop, 첫 번째에서 Shift+Tab 하면 마지막으로 loop, 뒤의 페이지에 사용자가 못 닿음. Native <dialog> element 가 이걸 자동 처리. Roll-your-own modal 은 이걸 세팅하는 JavaScript 필요 — <dialog> 선호의 또 다른 이유.
모든 걸 잡는 감사
한 시간 마우스 뽑고 본인 사이트 써. 로그인, 댓글 달기, 메뉴 네비, 설정 변경 시도. 발견하는 모든 버그가 키보드만 쓰는 또는 screen reader 사용자가 매일 사는 버그. 이 한 시간이 어떤 문서보다 많이 가르쳐.