Foco de estilo

O indicador de foco, geralmente representado por um "anel de foco", identifica o elemento em foco na sua página. Para usuários que não podem ou não querem usar um mouse, esse indicador é extremamente importante, porque ele atua como um substituto para um ponteiro do mouse.

Se o indicador de foco padrão do navegador entrar em conflito com seu design, use CSS para mudar o estilo dele. Não se esqueça dos usuários.

Usar :focus para sempre mostrar um indicador de foco

A pseudoclasse :focus é aplicada a elementos em foco, independente do método de entrada ou dispositivo (como mouse, teclado ou stylus) em uso.

Por exemplo, o <div> a seguir tem um tabindex que o torna focalizável, com um estilo personalizado para o estado :focus:

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

Não importa qual dispositivo você use, o <div> tem a mesma aparência em foco.

Infelizmente, os navegadores podem ser inconsistentes na forma como aplicam o foco. Se um elemento recebe foco ou não pode depender do navegador e do sistema operacional.

Por exemplo, o <button> a seguir tem CSS 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 vai aparecer se você clicar no <button> no Safari no macOS. Isso ocorre porque, no Safari, o elemento não recebe foco quando você clica nele.

O comportamento de foco é inconsistente. Teste sua página em diferentes dispositivos e com entradas diferentes para garantir que os estilos de foco sejam aceitáveis para seus usuários.

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

A pseudoclasse :focus-visible é aplicada quando um elemento recebe foco e o navegador determina (com 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 com um teclado e o pressionamento de tecla não incluiu uma tecla meta, ALT, OPTION ou CONTROL, :focus-visible vai corresponder.

O botão no exemplo a seguir mostra seletivamente um indicador de foco. Se você usar um mouse para clicar, os resultados serão diferentes de se você usar um teclado para navegar até ele.

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

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

A pseudoclasse :focus-within é aplicada a um elemento quando ele ou um elemento filho 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, um formulário recebe foco quando ele mesmo é selecionado e quando qualquer um dos botões de opção é selecionado.

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

Quando mostrar um indicador de foco

Uma boa pergunta é: "Se você clicar nesse controle ao usar um dispositivo móvel, espera que um teclado seja exibido?"

  • Se sim: o controle deve sempre mostrar um indicador de foco, independente do dispositivo de entrada. Por exemplo, isso é quase sempre verdade para o elemento <input type="text">. O usuário precisa enviar entrada para o elemento com o teclado, independente de como o elemento de entrada fica em foco.
  • Se não: o controle pode mostrar um indicador de foco de forma seletiva. Por exemplo, quando um usuário clica em um <button> com um mouse ou em uma tela sensível ao toque, a ação é concluída. Um indicador de foco pode ser desnecessário. No entanto, se o usuário estiver navegando com um teclado, é útil mostrar um indicador de foco para que ele possa decidir se quer ou não ativar o controle com ENTER ou ESPAÇO.

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 dar a um elemento um tabindex faz com que o comportamento padrão do anel de foco do navegador seja ativado.

Às vezes, os desenvolvedores removem o indicador de foco usando CSS:

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

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

/*
  This hides the focus indicator if the element receives focus with a
  mouse, but it still shows 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 {
  ...
}