Flexbox é perfeito para navegação responsiva
Flexbox é um módulo de layout versátil com o qual podemos criar layouts unidimensionais que requerem flexibilidade, como menus responsivos. Usando as propriedades de ordenação, alinhamento e dimensionamento do flexbox, podemos construir barras de navegação que adaptam seus layouts ao tamanho da janela de visualização, mantendo o contorno HTML lógico e acessível.
Neste tutorial, veremos como criar uma barra de navegação responsiva com flexbox. Nossa navegação flexbox terá três layouts diferentes, dependendo do tamanho da janela de visualização:
- a layout móvel em que apenas o logotipo e um botão de alternância estarão visíveis por padrão e os usuários podem abrir e fechar o menu usando o botão de alternância,
- a layout de tablet no qual mostraremos dois botões de call to action entre o logotipo e a alternância no estado padrão e o resto do menu permanecerá alternável,
- a layout da área de trabalho em que todos os itens do menu, exceto o botão de alternância, ficarão visíveis na tela.
Usaremos consultas de mídia para detectar o tamanho da janela de visualização do navegador do usuário. Nossa barra de navegação responsiva priorizará os dispositivos móveis, portanto, criaremos primeiro o layout para dispositivos móveis. Em seguida, adicionaremos o CSS específico para tablet e desktop usando min-width
consultas de mídia.
A barra de navegação também terá um submenu suspenso baseado em JavaScript que abre e fecha quando o usuário clica no item do menu pai.
Veja como ficará o menu no celular:
Aqui está a versão para tablet:
E é assim que ficará no desktop:
Você também pode testar, bifurcar e brincar com a demonstração interativa no CodePen:
Novo no Flexbox?
Se você não está acostumado com o flexbox ou precisa de uma atualização, estes guias para iniciantes lhe darão todas as habilidades necessárias para concluir este tutorial:
1. Crie o HTML
O HTML é um simples
- lista, como você pode ver abaixo. O
- class="logo"> href="#">Creative Mind Agency
- class="item"> href="#">Home
- class="item"> href="#">About
- class="item has-submenu">
- class="subitem"> href="#">Design
- class="subitem"> href="#">Development
- class="subitem"> href="#">SEO
- class="subitem"> href="#">Copywriting
- class="item has-submenu">
- class="subitem"> href="#">Freelancer
- class="subitem"> href="#">Startup
- class="subitem"> href="#">Enterprise
- class="item"> href="#">Blog
- class="item"> href="#">Contact
- class="item button"> href="#">Log In
- class="item button secondary"> href="#">Sign Up
- class="toggle"> href="#"> class="fas fa-bars">
-
.logo
recebe oorder: 0;
valor, pois será o primeiro item (no entanto, como este é o valor padrão deorder
não precisamos adicioná-lo ao CSS), -
.toggle
recebe1
como vem logo depois.logo
, -
.item.button
pertencente ao Conecte-se e Inscrever-se botões obtém2
, - e
.item
pertencente ao restante dos itens do menu fica3
. -
Primeiro, selecionamos o menu e o botão de alternância usando o
querySelector()
método para que possamos acessá-los com JavaScript. - Em seguida, adicionamos o personalizado
toggleMenu()
função que será chamada quando o botão de alternância for clicado. - Por último, adicionamos o ouvinte de evento que ouvirá o evento click usando o comando
addEventListener()
método. - Primeiro, selecionamos todos os itens do menu com o
querySelectorAll()
método que retorna uma lista de nós (em vez de um único elemento comoquerySelector()
). - No costume
toggleItem()
função, adicionamos e removemos.submenu-active
de/para o elemento clicado. Observe que noelse if
bloco, removemos a classe de todos os outros itens de menu que foram abertos anteriormente. Desta forma, não acontecerá que dois submenus fiquem abertos ao mesmo tempo, pois eles podem se sobrepor no desktop. - Finalmente, percorremos o
items
classList usando umfor...of
laço. Dentro doif
bloco, adicionamos dois ouvintes de eventos aos itens de menu que possuem um submenu: um para oclick
evento para usuários regulares que acessam o menu clicando ou tocando, e um para okeypress
evento para usuários de teclado. - mudar o
order
dos itens de menu para adaptar o layout às viewports do tablet, - realinhar os itens (veja a explicação abaixo),
- faça o Conecte-se e Inscrever-se os botões parecem botões reais (no layout móvel, parecem links, pois fazem parte da lista suspensa alternável).
.menu
class será o flex container e os itens da lista serão os flex items. A ordem deles se adaptará ao tamanho da janela de visualização do dispositivo do usuário. Por exemplo, o Conecte-se e Inscrever-se os botões virão primeiro no celular, mas serão exibidos no final do menu no desktop. Conseguiremos esse efeito fazendo uso das propriedades de ordenação do flexbox.
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
tabindex="0">Services
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
tabindex="0">Plans
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 |
|
Você provavelmente já percebeu que os itens de menu com submenu (“Serviços” e “Planos”) têm um etiqueta sem um
href
atributo. Fazemos isso porque esses itens “vazios” do menu pai não levam a nenhuma outra página – eles apenas abrem e fecham o submenu. O uso da tag âncora sem href é permitido e evita que a página salte em telas pequenas quando o usuário clica no item de menu vazio para abrir ou fechar o submenu.
Também adicionamos o tabindex="0"
atribuir a elementos sem
href
atributo. Isso ocorre porque vazio tags são omitidas da ordem de tabulação padrão, então precisamos colocá-las de volta na ordem de tabulação com o
tabindex
atributo para manter o menu acessível pelo teclado.
Observação: o botão de alternância no final da lista usa um ícone Font Awesome. Para fazer a demonstração funcionar, você precisará adicionar a biblioteca Font Awesome ao seção do documento HTML do CDN usando o código abaixo. (Se quiser fazer o menu funcionar offline, você precisará hospedar o Font Awesome localmente.)
1 |
rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.13.0/css/all.min.css">
|
2. Adicione algum estilo básico
Para o estilo básico, defini alguns valores e cores padrão, mas você também pode usar qualquer uma de suas próprias regras de estilo:
1 |
/* Basic styling */
|
2 |
* { |
3 |
box-sizing: border-box; |
4 |
padding: 0; |
5 |
margin: 0; |
6 |
}
|
7 |
body { |
8 |
font-family: sans-serif; |
9 |
font-size: 16px; |
10 |
}
|
11 |
nav { |
12 |
background: #222; |
13 |
padding: 0 15px; |
14 |
}
|
15 |
a { |
16 |
color: white; |
17 |
text-decoration: none; |
18 |
}
|
19 |
.menu, |
20 |
.submenu { |
21 |
list-style-type: none; |
22 |
}
|
23 |
.logo { |
24 |
font-size: 20px; |
25 |
padding: 7.5px 10px 7.5px 0; |
26 |
}
|
27 |
.item { |
28 |
padding: 10px; |
29 |
}
|
30 |
.item.button { |
31 |
padding: 9px 5px; |
32 |
}
|
33 |
.item:not(.button) a:hover, |
34 |
.item a:hover::after { |
35 |
color: #ccc; |
36 |
}
|
3. Comece com a navegação móvel
Como nossa navegação priorizará os dispositivos móveis, começamos com o layout móvel. A maioria dos menus flexbox responsivos usam layouts baseados em colunas para dispositivos móveis, já que os itens de menu podem ser rapidamente compactados uns abaixo dos outros adicionando o flex-direction: column;
regra para o contêiner flexível. Embora esta seja uma solução excelente, não a usaremos em nosso exemplo.
Em vez disso, criaremos um layout baseado em linhas para dispositivos móveis, para que possamos exibir o logotipo e o botão de alternância um ao lado do outro na parte superior do menu.
O truque do CSS aqui é criar itens de menu regulares, como Lar e Sobre abranger todo o contêiner usando o width: 100%;
regra. Portanto, o flexbox irá exibi-los um abaixo do outro, enquanto o logotipo e o botão de alternância manterão seus tamanhos naturais e ficarão no topo da barra de navegação na mesma linha.
No CSS abaixo, também usamos o justify-content
e align-items
propriedades para alinhar os itens flexíveis horizontalmente e verticalmente. Além disso, escondemos o .item
elementos usando o display: none;
regra. Os itens do menu só serão revelados quando o usuário clicar no botão de alternância. O .active
classe não estiver no código HTML, iremos adicioná-la dinamicamente com JavaScript.
1 |
/* Mobile menu */
|
2 |
.menu { |
3 |
display: flex; |
4 |
flex-wrap: wrap; |
5 |
justify-content: space-between; |
6 |
align-items: center; |
7 |
}
|
8 |
.menu li a { |
9 |
display: block; |
10 |
padding: 15px 5px; |
11 |
}
|
12 |
.menu li.subitem a { |
13 |
padding: 15px; |
14 |
}
|
15 |
.toggle { |
16 |
order: 1; |
17 |
font-size: 20px; |
18 |
}
|
19 |
.item.button { |
20 |
order: 2; |
21 |
}
|
22 |
.item { |
23 |
order: 3; |
24 |
width: 100%; |
25 |
text-align: center; |
26 |
display: none; |
27 |
}
|
28 |
.active .item { |
29 |
display: block; |
30 |
}
|
31 |
.button.secondary { /* divider between buttons and menu links */ |
32 |
border-bottom: 1px #444 solid; |
33 |
}
|
Como você pode ver acima, também alteramos a ordem dos itens do menu com a ajuda do order
propriedade. Nosso esboço HTML segue uma ordem lógica. É assim que queremos que usuários de leitores de tela e bots de mecanismos de pesquisa percorram o menu.
Porém, no layout mobile, queremos mostrar o logotipo e o botão de alternância na parte superior do menu. Também queremos exibir os dois botões de call to action (“Log In” e “Sign Up”) antes dos itens normais do menu. Então, montamos a seguinte ordem:
4. Estilize o submenu
Como esta é uma navegação que prioriza os dispositivos móveis, estilizaremos o submenu principalmente com as telas dos dispositivos móveis em mente. Esta é uma ótima técnica, pois geralmente é mais difícil criar um submenu amigável para telas pequenas do que para telas maiores. Então, também podemos usar o mesmo layout de submenu para telas de tablets. Para desktop, precisaremos apenas alterar o posicionamento do submenu.
Por padrão, o submenu está definido como display: none;
e só será revelado quando o usuário clicar no item do menu pai. Adicionaremos a funcionalidade JavaScript necessária nas próximas duas etapas antes de passar para o menu do tablet.
1 |
/* Submenu up from mobile screens */
|
2 |
.submenu { |
3 |
display: none; |
4 |
}
|
5 |
.submenu-active .submenu { |
6 |
display: block; |
7 |
}
|
8 |
.has-submenu i { |
9 |
font-size: 12px; |
10 |
}
|
11 |
.has-submenu > a::after { |
12 |
font-family: "Font Awesome 5 Free"; |
13 |
font-size: 12px; |
14 |
line-height: 16px; |
15 |
font-weight: 900; |
16 |
content: "\f078"; |
17 |
color: white; |
18 |
padding-left: 5px; |
19 |
}
|
20 |
.subitem a { |
21 |
padding: 10px 15px; |
22 |
}
|
23 |
.submenu-active { |
24 |
background-color: #111; |
25 |
border-radius: 3px; |
26 |
}
|
Como você pode ver acima, agora adicionamos os ícones Font Awesome usando CSS em vez de HTML. Esses ícones que adicionamos usando o ::after
O pseudoelemento serão as pequenas setas para baixo mostradas ao lado de cada item de menu que possui um submenu.
Se você se lembra, adicionamos o ícone Font Awesome para o botão de alternância com HTML na Etapa 1. Isso ocorre porque o botão de alternância será direcionado para JavaScript, portanto, deve estar presente no DOM. No entanto, as setas para baixo aqui são apenas elementos de estilo que indicam a presença do submenu. Como nenhuma funcionalidade depende deles, é melhor adicioná-los com CSS.
5. Adicione a funcionalidade de alternância com JavaScript
Configuraremos a funcionalidade de alternância adicionando um ouvinte de evento de clique ao botão de alternância que abre e fecha o menu no celular. No código JavaScript, usaremos a sintaxe ES6 que nos dá acesso ao const
e let
notação e o for...of
loop e já possui um bom suporte ao navegador.
Para o JavaScript personalizado, crie um vazio script.js
arquivo e adicione-o ao HTML antes do fechamento marcação:
1 |
|
E aqui está o código JavaSript responsável pela funcionalidade de alternância:
1 |
const toggle = document.querySelector(".toggle"); |
2 |
const menu = document.querySelector(".menu"); |
3 |
|
4 |
/* Toggle mobile menu */
|
5 |
function toggleMenu() { |
6 |
if (menu.classList.contains("active")) { |
7 |
menu.classList.remove("active"); |
8 |
|
9 |
// adds the menu (hamburger) icon
|
10 |
toggle.querySelector("a").innerHTML = ""; |
11 |
} else { |
12 |
menu.classList.add("active"); |
13 |
|
14 |
// adds the close (x) icon
|
15 |
toggle.querySelector("a").innerHTML = ""; |
16 |
}
|
17 |
}
|
18 |
|
19 |
/* Event Listener */
|
20 |
toggle.addEventListener("click", toggleMenu, false); |
6. Adicione a funcionalidade suspensa com JavaScript
Agora, quando o usuário clica no botão de alternância, o menu é ativado e desativado, porém o submenu ainda fica oculto. Adicionaremos esta funcionalidade com o seguinte JavaScript:
1 |
const items = document.querySelectorAll(".item"); |
2 |
|
3 |
/* Activate Submenu */
|
4 |
function toggleItem() { |
5 |
if (this.classList.contains("submenu-active")) { |
6 |
this.classList.remove("submenu-active"); |
7 |
} else if (menu.querySelector(".submenu-active")) { |
8 |
menu.querySelector(".submenu-active").classList.remove("submenu-active"); |
9 |
this.classList.add("submenu-active"); |
10 |
} else { |
11 |
this.classList.add("submenu-active"); |
12 |
}
|
13 |
}
|
14 |
|
15 |
/* Event Listeners */
|
16 |
for (let item of items) { |
17 |
if (item.querySelector(".submenu")) { |
18 |
item.addEventListener("click", toggleItem, false); |
19 |
item.addEventListener("keypress", toggleItem, false); |
20 |
}
|
21 |
}
|
Aqui, adicionamos o .submenu-active
classe para cada item do menu com um submenu quando o usuário clica nele.
7. Crie o menu do tablet
Criaremos o layout do tablet usando um min-width
consulta de mídia. No tablet, quatro itens de menu estarão visíveis por padrão: o logotipo, os dois botões de call to action (“Login” e “Cadastre-se”) e o botão de alternância. Para deixar tudo bonito, nosso CSS irá:
Em código:
1 |
/* Tablet menu */
|
2 |
@media all and (min-width: 700px) { |
3 |
.menu { |
4 |
justify-content: center; |
5 |
}
|
6 |
.logo { |
7 |
flex: 1; |
8 |
}
|
9 |
.item.button { |
10 |
width: auto; |
11 |
order: 1; |
12 |
display: block; |
13 |
}
|
14 |
.toggle { |
15 |
flex: 1; |
16 |
text-align: right; |
17 |
order: 2; |
18 |
}
|
19 |
/* Button up from tablet screen */
|
20 |
.menu li.button a { |
21 |
padding: 10px 15px; |
22 |
margin: 5px 0; |
23 |
}
|
24 |
.button a { |
25 |
background: #0080ff; |
26 |
border: 1px royalblue solid; |
27 |
}
|
28 |
.button.secondary { |
29 |
border: 0; |
30 |
}
|
31 |
.button.secondary a { |
32 |
background: transparent; |
33 |
border: 1px #0080ff solid; |
34 |
}
|
35 |
.button a:hover { |
36 |
text-decoration: none; |
37 |
}
|
38 |
.button:not(.secondary) a:hover { |
39 |
background: royalblue; |
40 |
border-color: darkblue; |
41 |
}
|
42 |
}
|
No layout do tablet, os itens de menu são alinhados de maneira diferente. Se você der uma olhada nos quatro itens de menu visíveis, verá que os dois botões são exibidos no centro, enquanto o logotipo e o botão de alternância são empurrados para a extremidade esquerda e direita do contêiner:
Podemos conseguir esse efeito usando o flex: 1;
Regra CSS. O flex
propriedade é uma abreviatura para flex-grow
, flex-shrink
e flex-basis
. Pode existir com muitas combinações de valores diferentes. Quando é declarado com apenas um valor, pertence a flex-grow
com flex-shrink
e flex-basis
mantendo seus valores padrão.
No CSS acima, adicionamos o flex: 1;
regra para o .logo
e .toggle
elementos. Desta forma, podemos dizer ao navegador que se houver algum espaço positivo na tela, queremos compartilhá-lo entre estes dois elementos. Enquanto o Conecte-se e Inscrever-se botões mantêm seu padrão 0
valor para flex-grow
, eles não receberão nada do espaço extra. Assim, eles ficarão no centro do recipiente, pois aderem ao justify-content: center;
regra definida no contêiner flexível.
8. Crie o menu da área de trabalho
O menu da área de trabalho oculta a alternância, restaura a ordem original e a largura natural de cada item e reposiciona o submenu.
É importante ter em mente que as regras específicas do tablet também se aplicam ao menu do desktop. Isso ocorre porque aqui a largura da janela de visualização é maior que ambas 700px
e 960px
, para que ambas as consultas de mídia tenham efeito. Então, .logo
mantém a sua flex: 1;
propriedade e empurra o restante dos itens para o final do contêiner.
1 |
/* Desktop menu */
|
2 |
@media all and (min-width: 960px) { |
3 |
.menu { |
4 |
align-items: flex-start; |
5 |
flex-wrap: nowrap; |
6 |
background: none; |
7 |
}
|
8 |
.logo { |
9 |
order: 0; |
10 |
}
|
11 |
.item { |
12 |
order: 1; |
13 |
position: relative; |
14 |
display: block; |
15 |
width: auto; |
16 |
}
|
17 |
.button { |
18 |
order: 2; |
19 |
}
|
20 |
.submenu-active .submenu { |
21 |
display: block; |
22 |
position: absolute; |
23 |
left: 0; |
24 |
top: 68px; |
25 |
background: #111; |
26 |
}
|
27 |
.toggle { |
28 |
display: none; |
29 |
}
|
30 |
.submenu-active { |
31 |
border-radius: 0; |
32 |
}
|
33 |
}
|
9. Permita que os usuários fechem o submenu clicando em qualquer lugar da página
Agora há apenas um passo para trás. Como o menu suspenso é ativado no evento de clique, ele não fecha automaticamente quando o usuário passa o mouse fora do item de menu superior. Isso é especialmente irritante na área de trabalho, onde o menu suspenso pode cobrir o conteúdo.
Portanto, seria bom permitir que os usuários fechassem o submenu clicando em qualquer lugar da tela. Podemos adicionar o recurso com JavaScript:
1 |
/* Close Submenu From Anywhere */
|
2 |
function closeSubmenu(e) { |
3 |
if (menu.querySelector(".submenu-active")) { |
4 |
let isClickInside = menu |
5 |
.querySelector(".submenu-active") |
6 |
.contains(e.target); |
7 |
|
8 |
if (!isClickInside && menu.querySelector(".submenu-active")) { |
9 |
menu.querySelector(".submenu-active").classList.remove("submenu-active"); |
10 |
}
|
11 |
}
|
12 |
}
|
13 |
|
14 |
/* Event listener */
|
15 |
document.addEventListener("click", closeSubmenu, false); |
O costume closeSubmenu()
A função verifica se há algum submenu aberto na tela e, se sim, também verifica se o usuário clicou dentro dele com a ajuda do target
propriedade. Se o usuário clicar em qualquer outro lugar da tela, o .submenu-active
a classe será removida e o submenu será fechado. Adicionamos o ouvinte de evento ao document
objeto, pois queremos ouvir cliques em toda a página.
Você construiu uma barra de navegação responsiva com Flexbox e JavaScript!
Nossa barra de navegação responsiva e voltada para dispositivos móveis está instalada e funcionando em três layouts diferentes.
Aqui está um lembrete do resultado final:
Flexbox é uma ótima ferramenta para implementar layouts complexos sem quaisquer ajustes. Se você combinar as propriedades de alinhamento, ordenação e dimensionamento do flexbox com consultas de mídia, poderá criar layouts diferentes para diferentes viewports sem precisar manipular o código-fonte HTML.
Recursos úteis
Para obter uma lista de práticas recomendadas que você deve considerar ao criar uma navegação responsiva ou se precisar de ajuda para começar a usar ouvintes de eventos em JavaScript, dê uma olhada nestes guias para iniciantes:
Por último, se você estiver interessado em como usar o flexbox em seu trabalho diário, dê uma olhada nestes outros tutoriais práticos – cada um ajuda você a aprender construindo coisas que você pode realmente usar: