Categorias
Projetos

Como fazer menu dropdown com CSS puro

Existem diversas técnicas para fazer um menu dropdown; neste artigo mostramos como fazer um menu dropdown com CSS puro!

É bastante comum, quando o assunto é interfaces, a necessidade de se criar um menu dropdown. Menus dropdown são componentes de UI bastante usados, justamente por serem tão úteis.

Existem os dropdown dos mais simples, aos mais complexos; independentemente de qual seja o caso, alguns princípios básicos podem ser usados para seu desenvolvimento.

Neste tutorial, mostramos como fazer um dropdown menu com CSS puro através de técnicas comuns do dia-a-dia, que permitem alcançar o resultado final bem facilmente.

Mostraremos os pontos-chave para conseguir o efeito. Para todos os passos, assista ao vídeo acima; para acessar o código completo, acesse o código completo no repo do projeto.

Semanticamente, é correto afirmar (na maioria dos casos) que um menu dropdown é um submenu aninhado em outro menu.

Algumas observações preliminares:

  • Será usado como base o BFB (códigos de estilos em Sass)
  • Convenções de nome com BEM
  • Também, Namespaces CSS
  • Tema do menu fictício (e divertido)

Se você acompanha nossos tutoriais aqui no blog e no canal YouTube, já deve estar acostumado a essas tecnologias/convenções.

Então, a estrutura desse dropdown menu não precisa ser mais complexa que:

<ul class="c-dropdown">
<li class="c-dropdown__item">
<a href="#" class="c-dropdown__link">In&iacute;cio</a>
</li>
<li class="c-dropdown__item">
<span class="c-dropdown__item-title">Melhores animes</span>
<ul class="c-dropdown__submenu">
<li class="c-dropdown__submenu-item">
<a href="#" class="c-dropdown__submenu-link">Shingeki no Kyojin</a>
</li>
<li class="c-dropdown__submenu-item">
<a href="#" class="c-dropdown__submenu-link">Bleach</a>
</li>
<li class="c-dropdown__submenu-item">
<a href="#" class="c-dropdown__submenu-link">Saint Seiya</a>
</li>
</ul>
</li>
<li class="c-dropdown__item">
<a href="#" class="c-dropdown__link">Contato</a>
</li>
</ul>

Como é possível ver, há um <ul> primário, com seus itens; então, o item que contém o dropdown também recebe um <ul> aninhado.

Uma marcação semanticamente correta, limpa e simples de ser feita. :)

Dentro de uma arquitetura SMACSS usando Sass (como é o caso do BFB), conta-se com a liberdade de separar os arquivos de estilo para um organização mais profissional.

Pelos nomes de classes usados, já é possível notar que, neste exemplo de dropdown, tudo será feito em somente um arquivo de estilo.

Entretanto, se for de sua preferência, c-dropdown__submenu poderia muito bem, ao invés de Elemento do Bloco “dropdown”, um Elemento à parte.

A estrutura geral do estilo é:

$component-name: "c-dropdown";
.#{$component-name} {
display: flex;
list-style: none;
margin: 0;
padding: 0;
&__item {
// ...
}
&__link {
// ...
}
&__submenu {
// ...
}
}

Inicialmente, “item” ficaria assim:

&__item {
color: var(--color-dpw-primary);
margin: 0 rem(10);
position: relative;
}

Quer dizer, de cor azul (--color-dpw-primary é uma variável já presente no BFB), com pequena margem entre cada item.

Uma observação importante para quem ainda não viu o BFB: rem() converte o valor informado para a unidade de medida CSS rem.

Os links de primeiro nível:

&__link {
color: var(--color-dpw-primary);
text-decoration: none;
&:hover {
text-decoration: underline;
}
}

Repetição do mesmo azul (para consistência visual) e efeitinho de sublinhado quando no :hover.

O submenu

Agora, o submenu, em si, inicialmente recebe seus estilos-base:

&__submenu {
background-color: var(--color-dpw-primary);
border-radius: $global-radius;
left: 50%;
list-style: none;
margin: 0;
opacity: 0.25;
padding: $global-module-size / 2;
position: absolute;
top: calc(100% + 10px);
transform-origin: top center;
transform: translateX(-50%) rotateX(-90deg);
transition: all $transition-duration-fast 125ms ease-in;
width: rem(200);
}

Para quem ainda não conhece o BFB, $global-module-size é uma variável Sass que guarda o valor rem(30), o que significa que o padding informado é o equivalente a 15px. $global-radius guarda o valor rem(6).

Talvez o que mais chame a atenção seja transform: translateX(-50%) rotateX(-90deg). Nesta técnica de menu dropdown com CSS puro, este é um ponto-chave.

O que se está fazendo é rotacionando o menu somente no eixo X (rotateX), parecendo que ele “desapareceu”, quando, na verdade, está ali, mas parece invisível devido a sua rotação.

Outro ponto bem interessante é o 3º parâmetro de transition, que indica um delay. Ele garante que o dropdown não apareça instantaneamente no hover, mas somente depois de 125ms, para a pessoa não o acionar por acidente.

E como fazer para ele “aparecer”? Um menu dropdown aparece com hover (ou clique) no item ancestral; no caso deste, é com hover, então, é preciso garantir:

&__item {
// ...
&:hover {
.#{$component-name}__submenu {
opacity: 1;
transform: rotateX(0) translateX(-50%);
transition-timing-function: ease-out;
}
}
}

Ou seja, quando se der o :hover em c-dropdown__item, seu elemento interno c-dropdown__submenu (perceba a interpolação com o nome do próprio componente) tem a rotação revertida, dando o efeito de “aparecer”.

Como fazer menu dropdown com CSS puro: resultado final do menu

Voilà! Um menu dropdown com CSS puro, semanticamente correto e bastante simples de se codar.

Conclusão

Como citado, existem diversas técnicas possível para conseguir fazer um menu dropdown com CSS. Inclusive, vários efeitos de aparecer/desaparecer também podem ser usados.

Este dropdown menu tem a vantagem de ser bem simples de se conseguir: usa marcação HTML simples e nenhuma técnica extraordinário de CSS para funcionar.

O ponto-chave é a rotação no eixo X do submenu e sua “desrotação” no hover do elemento ancestral, o que, convenhamos, também é mais difícil de planejar do que executar. :)

Para todos os passos de desenvolvimento do menu dropdown, assista ao vídeo no começo do artigo; para acessar o código completo, acesse o código completo no repo do projeto.

E você, tem usado alguma outra técnica para menu dropdown? Gostaria de compartilhar algum projeto que está usando? Coloca aí nos comentários!