Programação Por Equipe DevBras

Capa do artigo: Ícone SVG em botão: aria-label, aria-hidden e o que o leitor de tela anuncia

Ícone SVG em botão: aria-label, aria-hidden e o que o leitor de tela anuncia

Como marcar ícones SVG de biblioteca, como o Bootstrap Icons, para que botões só de ícone tenham nome, ícones decorativos fiquem em silêncio e o desenho continue visível em alto contraste.

O cabeçalho do painel administrativo tem três botões só com ícone: uma pessoa (conta), um sino (notificações) e uma seta saindo de uma caixa (sair). Todos copiados do Bootstrap Icons, nítidos em qualquer tela. Com o leitor de tela ligado, a navegação por Tab anuncia "botão", "botão", "botão". Um usuário cego do time de suporte descobriu qual era "sair" clicando em todos.

A resposta curta: o ícone não traz a sua intenção; o nome do botão é você quem dá. Botão só de ícone recebe aria-label (ou texto visualmente oculto) e o SVG dentro dele ganha aria-hidden="true". Ícone ao lado de texto é decoração e também fica com aria-hidden="true". Ícone que sozinho transmite informação, fora de botão, usa role="img" com um nome. E use fill="currentColor", para o desenho acompanhar a cor do texto, inclusive em modo de alto contraste.

Por que o ícone fica mudo

O leitor de tela não enxerga o desenho. Ele lê o nome acessível que o navegador calcula para cada elemento, a partir do conteúdo de texto, de aria-label, de aria-labelledby e de algumas outras fontes. Um button que contém só um svg com caminhos geométricos não tem texto nenhum. O resultado é "botão" e mais nada.

Dependendo de como o ícone foi copiado, pode ser pior: se o SVG vier com um title genérico em inglês, o leitor anuncia "person" ou "bell". Se for uma fonte de ícones, pode ler um caractere estranho da área de uso privado da fonte. Em nenhum caso sai "Minha conta". O conceito geral, para qualquer tipo de ícone, está em ícone no botão: a figura pode ser a decoração, o nome não pode faltar. Aqui o assunto é a marcação de SVG.

Os quatro casos e a marcação de cada um

1. Botão só de ícone

<button type="button" aria-label="Minha conta">
  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20"
       fill="currentColor" viewBox="0 0 16 16" aria-hidden="true">
    <path d="..."/>
  </svg>
</button>

O aria-label dá o nome ao botão. O aria-hidden="true" no SVG garante que nada de dentro dele seja anunciado em duplicidade. O leitor passa a dizer "Minha conta, botão".

Uma alternativa é texto real escondido visualmente, com a mesma classe utilitária de esconder campos de formulário (o Bootstrap traz uma, visually-hidden):

<button type="button">
  <svg ... aria-hidden="true">...</svg>
  <span class="visually-hidden">Minha conta</span>
</button>

A vantagem do texto oculto é que ferramentas de tradução automática do navegador costumam traduzi-lo, enquanto o tratamento de aria-label varia. Para um painel só em português, as duas formas funcionam.

2. Ícone ao lado de texto

<button type="submit">
  <svg ... aria-hidden="true">...</svg>
  Salvar
</button>

O texto "Salvar" já é o nome. Sem o aria-hidden, um title perdido no SVG poderia virar "disquete Salvar". Não repita o texto no leitor.

3. Ícone que informa, fora de botão

Na tabela de pedidos, um ícone verde de "check" sozinho na coluna de status significa "pago". Aqui o ícone é conteúdo:

<svg role="img" aria-label="Pago" ... fill="currentColor">...</svg>

Melhor ainda: escreva "Pago" ao lado. Cor e forma sozinhas não servem a quem não distingue verde de vermelho nem a quem lê a tela impressa.

4. Ícone com estado

O sino mostra um número quando há notificações novas. O número na bolinha vermelha é visual. O nome do botão precisa carregar a mesma informação:

