디자인이 지저분하다고 outline: none을 넣었다가 키보드 사용자를 잃은 이유
문제 발생
버튼을 클릭할 때마다 파란 테두리가 남는 게 보기 싫다는 피드백을 받고 전역으로 지웠습니다.
*:focus { outline: none; }클릭 자국은 사라졌지만, Tab으로 화면을 넘겨 보니 지금 어디에 있는지 전혀 알 수 없었습니다. 키보드만 쓰는 사용자에게는 화면이 통째로 길을 잃은 상태가 됩니다.
원인 분석
포커스 링은 장식이 아니라 현재 위치 표시입니다. 마우스 사용자는 자기가 방금 무엇을 클릭했는지 알기 때문에 필요 없지만, 키보드 사용자에게는 유일한 단서입니다. MDN도 명확히 적어 둡니다 — 포커스 스타일을 제거하면 눈이 보이는 키보드 사용자에게 키보드 내비게이션이 접근 불가능해집니다.
문제는 :focus가 어떻게 포커스를 받았는지 구분하지 않는다는 것이었습니다. 마우스로 눌러도, Tab으로 옮겨도 똑같이 매칭되니 "클릭했을 때만 숨긴다"를 표현할 방법이 없었습니다. 그래서 다들 통째로 지웠습니다.
:focus-visible은 브라우저의 휴리스틱을 그대로 씁니다. 브라우저가 "사용자에게 포커스 위치를 알려 줄 필요가 있다"고 판단할 때만 매칭됩니다. 대략 키보드 이동이나 스크립트로 포커스를 옮겼을 때는 매칭되고, 포인팅 장치로 눌렀을 때는 매칭되지 않습니다. 2022년 3월부터 Baseline입니다.
해결 방안
- 기본 링을 지우되
:focus-visible로 되살립니다. 지우는 것과 되살리는 것을 한 쌍으로 씁니다.
button:focus { outline: none; }
button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}- 대비를 확인합니다. WCAG 2.1의 1.4.11은 시각적 포커스 표시에 최소 3:1 대비를 요구합니다. 배경과 비슷한 색의 얇은 선은 없는 것과 비슷합니다.
outline대신box-shadow를 쓸 때는 모양을 신경 씁니다.outline은border-radius를 따라가고 레이아웃에 영향을 주지 않습니다. 굳이 바꿀 이유가 없다면outline이 안전합니다.- 미지원 브라우저에는
@supports로 폴백을 둡니다. 지원하지 않으면:focus-visible규칙 전체가 무시되어 링이 아예 사라지므로, 그 경우에만:focus를 씁니다.
@supports not selector(:focus-visible) {
button:focus { outline: 2px solid var(--accent); }
}- 입력 필드는
:focus로 두는 편이 낫습니다. 텍스트를 입력받는 컨트롤은 마우스로 눌렀을 때도 어디에 쓰는지 보이는 편이 도움이 됩니다 — MDN의 설명도 이 구분을 예로 듭니다. - 부모를 강조하려면
:focus-within을 씁니다. 자식 중 하나라도 포커스를 받으면 매칭되므로, 필드 묶음 전체를 표시할 때 유용합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.