스타일 포커스

포커스 표시기('포커스 링'으로 표시되는 경우가 많음)는 페이지에서 현재 포커스가 설정된 요소를 식별합니다. 마우스를 사용할 수 없는 사용자의 경우 이 표시기가 마우스 포인터의 독립형 역할을 하므로 매우 중요합니다.

브라우저의 기본 포커스 표시기가 디자인과 충돌하는 경우 CSS를 사용하여 스타일을 다시 지정할 수 있습니다. 키보드 사용자를 염두에 두어야 합니다.

:focus를 사용하여 항상 포커스 표시기를 표시합니다.

:focus 의사 클래스는 입력 기기 (마우스, 키보드, 스타일러스 등) 또는 요소에 포커스를 지정하는 데 사용되는 메서드와 관계없이 요소에 포커스가 있을 때마다 적용됩니다. 예를 들어 아래 <div>에는 포커스 가능하게 만드는 tabindex가 있습니다. :focus 상태를 위한 맞춤 스타일도 있습니다.

div[tabindex="0"]:focus {
  outline: 4px dashed orange;
}

마우스를 사용하여 클릭하든 키보드를 사용하여 탭하든 <div>항상 동일하게 보입니다.

안타깝게도 브라우저는 포커스를 적용하는 방식과 일치하지 않을 수 있습니다. 요소가 포커스를 받는지 여부는 브라우저와 운영체제에 따라 다를 수 있습니다.

예를 들어 아래 <button>에는 :focus 상태의 맞춤 스타일도 있습니다.

button:focus {
  outline: 4px dashed orange;
}

macOS의 Chrome에서 마우스로 <button>를 클릭하면 맞춤 포커스 스타일이 표시됩니다. 그러나 macOS의 Safari에서 <button>를 클릭하면 맞춤 포커스 스타일이 표시되지 않습니다. 이는 Safari에서 요소를 클릭해도 포커스를 받지 않기 때문입니다.

포커스 동작이 일관되지 않으므로 포커스 스타일이 사용자에게 허용되는지 확인하기 위해 다른 기기에서 약간의 테스트가 필요할 수 있습니다.

:focus-visible를 사용하여 포커스 표시기를 선택적으로 표시합니다.

새로운 :focus-visible 유사 클래스는 요소가 포커스를 받고 브라우저는 휴리스틱을 통해 포커스 표시기를 표시하는 것이 사용자에게 도움이 된다고 판단할 때마다 적용됩니다. 특히 가장 최근의 사용자 상호작용이 키보드를 통해 이루어졌고 키 누름에 메타, ALT / OPTION, CONTROL 키가 포함되지 않았다면 :focus-visible가 일치합니다.

아래 예의 버튼은 포커스 표시기를 선택적으로 표시합니다. 마우스를 사용하여 클릭하는 경우 처음 키보드를 사용하여 탭하는 경우와 결과가 다릅니다.

button:focus-visible {
  outline: 4px dashed orange;
}

:focus-within을 사용하여 포커스가 맞춰진 요소의 상위 요소 스타일 지정

:focus-within 유사 클래스는 요소 자체가 포커스를 받거나 그 요소 내부의 다른 요소가 포커스를 받을 때 요소에 적용됩니다.

페이지의 한 영역을 강조 표시하여 해당 영역에 사용자의 관심을 유도할 수 있습니다. 예를 들어 아래 양식은 양식 자체가 선택될 때와 라디오 버튼이 선택될 때 모두 포커스를 받습니다.

form:focus-within {
  background: #ffecb3;
}

포커스 표시기를 표시하는 경우

경험상 '휴대기기를 사용하는 동안 이 컨트롤을 클릭하면 키보드가 표시될 것으로 예상하나요?'라고 자문해 보는 것이 좋습니다.

답변이 '예'라면 컨트롤은 포커스를 지정하는 데 사용된 입력 기기와 관계없이 항상 포커스 표시기를 표시해야 합니다. <input type="text"> 요소를 예로 들 수 있습니다. 사용자는 입력 요소가 원래 포커스를 받은 방식과 관계없이 키보드를 통해 요소에 입력을 보내야 하므로 항상 포커스 표시기를 표시하는 것이 좋습니다.

답이 '아니요'이면 컨트롤은 포커스 표시기를 선택적으로 표시하도록 선택할 수 있습니다. <button> 요소를 예로 들 수 있습니다. 사용자가 마우스나 터치스크린으로 이를 클릭하면 작업이 완료되고 포커스 표시기가 필요하지 않을 수 있습니다. 그러나 사용자가 키보드로 탐색하는 경우 포커스 표시기를 표시하여 사용자가 ENTER 또는 SPACE 키를 사용하여 컨트롤을 클릭할지 결정할 수 있도록 하는 것이 좋습니다.

outline: none 사용 자제

브라우저에서 포커스 표시기를 그릴 시점을 결정하는 방식은 솔직히 매우 혼란스럽습니다. CSS를 사용하여 <button> 요소의 모양을 변경하거나 요소에 tabindex를 지정하면 브라우저의 기본 포커스 링 동작이 시작됩니다.

매우 일반적인 안티패턴은 다음과 같은 CSS를 사용하여 포커스 표시기를 제거하는 것입니다.

/* Don't do this!!! */
:focus {
  outline: none;
}

이 문제를 해결하는 더 좋은 방법은 :focus:focus-visible 폴리필의 조합을 사용하는 것입니다. 아래의 첫 번째 코드 블록은 폴리필의 작동 방식을 보여주며, 그 아래의 샘플 앱에서는 폴리필을 사용하여 버튼의 포커스 표시기를 변경하는 예를 제공합니다.

/*
  This will hide the focus indicator if the element receives focus via the
  mouse, but it will still show up on keyboard focus.
*/
.js-focus-visible :focus:not(.focus-visible) {
  outline: none;
}

/*
  Optionally: Define a strong focus indicator for keyboard focus.
  If you choose to skip this step, then the browser's default focus
  indicator will be displayed instead.
*/
.js-focus-visible .focus-visible {
  …
}