Uma foto minha vestido com o uniforme da Grifinória do Harry Potter

Willian JustenSoftware Engineer

Instrutor na Udemy, escrevo sobre o mundo front end, viagens, vida pessoal e mais.

← Voltar na listagem

Criando um menu Off Canvas com CSS3

Aprenda a criar um menu off canvas usando CSS3 Transitions e Transforms.

Introdução

Como eu disse no post anterior, vou tentar voltar a escrever um pouquinho mais e para isso escolhi uma coisa que há muito tempo já haviam me perguntado, que era, como criar um menu off canvas como eu uso nesse blog. A trilha sonora de hoje vai ser Forever Alone (que minha namorada não leia isso =o).

Off Canvas

Esse menu passou a ser mais famoso com o uso de dispositivos mobile, onde não possuímos tanto espaço em tela para poder ter um menu lateral. Então nada melhor do que esconder e mostrar só quando necessário né?

Se você é daqueles que gosta de ver funcionando primeiro, segue a DEMO.

O exemplo mostrado aqui abaixo está bem simplificado sem o uso de prefixos para os browsers e pode ser instável em certas versões. Por favor, utilize um auto-prefixer para que tudo fique correto =)

Funcionamento

O funcionamento é bem básico e consiste de trabalhar com camadas deslocadas. Vamos imaginar os seguintes elementos:

  • Wrapper: elemento do tamanho da viewport da tela.
  • Canvas: área onde teremos nosso conteúdo de fato.
  • Menu: nosso menu.

Em seu primeiro momento, teremos o menu totalmente fora do wrapper e o canvas ocupando toda a tela, conforme imagem abaixo:

Menu Off Canvas do lado de fora

Para que o menu apareça na tela, o que fazemos é deslocar tudo para o lado direito, ou seja, no eixo X e assim o menu passa a aparecer e um pedaço do nosso canvas sai da tela, conforme imagem abaixo:

Menu Off Canvas do lado de dentro

HTML

Bom, vamos começar a mão na massa, porque isso é tão fácil de fazer e já estou enrolando muito. Primeiro de tudo, vamos montar nossa estrutura, que vai seguir basicamente aquelas 3 camadas ditas acima.

<body>
  <div class="wrapper">
    <div class="canvas">
      <div class="menu"></div>
    </div>
  </div>
</body>

Dentro dessas camadas, vamos colocar algum conteúdo, só para não ficar muito vazio.

<body>
  <div class="wrapper">
    <div class="canvas">
      <!-- Aqui fica o menu escondido -->
      <div class="menu">
        <a href="#" class="toggle-menu btn">Fechar o menu</a>
        <ul>
          <li><a href="#">Link 1</a></li>
          <li><a href="#">Link 2</a></li>
          <li><a href="#">Link 3</a></li>
        </ul>
      </div>
      <!-- Aqui fica o conteúdo do site -->
      <div class="conteudo">
        <a href="#" class="toggle-menu">Abrir o menu</a>
        <h1>Menu Off Canvas!!</h1>
        <p>Uma simples demo mostrando como funciona o menu off canvas.</p>
        <p>
          Tutorial em
          <a
            href="https://willianjusten.com.br/criando-um-menu-off-canvas-com-css3/"
            >willianjusten.com.br</a
          >
        </p>
      </div>
    </div>
  </div>
</body>

Note também, que eu criei um botão com a seguinte classe toggle-menu, que vai ser responsável por fazer a mágica de abrir e fechar o menu.

CSS

Wrapper

Depois de montada a estrutura, precisamos deixar um pouco bonitinho e fazer a mágica acontecer. Primeiro vamos montar nosso wrapper, ele é o responsável por segurar o conteúdo de nosso site e "esconder" as coisas que estiverem por fora dele, por esse motivo iremos utilizar a propriedade overflow: hidden, que vai esconder essas coisinhas.

.wrapper {
  position: relative;
  overflow: hidden;
  width: 100%;
  height: 3000px; /* só para deixar a página grande*/
}

Canvas

O canvas nada mais é que nossa tela e que será responsável por se mover pelas laterais junto com o menu, ou seja, movimentos no eixo X. Em seu estado inicial, ele deverá assumir que x é igual a 0, visto que ainda não se moveu. Coloquei também uma transition só para que o efeito seja suave e bonitinho <3

.canvas {
  width: 100%;
  height: 100%;
  position: relative;
  transform: translateX(0);
  transition: 0.3s ease all;
}

Nosso menu inicialmente precisa estar do lado de fora do wrapper e para isso terá um valor negativo de X. As outras propriedades são somente para dar um pouco de estilo ao mesmo.

.menu {
  height: 100%;
  position: absolute;
  transform: translateX(-300px);
  width: 300px;
  background: #bf0000;
  padding: 5rem;
}

Animação

Depois de feitas essas adições de CSS, nosso menu já se encontra do lado de fora escondido, nosso canvas já está aparecendo, mas e como será o efeito para tudo funcionar? Simples, precisamos mover o nosso canvas para o lado direito, no tamanho exato que o menu foi deslocado, ou seja 300px.

.wrapper.show-menu .canvas {
  transform: translateX(300px);
}

Javascript

Para funcionar o menu, só falta criarmos alguma trigger que será responsável por adicionar e remover a classe .show-menu do nosso wrapper. Podemos fazer isso usando Javascript puro, jQuery ou podemos até fazer sem o uso de classes e sim esquema de :checked de inputs e aí nem usar JS, enfim, fica a seu critério. Aqui segue um exemplo bem simples com JS Puro.

// elementos auxiliares
var toogleMenu = document.querySelectorAll('.toggle-menu'),
  wrapper = document.querySelector('.wrapper')

// criando evento de click para abrir o menu
for (var i = 0; i < toogleMenu.length; i++) {
  toogleMenu[i].addEventListener('click', menuAction)
}

// função auxiliar que abre e fecha o menu
function menuAction() {
  if (wrapper.classList.contains('show-menu')) {
    wrapper.classList.remove('show-menu')
  } else {
    wrapper.classList.add('show-menu')
  }
}

O código acima usa o classList para verificar se já existe a classe e adicionar ou então remover, fazendo assim a animação funcionar.

E o resultado fica assim:

See the Pen by Willian Justen de Vasconcellos (@willianjusten) on CodePen.

Melhorias

Performance com uso da GPU

Um truque bem famoso que podemos usar para otimizar a animação é forçar o uso da aceleração via hardware do computador, definindo as transições em 3D. A mudança pode ser bem pequena e quase imperceptível para a maioria das máquinas, mas já é um ganho, no caso, faríamos assim, substituimos o translateX() pelo translate3d().

/* Antes */
.canvas {
  transform: translateX(0);
}
.show-menu .canvas {
  transform: translateX(300px);
}

/* Novo */
.canvas {
  transform: translate3d(0);
}
.show-menu .canvas {
  transform: translate3d(300px, 0, 0);
}

Fechar o menu com a tecla ESC

Uma coisa que já é quase intuitivo é fechar as coisas usando a tecla ESC, então por que não criar um evento para isso no nosso menu? Em Javascript Puro ficaria assim

// Adicionando evento para fechar o menu ao pressionar a tecla ESC
document.addEventListener('keyup', function (e) {
  if (e.keyCode == 27) {
    if (wrapper.classList.contains('show-menu')) {
      menuAction()
    }
  }
})

Conclusão

É basicamente isso pessoal, existem várias coisas que vocês podem brincar, como tipos diferentes de animação e velocidades de transição. Também podem brincar com novas posições, com menus vindo de cima, da direita, enfim... Quem fizer uma brincadeira nova, posta aí nos comentários.