>
Construir um menu móvel progressivamente melhorado que funcione sem JavaScript
>
>
Última actualização em 21 de Janeiro de 2019.
>
Menu hamburguer CSS puro fora de tela não são uma descoberta recente. Afinal, Chris Coyier escreveu sobre esta técnica em novembro de 2012.
- Se este é um truque antigo para você, então fique comigo por um pouco. Eu melhorei o exemplo do Chris, e adoraria seu feedback.
- Se isto é novo para você, não se preocupe. Você tem muita companhia, pois parece que boa parte da web ainda não pegou.
Com isso, vamos construir um menu de hambúrgueres simples e ágil fora da tela usando apenas CSS que será fácil de incorporar ao seu próprio projeto. Mas primeiro…
O que há de errado com JavaScript?
Nada.
Aaron Gustafson explica a importância de Melhorias Progressivas e o papel do JavaScript no desenvolvimento web melhor do que eu jamais poderia fazer. Você deve ler o post dele. Mas por uma questão de brevidade, vou tentar resumir:
- “As tarefas principais podem sempre ser realizadas sem JavaScript”
- As tarefas principais devem ser feitas na camada mais estável (ou seja, não JavaScript).
- Aprimoramentos progressivos não é anti-JavaScript. Trata-se apenas de abraçar as tecnologias certas na camada certa.
- “Porque há alguma hipótese do JavaScript não correr, devemos sempre ter em conta essa hipótese.
- Nunca é uma boa ideia ignorar potenciais utilizadores.
- Aprimoramentos progressivos é apenas uma boa engenharia.
Então, vamos fazer o máximo que pudermos com HTML e CSS. Então faça o JavaScript fazer sua mágica em uma camada mais apropriada – melhorando a UI já existente.
Passo 1: HTML
Como você deve saber, o primeiro passo é sempre escrever um sólido, bem pensado, base-layer de HTML.
Nota: Estou usando Font Awesome para os ícones do meu exemplo.
Parece bastante padrão, certo? Nós temos:
- Nosso pai < cabeçalho> elemento
- Icone do hambúrguer (“fa-bars”)
- Um cabeçalho principal (ou potencialmente um logotipo)
- A navegação num <nav> elemento
- Icone de fecho (“fa-close”) dentro da navegação (mais adiante)
- Um “pano de fundo” após a navegação. Por que é uma etiqueta de âncora? Explicarei mais tarde.
Passo 2: Vamos torná-la mais acessível
A acessibilidade nunca deve ser um pensamento posterior – como depois de ter escrito a sua aplicação. Deve ser planeada desde o início. Adicionar agora algumas considerações básicas não só melhorará a acessibilidade geral do seu site, mas também lhe dará (ao desenvolvedor) uma melhor marcação para utilizar no seu JavaScript!
Com isso, vamos adicionar mais alguns atributos e algum texto somente para leitor de tela:
Aqui está a quebra rápida de todos esses atributos e como eles funcionam:
- Adicionamos IDs únicos para direcionar nossos HREFs (mais sobre como isso funciona mais tarde).
- Fornecemos uma etiqueta informativa dos botões para leitores de tela usando .
- Ocultámos os ícones dos leitores de tela com , porque são representações visuais, e adicionámos texto apenas para leitor de tela com os elementos <span class=”sr-only”>.
- Tiramos o “fundo” do índice de abas com um . É de natureza puramente visual e não queremos confundir os nossos utilizadores deficientes visuais e só de teclado.
- Adicionamos o atributo surpreendente para definir o estado inicial (e semântico) do “fundo”. Chega de lixo – que emocionante!
Aqui está o resultado até agora:
>
Passo 3: Vamos dar estilo!
Vamo-nos aproximar primeiro deste mobile-first, por isso vamos dar cabo do mobile, vista “hamburger-y” (a parte interessante).
Primeiro, vamos apenas obter o layout do cabeçalho (sem a interactividade):
O resultado:
Passo 4: Interatividade com CSS puro
Ao tornar os widgets interativos com CSS, você tem algumas opções:
- Utilizar rádios ou checkboxes
- Utilizar a :target pseudo-class.
Radios e checkboxes funcionam incrivelmente bem para a maioria dos widgets, como abas, modais, dropdowns e acordeões. Chris Coyier apelidou esta técnica de “a caixa de verificação hack”. Vários desenvolvedores têm usado este “hack” para seus menus off-canvas, como no tutorial de Paul Lewis para o Chrome Dev Summit ou no menu de hambúrgueres morphing do Luis Manuel.
No entanto, o :target pseudo-class é mais semântico neste caso de uso, já que estamos lidando diretamente com navegação. Você pode discordar, e isso é completamente ok! Seria incrivelmente fácil e perfeitamente aceitável trocar a pseudo-classe :target por uma caixa de seleção.
A qualquer uma das técnicas, no entanto, tem suas ressalvas.
Usando uma checkbox:
- Requer que o JavaScript feche o menu off-canvas se um dos links dentro do menu for um link de âncora para uma seção específica da mesma página.
- Requer que o campo <input> seja um irmão do menu ou pelo menos um irmão do antepassado do menu. Em outras palavras, o CSS é um pouco mais complicado. Você pode ter o elemento <label> (mesmo múltiplas etiquetas) em outro lugar, embora.
- O elemento <label> não será diretamente focalizável ou tabelável, requerendo algum CSS ligeiramente mais complicado para manipular o foco na caixa de seleção enquanto altera a aparência visível do elemento <label>.
- A navegação do teclado em torno da abertura/fechamento do menu será um pouco mais complicada. Afetar uma mudança de estado em uma caixa de seleção é feito através da tecla e não da tecla. Enquanto usuários cegos podem entender que o widget é operado por uma checkbox, usuários de teclados avistados ficarão confusos uma vez que a checkbox não é aparente – algo que eu senti que foi um quebra de contrato neste caso de uso.
Usando a :target pseudo-class:
- Adiciona a abertura/fechamento do menu off-canvas ao histórico do navegador (empurrando o hash para a barra de endereço). Será necessário JavaScript para executar Event.preventDefault() para evitar isso (e o salto potencialmente irritante para o topo da página).
E pode haver outras advertências que eu perdi. De qualquer forma, escolhendo qual técnica é tanto uma questão de preferência quanto de acordo com os requisitos do seu projeto. De qualquer forma, eu divaguei…
Aqui está a parte interativa do CSS:
O resultado quando clicado:
Como tudo isto funciona
Essencialmente, o :target pseudo-class dá-nos um novo “estado” para estilizar a navegação direccionada. Quando o menu principal tiver sido alvo (com seu hash adicionado à URL), podemos agora deslizar para fora do menu. É um pouco como uma pseudo-classe :focus para o elemento alvo (não o link em si).
Também permitimos que o “backgrounddrop” seja exibido quando a navegação é alvo.
Vai notar que o ícone do hambúrguer principal está ligado ao ID da navegação, enquanto ambos os botões close e backdrop estão ligados ao ícone do hambúrguer principal. Isto permite-nos clicar no ícone de fechar ou no fundo para remover o “focus” – ou realmente :target – da navegação. Se o pano de fundo não fosse um link, não seria clicável sem JavaScript.
Eu também acorrentei os seletores :target junto com o atributo no CSS. Este será, eventualmente, o lugar onde progressivamente melhoraremos o menu de hambúrgueres com JavaScript para não saltar para o cabeçalho quando clicado – evitando a ressalva que mencionei anteriormente. Tendo o JavaScript seqüestrado o comportamento do hash do navegador significa que a pseudo-classe :target não funcionará mais. Quando isso acontecer, vamos tirar vantagem do atributo para dar estilo à troca de valores verdadeiro/falso muito parecido com o que poderíamos ter no passado com classes.
No entanto, isso funciona muito bem sem JavaScript.
Adicionei a consulta @supports media para fornecer a posição preferida:CSS fixo aos navegadores (tanto móveis quanto desktop) que o suportam. Caso contrário, navegadores e dispositivos lame – estou olhando para você iOS – irá obter position:absolute.
Passo 5: Estilos de tela maior
Desde que não queremos que o menu hambúrguer para exibir para dispositivos não móveis (ou telas maiores em geral), vamos adicionar a consulta de mídia necessária para isso. Depois vamos estilizá-lo para parecer uma navegação horizontal:
O resultado:
Voila! Terminamos!
Pondo tudo junto
Aqui está o HTML final:
Aqui está o CSS final:
Demo
>
Execute o meu CodePen para si:
→ Menu de hambúrgueres CSS puro sem JavaScript.
Nota: você também pode fazer uma demonstração da versão de caixa de seleção do menu.
Deseja adicionar JavaScript para torná-lo mais inteligente?
Embora possamos fazer o menu off-canvas funcionar inteiramente com CSS – melhorando seu desempenho e confiabilidade – ainda precisaremos do JavaScript para ajudar de alguma forma a melhorar a interatividade em torno das quedas de qualquer uma das técnicas. Você também pode utilizar JavaScript para evitar a rolagem na página enquanto o menu estiver aberto.
É também digno de nota que um nível decente (e sem dúvida o nível mais importante) de acessibilidade pode ser alcançado sem JavaScript. Entretanto, é difícil fornecer um nível robusto de acessibilidade sem a capacidade do JavaScript de manipular o DOM (por exemplo, gerenciamento de foco, atualizações de atributos ARIA, etc.).
Para mais informações sobre como melhorar a acessibilidade do seu website através do JavaScript, consulte os seguintes artigos:
- Utilizar atributos ARIA para configuração de estado JavaScript & Estilo
- Escrever JavaScript com a acessibilidade em mente
Dar outras ideias ou sugestões?
Adorava ouvir os seus comentários com a minha abordagem a um menu de hambúrgueres CSS puro.
>
Editar e ruminações posteriores
Janeiro 21, 2019: Artigo editado e exemplos de código atualizados para remover atributos ARIA desnecessários e melhorar a acessibilidade.
Como aprendi mais sobre o uso de ARIA e desenvolvimento &Testes de acessibilidade em geral, eu percebi algumas coisas:
- JavaScript definitivamente tem o seu lugar, e deve fazer parte de qualquer padrão robusto de acessibilidade UI.
- Exceto para pontos de referência ARIA, JavaScript é necessário para usar ARIA corretamente. E, muitos dos atributos que usei, como por exemplo, são melhor deixar o JavaScript para adicionar uma vez carregado em vez de adicioná-lo diretamente no markup. Este conceito segue boas práticas de melhoria progressiva – estados e propriedades ARIA juntamente com o JavaScript são uma melhoria e devem ser tratados em uma camada separada.
- Anteriormente, eu não lidei com o foco corretamente, pois o foco desapareceria à medida que ele progredia através dos links visualmente ocultos (quando colapsado). Eu adicionei um display: none; ao menu CSS para corrigir isto.
Então, se você implementou uma versão anterior do meu Puro CSS Off-Canvas Hamburger Menu, por favor considere atualizá-lo para esta versão mais simples e acessível!