스타일 포커스

포커스 표시기 (흔히 '포커스 링'으로 표시됨)는 페이지에서 현재 포커스가 있는 요소를 식별합니다. 마우스를 사용할 수 없는 사용자의 경우 이 표시기가 마우스 포인터의 대체 역할을 하므로 매우 중요합니다.

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

: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 {
  
}