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.