O menu costuma ser a primeira parte da landing page a quebrar quando o layout fica estreito. Links somem atrás de um ícone, submenus abrem apenas com hover e o foco entra em opções que continuam visualmente fechadas. Uma camada de ARIA adicionada no fim não conserta essa estrutura.
Um menu de navegação acessível começa com links e listas. Se houver grupos recolhíveis, botões controlam a abertura e informam o estado. O comportamento precisa continuar previsível por teclado, toque, leitor de tela, zoom e voz. Este guia mostra como escolher o padrão, montar a hierarquia e conferir a URL publicada.
Separe navegação de menu de aplicativo
A palavra “menu” cobre interfaces diferentes. A navegação de um site leva a páginas ou seções. Um menu de aplicativo oferece comandos como salvar, duplicar ou alterar formatação.
Para a navegação comum de uma landing page, prefira HTML nativo:
<nav aria-label="Principal"> <ul> <li><a href="/recursos/">Recursos</a></li> <li><a href="/precos/">Preços</a></li> <li><a href="/docs/">Documentação</a></li> </ul></nav>Não adicione role="menu", role="menubar" e role="menuitem" só porque a lista aparece no cabeçalho. O exemplo de navegação com disclosure da W3C explica que esses papéis criam a expectativa de um widget parecido com menus de aplicativos, incluindo gerenciamento próprio de foco e comandos com setas. A navegação de site normalmente funciona melhor com Tab, Shift+Tab, links e botões nativos.
Use o padrão de menu e menubar apenas quando a interface realmente precisar desse modelo de interação. Ele traz roving tabindex, setas, Home, End, busca por caracteres e regras para submenus. Implementar metade do padrão piora a experiência.
Dê estrutura e nome à navegação
O elemento nav cria uma região de navegação. Dentro dele, listas comunicam quantos itens existem e como grupos se relacionam. Não remova a semântica de ul e li para facilitar o CSS.
Uma página pode ter navegação principal, rodapé, sumário e links relacionados. Dê nomes distintos quando houver mais de uma região:
<nav aria-label="Principal">...</nav><nav aria-label="Rodapé">...</nav>Se um título visível já identifica o bloco, use aria-labelledby para reaproveitá-lo. Evite nomes como “Navegação de navegação”. Leitores de tela já anunciam o tipo da região.
Marque a página atual com aria-current="page" no link correspondente. Preserve também uma diferença visual que não dependa apenas de cor. O estado atual ajuda a pessoa a entender onde está sem abrir cada destino.
O guia sobre títulos e regiões ajuda a conferir se cada landmark tem propósito e nome próprios.
Use um botão para abrir cada submenu
Um link navega. Um botão altera o estado da página. Quando “Recursos” apenas abre um grupo de destinos, implemente esse controle como button:
<li> <button type="button" id="controle-recursos" aria-expanded="false" aria-controls="submenu-recursos" > Recursos </button> <ul id="submenu-recursos" aria-labelledby="controle-recursos" hidden> <li><a href="/recursos/portfolio/">Portfólios</a></li> <li><a href="/recursos/landing-pages/">Landing pages</a></li> </ul></li>Ao abrir, mude aria-expanded para true e remova hidden. Ao fechar, restaure os dois valores. Derive o ícone, o estilo e a visibilidade desse mesmo estado.
Se o rótulo também precisa navegar para uma página de categoria, prefira um link separado e um botão adjacente com nome específico, como “Abrir páginas de Recursos”. Um único elemento que navega no clique e abre o submenu com outra tecla exige uma regra difícil de descobrir, sobretudo no toque.
O artigo sobre nomes acessíveis de links e botões ajuda a revisar controles com ícones e rótulos repetidos.
Não faça do hover a única entrada
Submenus que aparecem apenas quando o ponteiro passa sobre um item excluem teclado e toque. Abra o grupo pelo botão. O hover pode acompanhar essa interação, desde que não seja o único caminho nem introduza um estado separado.
Conteúdo exibido por hover ou foco precisa cumprir três condições do critério 1.4.13 da WCAG 2.2:
- deve poder ser dispensado sem mover foco ou ponteiro quando cobre conteúdo;
- deve aceitar que o ponteiro passe do controle para o conteúdo aberto;
- deve permanecer visível até a pessoa sair, fechar ou a informação perder a validade.
Permita fechar com Escape e devolva o foco ao botão que abriu o submenu. Não use um atraso curto para fechar assim que o ponteiro cruza um pequeno espaço. Uma área segura entre controle e painel reduz fechamentos acidentais.
Evite abrir automaticamente apenas porque o botão recebeu foco. Quem navega com Tab pode querer seguir adiante sem revelar cada grupo.
Mantenha a ordem de teclado igual à ordem visual
Na navegação baseada em disclosure, Tab e Shift+Tab percorrem botões e links visíveis na ordem do DOM. Enter ou Espaço ativa o botão. Escape fecha o grupo aberto. Setas, Home e End são opcionais, não um requisito para uma lista de links comum.
Quando o submenu fecha, seus links devem sair da ordem de foco. opacity: 0, altura zero ou deslocamento para fora da tela não bastam. Use hidden, remoção controlada do DOM ou outra técnica que sincronize visual, leitura e foco.
No menu móvel, abrir o painel não deve prender o foco como um diálogo se o conteúdo continuar fazendo parte da página. Se o projeto usa um drawer modal que bloqueia o restante da interface, aplique o contrato de um diálogo e teste contenção, retorno de foco e fundo inerte. O guia de diálogos modais acessíveis cobre esse caso.
Não use tabindex positivo para empurrar o menu ao início. Corrija a ordem do DOM. O roteiro de navegação por teclado ajuda a encontrar links invisíveis, armadilhas e foco encoberto.
Trate o menu móvel como a mesma navegação
Desktop e celular devem expor os mesmos destinos essenciais. Não mantenha duas cópias simultaneamente disponíveis para tecnologia assistiva. Quando o breakpoint troca a apresentação, confirme qual navegação está visível e alcançável.
O botão que abre a navegação móvel precisa de nome e estado:
<button type="button" aria-expanded="false" aria-controls="navegacao-principal">Menu</button>Um ícone de três linhas sem nome não informa a ação. Um botão chamado “Menu” já é claro; o estado expandido ou recolhido vem de aria-expanded. Evite substituir o nome por “Fechar” se isso fizer o rótulo anunciado divergir do texto visível.
Teste o painel com zoom de 200% e 400%, teclado na tela, orientação retrato e paisagem e largura equivalente a 320 pixels CSS. A navegação precisa rolar quando for maior que a viewport. O botão de fechar e o item focado não podem ficar sob um cabeçalho fixo.
Preserve destinos e comportamento sem JavaScript
Os links devem continuar apontando para URLs reais. JavaScript pode controlar a apresentação, mas não deve transformar destinos em href="#" ou depender de um listener para descobrir a rota.
Se o script falhar, uma navegação simples e expandida é melhor do que nenhum acesso às páginas. Defina o estado inicial no HTML e evite um intervalo em que o submenu aparece, recebe foco e some durante a hidratação.
Ao criar links internos, confirme barras finais, fragmentos e redirecionamentos no ambiente publicado. Marque aria-current a partir da rota real, não de uma comparação frágil que quebra com parâmetros ou normalização de URL.
Teste a navegação inteira
Não valide apenas o botão do menu. Percorra todos os destinos e estados:
| Situação | Evidência esperada |
|---|---|
primeira entrada com Tab |
foco aparece no primeiro controle lógico |
| submenu fechado | links internos não recebem foco nem leitura |
| abertura | botão e painel concordam sobre o estado |
Escape |
grupo fecha e foco volta ao controle |
| página atual | link usa aria-current="page" e indicação visual |
| toque e ponteiro | painel não fecha durante o deslocamento até os links |
| largura estreita | todos os destinos continuam visíveis e operáveis |
| JavaScript indisponível | links essenciais permanecem disponíveis |
Faça o percurso com teclado, toque, leitor de tela e ampliação. Um scanner encontra IDs duplicados e nomes ausentes. Só o teste manual mostra se a ordem é cansativa, se o painel cobre o foco ou se um submenu desaparece antes do clique.
Dê ao agente um pedido verificável
Revise os menus de navegação desta landing page sem publicar ainda.
Escopo:- fonte e commit: [referência]- rotas: [lista]- navegações e submenus: [inventário]
Para cada navegação:1. Diferencie links de navegação, disclosures e menus de aplicativo.2. Preserve nav, listas, links reais e a ordem do DOM.3. Use botões para abrir grupos e sincronize aria-expanded, aria-controls e hidden.4. Remova itens fechados da leitura e da ordem de foco.5. Implemente fechamento com Escape e retorno de foco quando aplicável.6. Marque a página atual com aria-current.7. Teste teclado, toque, leitor de tela, zoom, hover e JavaScript indisponível.8. Preserve URLs, analytics e lógica de negócio.
Entregue o inventário, o diff e as evidências antes de publicar.O escopo impede que uma revisão de acessibilidade vire uma troca completa do cabeçalho ou da arquitetura de informação.
Reteste a versão publicada
Depois da aprovação, siga a documentação de Publicação: publique uma nova Version, acompanhe o deploy e abra a URL final. Teste o menu em uma rota de cada nível, confirme o item atual e percorra todos os submenus.
Verifique também redirecionamentos, analytics, links externos e o menu depois da hidratação. Se a build deixar duas navegações acessíveis ao mesmo tempo ou separar aria-expanded da visibilidade, corrija a fonte e republique o mesmo Site. A navegação está pronta quando cada destino pode ser encontrado e ativado sem adivinhar o dispositivo ou o estado do menu.
