Artigo original: How to build a responsive navbar with a toggle menu using Flexbox
Escrito por: Charlie Waite
Durante um projeto recente, minha equipe teve que remover todos os vestígios do Bootstrap. Isso significou que a barra de navegação responsiva, extremamente útil, teve que ser criada do zero. Eu sou relativamente novo em CSS, tendo sempre confiado nas navbars do Bootstrap pela sua simplicidade. Então, me ofereci para assumir essa tarefa. Aqui está o que aprendi e fiz ao longo do processo.
Neste artigo, vou assumir que você tem conhecimento básico de HTML, CSS e JavaScript — sabe como vincular uma folha de estilo ao HTML ou aplicar os estilos em uma tag <style>
— e que sabe como importar um arquivo de JavaScript para sua página.
Já vi elitistas se defendendo por meio de críticas ao meu jeito de fazer as coisas, em especial pelo fato de usar position: absolute
para o menu de sanduíche — se tiver maneiras melhores de fazer isso, fique à vontade para publicar sua solução. Juntos, podemos ajudar milhares de pessoas que leem estes artigos!
Introdução
Primeiro, comecei com o HTML básico para fazer o layout:
<div class="Navbar">
<div class="Navbar__Link Navbar__Link-brand">
Website title
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
</div>
Você pode usar a convenção de nomes que quiser para as classes.

Bem, não estamos vendo muita coisa aqui ainda. Essa é apenas uma lista de itens simples. Porém, com apenas uma linha de CSS, vemos o poder do Flexbox.
.Navbar {
display: flex;
}

Uma linha de código e já temos nossos itens de navegação alinhados horizontalmente na parte superior da página.
Agora, vamos adicionar dois elementos nav
ao nosso HTML para termos alguns itens à esquerda e à direita da navbar:
<div class="Navbar">
<nav class="Navbar__Items">
<div class="Navbar__Link Navbar__Link-brand">
Website title
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
<nav class="Navbar__Items Navbar__Items--right">
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
</div>
Vamos fazer também a estilização básica de nossa classe Navbar
, que envolve todos os outros elementos:
.Navbar {
background-color: #46ACC2;
display: flex;
padding: 16px;
font-family: sans-serif;
color: white;
}
Você, logicamente, pode escolher seu próprio esquema de cores, fontes e preenchimento (do inglês, padding).
Nossa navbar, de momento, terá esta aparência:

É... já parece um pouco melhor, mas não podemos deixar nossos itens de navegação serem exibidos na vertical. Antes de seguir lendo, tente adivinhar o que faremos a seguir…
Agora, a propriedade display:flex
da classe .Navbar
já não está mais responsável por esses itens. Eles são responsabilidade dos contêineres <nav>
. Queremos que os dois estejam alinhados na horizontal.
Desse modo, alteramos a classe .Navbar__Items
também:
.Navbar__Items {
display:flex;
}
Em seguida, vamos adicionar preenchimento aos nossos links para deixar tudo um pouco mais bonito:
.Navbar__Link {
padding-right: 8px;
}
A aparência da navbar, agora, é esta:

Estamos chegando lá. No entanto, também queremos que o segundo elemento <nav>
esteja alinhado à direita. Como você deve ter percebido, adicionei uma classe a mais ao segundo elemento <nav>
, .Navbar__Items--right
.
Vamos apenas adicionar um atributo margin-left:auto
a essa classe:
.Navbar__Items--right {
margin-left:auto;
}


Como você pode ver, parece bem melhor. Já temos uma navbar totalmente responsiva. O que aconteceria, contudo, se cada item de navegação tivesse um texto maior? O que aconteceria se tivéssemos mais itens?

Como podem ver, não é isso que queremos. Queremos deixar todos os itens de navegação em uma única linha, para manter a consistência, ou que eles fossem escondidos em um menu que o usuário pudesse abrir e fechar.
Vamos usar a segunda opção, pois é um estilo muito mais limpo – e não teremos que nos preocupar com o usuário lutando para ler o texto em cada item de navegação.
flex-direction
Com um item que tenha display:flex;
, também há uma regra para a direção na qual queremos que os itens estejam orientados. Como padrão, é ao longo de uma linha (em inglês, row), o que alinha todos os itens ao longo do eixo x.
Em nosso caso, queremos um menu vertical pequeno na parte superior da página. Vamos tentar alterar isso usando flex-direction
nos dois elementos .Navbar
e dando a .Navbar__Items
o valor de column
— isso alinhará todos os itens de menu ao longo do eixo y — sempre que a largura da tela for 768px ou menos.
Vamos, também, remover aquele margin-left
do segundo elemento <nav>
:
@media only screen and (max-width: 768px) {
.Navbar__Items,
.Navbar {
flex-direction: column;
}
.Navbar__Items--right {
margin-left: 0;
}
}

