Foco de estilo

O indicador de foco (geralmente indicado por um "anel de foco") identifica o elemento em foco na página. Para usuários que não conseguem usar um mouse, esse indicador é extremamente importante, porque funciona como um substituto do ponteiro do mouse.

Se o indicador de foco padrão do navegador conflitar com seu design, use CSS para reestilizá-lo. Não se esqueça de pensar nos usuários de teclado.

Use :focus para sempre mostrar um indicador de foco

A pseudoclasse :focus é aplicada sempre que um elemento é focado, independentemente do dispositivo de entrada (mouse, teclado, stylus etc.) ou do método usado para focar. Por exemplo, o <div> abaixo tem um tabindex que permite o foco. Ele também tem um estilo personalizado para o estado :focus:

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

Não importa se você usa um mouse para clicar ou um teclado para navegar, o <div> sempre vai ter a mesma aparência.

Infelizmente, os navegadores podem ser inconsistentes na forma como aplicam o foco. A possibilidade de um elemento receber o foco pode depender do navegador e do sistema operacional.

Por exemplo, o <button> abaixo também tem um estilo personalizado para o estado :focus.

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

Se você clicar no <button> com um mouse no Chrome no macOS, vai aparecer o estilo de foco personalizado. No entanto, o estilo de foco personalizado não será mostrado se você clicar em <button> no Safari no macOS. Isso ocorre porque, no Safari, o elemento não recebe foco quando você clica nele.

Como o comportamento de foco é inconsistente, pode ser necessário testar em diferentes dispositivos para garantir que os estilos de foco sejam aceitáveis para os usuários.

Usar :focus-visible para mostrar seletivamente um indicador de foco

A nova pseudoclasse :focus-visible é aplicada sempre que um elemento recebe o foco e o navegador determina por meio de heurísticas que mostrar um indicador de foco seria benéfico para o usuário. Em particular, se a interação mais recente do usuário foi pelo teclado e a tecla pressionada não incluiu uma meta, ALT / OPTION ou CONTROL, então :focus-visible será correspondente.

O botão no exemplo abaixo seletivamente mostra um indicador de foco. Se você usar um mouse para clicar nele, os resultados serão diferentes do que se você usar um teclado para selecioná-lo.

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

Usar :focus-within para estilizar o elemento pai de um elemento em foco

A pseudoclasse :focus-within é aplicada a um elemento quando ele recebe foco ou quando outro elemento dentro dele recebe foco.

Ele pode ser usado para destacar uma região da página e chamar a atenção do usuário para essa área. Por exemplo, o formulário abaixo recebe foco quando o formulário é selecionado e também quando qualquer um dos botões de opção é selecionado.

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

Quando mostrar um indicador de foco

Uma boa regra geral é se perguntar: "Se você clicar nesse controle enquanto usa um dispositivo móvel, ele vai mostrar um teclado?"

Se a resposta for "sim", o controle provavelmente sempre vai mostrar um indicador de foco, independentemente do dispositivo de entrada usado para dar foco. Um bom exemplo é o elemento <input type="text">. O usuário precisa enviar a entrada para o elemento pelo teclado, independentemente de como o elemento de entrada recebeu o foco originalmente. Portanto, é útil sempre mostrar um indicador de foco.

Se a resposta for "não", o controle poderá mostrar seletivamente um indicador de foco. Um bom exemplo é o elemento <button>. Se um usuário clicar nele com um mouse ou uma tela touchscreen, a ação será concluída, e um indicador de foco pode não ser necessário. No entanto, se o usuário estiver navegando com um teclado, será útil mostrar um indicador de foco para que o usuário possa decidir se quer ou não clicar no controle usando as teclas ENTER ou SPACE.

Evite outline: none

A maneira como os navegadores decidem quando desenhar um indicador de foco é, francamente, muito confusa. Mudar a aparência de um elemento <button> com CSS ou atribuir a um elemento um tabindex fará com que o comportamento padrão do anel de foco do navegador seja iniciado.

Um antipadrão muito comum é remover o indicador de foco usando CSS, como:

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

Uma maneira melhor de contornar esse problema é usar uma combinação de :focus e o polyfill :focus-visible. O primeiro bloco de código abaixo demonstra como o polyfill funciona, e o app de exemplo abaixo mostra um exemplo de como usar o polyfill para mudar o indicador de foco em um botão.

/*
  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 {
  …
}