Foco de estilo

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

Se o indicador de foco padrão do navegador entrar em conflito com o design, use o CSS para mudar o estilo. Lembre-se apenas de pensar nos usuários do teclado.

Use :focus para sempre mostrar um indicador de foco

A pseudoclasse :focus é aplicada sempre que um elemento está em foco, independente do dispositivo de entrada (mouse, teclado, stylus etc.) ou do método usado para focalizar um elemento. Por exemplo, a <div> abaixo tem um tabindex que a torna focalizável. Ela também tem um estilo personalizado para o estado :focus:

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

Independentemente de você usar um mouse para clicar nele ou um teclado para navegar até ele, a <div> sempre terá a mesma aparência.

Infelizmente, os navegadores podem ser inconsistentes com a forma como eles aplicam o foco. O recebimento ou não de um elemento depende do navegador e do sistema operacional.

Por exemplo, a <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 encontrar o estilo de foco personalizado. No entanto, você não verá o estilo de foco personalizado se 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 do foco é inconsistente, pode ser necessário fazer alguns testes em dispositivos diferentes para garantir que os estilos de foco sejam aceitáveis para os usuários.

Use :focus-visible para mostrar um indicador de foco de forma seletiva

A nova pseudoclasse :focus-visible é aplicada sempre que um elemento recebe foco e o navegador determina por heurística que mostrar um indicador de foco seria benéfico para o usuário. Especificamente, se a interação mais recente do usuário foi pelo 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 abaixo mostra seletivamente um indicador de foco. Se você usar um mouse para clicar nele, os resultados serão diferentes do que se você usasse um teclado para acessar a tecla Tab.

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

Usar :focus-within para definir o estilo do pai de um elemento em foco

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

Ele pode ser usado para destacar uma região da página e chamar a atenção do usuário para ela. Por exemplo, o formulário abaixo recebe foco quando ele é 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 prática é perguntar a si mesmo: "Se você clicasse nesse controle enquanto usa um dispositivo móvel, esperaria que ele exibisse um teclado?"

Se a resposta for "sim", o controle provavelmente sempre mostrará um indicador de foco, independentemente do dispositivo de entrada usado para focalizá-lo. Um bom exemplo é o elemento <input type="text">. O usuário precisará enviar entrada para o elemento usando o teclado, independentemente de como o elemento de entrada recebeu o foco originalmente. Por isso, é útil sempre exibir um indicador de foco.

Se a resposta for "não", o controle poderá escolher mostrar um indicador de foco de forma seletiva. Um bom exemplo é o elemento <button>. Se um usuário clicar nele com um mouse ou 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, é útil mostrar um indicador de foco para que ele possa decidir se quer ou não clicar no controle usando as teclas ENTER ou SPACE.

Evite outline: none

Francamente, a maneira como os navegadores decidem quando desenhar um indicador de foco é muito confusa. Mudar a aparência de um elemento <button> com CSS ou atribuir um tabindex a um elemento vai fazer com que o comportamento do anel de foco padrão 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 dele mostra 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 {
  …
}