Agora, contudo, os itens de navegação estão sempre visíveis, o que toma uma quantidade significativa de espaço em tela.
Em nossa media query, vamos adicionar uma segunda regra para .Navbar__Items
, de maneira que não fiquem visíveis:
@media only screen and (max-width: 768px) {
.Navbar__Items,
.Navbar {
flex-direction: column;
}
.Navbar__Items {
display:none;
}
.Navbar__Items--right {
margin-left:0;
}
}

O botão para abrir/fechar o menu
Para o botão de abrir/fechar o menu, usarei um ícone fornecido pelo Font Awesome. Se decidir fazer o mesmo, basta seguir as instruções no site deles para integrar os ícones ao seu projeto. Você pode usar qualquer conjunto de ícones que quiser, ou até texto simples, se isso for o que você quer.
Vamos adicionar esse ícone ao HTML:
<div class="Navbar">
<div class="Navbar__Link Navbar__Link-brand">
Website title
</div>
<div class="Navbar__Link Navbar__Link-toggle">
<i class="fas fa-bars"></i>
</div>
<nav class="Navbar__Items">
<div class="Navbar__Link">
Longer Link
</div>
<div class="Navbar__Link">
Longer Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
<nav class="Navbar__Items Navbar__Items--right">
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
</div>
A inclusão é a linha que diz <i class="fas fa-bars"></i>
. Você perceberá que o ícone não vai dentro de nenhuma das tags nav
, ficando fora, juntamente com o título do site. Isso é algo que faz sentido.

Claro que não é o local onde queremos que ele esteja. Pior ainda, ele está visível em resoluções para desktop.

Vamos consertar isso. Vamos fazer o que fizemos com os .Navbar__Items
nas resoluções para dispositivos móveis. Desta vez, faremos isso com o ícone de menu nas resoluções para desktop:
.Navbar__Link-toggle {
display: none;
}
Em seguida, vamos adicionar algumas regras para a mesma classe dentro de nossa media query:
.Navbar__Link-toggle {
align-self: flex-end;
display: initial;
position: absolute;
cursor: pointer;
}

Estamos praticamente prontos. Já temos a aparência desejada. Precisamos apenas adicionar a funcionalidade de abrir e fechar o menu ao ícone.
No JavaScript, adicione o seguinte:
function classToggle() {
const navs = document.querySelectorAll('.Navbar__Items')
navs.forEach(nav => nav.classList.toggle('Navbar__ToggleShow'));
}
document.querySelector('.Navbar__Link-toggle')
.addEventListener('click', classToggle);
Por fim, adicione Navbar__ToggleShow
com a regra display:flex
à media query.
Pronto! Temos uma navbar totalmente responsiva com um menu que abre e fecha. Usando o Flexbox, fica muito simples!

Versão final
HTML:
<div class="Navbar">
<div class="Navbar__Link Navbar__Link-brand">
Website title
</div>
<div class="Navbar__Link Navbar__Link-toggle">
<i class="fas fa-bars"></i>
</div>
<nav class="Navbar__Items">
<div class="Navbar__Link">
Longer Link
</div>
<div class="Navbar__Link">
Longer Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
<nav class="Navbar__Items Navbar__Items--right">
<div class="Navbar__Link">
Link
</div>
<div class="Navbar__Link">
Link
</div>
</nav>
</div>
CSS:
.Navbar {
background-color: #46ACC2;
display: flex;
padding: 16px;
font-family: sans-serif;
color: white;
}
.Navbar__Link {
padding-right: 8px;
}
.Navbar__Items {
display: flex;
}
.Navbar__Items--right {
margin-left:auto;
}
.Navbar__Link-toggle {
display: none;
}
@media only screen and (max-width: 768px) {
.Navbar__Items,
.Navbar {
flex-direction: column;
}
.Navbar__Items {
display:none;
}
.Navbar__Items--right {
margin-left:0;
}
.Navbar__ToggleShow {
display: flex;
}
.Navbar__Link-toggle {
align-self: flex-end;
display: initial;
position: absolute;
cursor: pointer;
}
}
JavaScript:
function classToggle() {
const navs = document.querySelectorAll('.Navbar__Items')
navs.forEach(nav => nav.classList.toggle('Navbar__ToggleShow'));
}
document.querySelector('.Navbar__Link-toggle')
.addEventListener('click', classToggle);
Você pode ler mais sobre o Flexbox na MDN:
Você também pode consultar o local onde eu mesmo aprendi sobre o básico do Flexbox (texto em inglês):
Learn CSS Flexbox in this FREE and interactive tutorial
Siga o autor no GitHub.