const sino = document.getElementById('botao-notificacoes');
const contador = document.getElementById('contador-notificacoes');

function mostrarNovas(quantidade) {
  contador.textContent = quantidade > 0 ? String(quantidade) : '';
  sino.setAttribute('aria-label',
    quantidade > 0 ? 'Notificações, ' + quantidade + ' novas' : 'Notificações');
}

Com o aria-label no botão, o conteúdo de dentro, inclusive a bolinha, deixa de entrar no nome. Por isso a contagem vai no rótulo. Para um botão de alternar, como "fixar menu", mantenha o rótulo fixo e use aria-pressed="true" ou "false" para o estado.

Sprite, fonte de ícones e SVG inline

O Bootstrap Icons, como outras bibliotecas, pode ser usado de três formas, e a regra de nome vale para todas:

  • SVG inline: o mais flexível. Aplique os atributos acima direto no svg.
  • Sprite com use: <svg aria-hidden="true"><use href="/icones/bootstrap-icons.svg#bell"/></svg>. O aria-hidden vai no svg externo.
  • Fonte de ícones: um i com as classes do ícone. Coloque aria-hidden="true" no i e o nome no botão. Fontes de ícone podem desaparecer quando a pessoa força a própria fonte no navegador, um motivo a mais para preferir SVG.

Se você encontrar focusable="false" em exemplos antigos, ele existia para impedir que versões antigas do Internet Explorer pusessem o SVG na ordem do Tab. Não atrapalha, mas não resolve nome nenhum.

Cor, contraste e o foco que some

Com fill="currentColor", o ícone usa a cor do texto do botão. No modo de cores forçadas do Windows (alto contraste), o navegador troca as cores do texto pelas do sistema, e o ícone acompanha. Um fill="#6c757d" fixo pode ficar invisível sobre o fundo escolhido pela pessoa.

Botões só de ícone costumam vir com border: 0; background: none, e às vezes alguém tira o contorno de foco junto. Garanta um foco visível:

.botao-icone:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

Para escolher quais ícones usar, sem poluir a interface, veja como escolher ícones. E confira a licença do pacote, como explica pacote de ícone grátis ainda tem licença.

Como conferir o nome sem leitor de tela

  1. Abra o DevTools do Chrome ou do Edge e selecione o botão no painel Elements.
  2. Na aba Accessibility, veja o campo "Name" na seção de propriedades computadas.
  3. Repita para cada botão só de ícone do cabeçalho.
  4. Depois, faça um teste real com NVDA no Windows ou VoiceOver no Mac, navegando por Tab.

Erros comuns

  • Botão só de ícone sem nome: o leitor anuncia "botão" e a pessoa precisa adivinhar a ação.
  • Usar o atributo title como nome: aparece só no passar do mouse, some no toque e no teclado, e não é anunciado de forma consistente.
  • Esquecer o aria-hidden no ícone decorativo: o leitor repete o texto ou lê o nome do desenho em inglês.
  • Cor fixa no SVG: o ícone some no modo de alto contraste.
  • Contador só visual: quem usa leitor de tela não sabe que há notificações novas.
  • Tirar o contorno de foco do botão transparente: quem navega por teclado não vê em qual ícone está.

Checklist

  • Todo botão só de ícone tem aria-label ou texto visualmente oculto.
  • SVGs decorativos e dentro de botões nomeados têm aria-hidden="true".
  • Ícone que informa sozinho tem role="img" e nome, ou texto ao lado.
  • Os ícones usam currentColor.
  • Estados como contagem aparecem também no nome acessível.
  • O foco é visível em todos os botões de ícone.
  • O campo "Name" do DevTools mostra a ação de cada botão.

Selecione no DevTools o botão de sair do seu sistema e olhe a aba Accessibility: o campo Name diz "Sair" ou está vazio?

Avalie este artigo

Referência: https://icons.getbootstrap.com/?q=user