1. Comece com a marcação da página
Primeiro vamos criar um modal. Para fazer isso, adicionaremos o .modal
classe e um ID exclusivo para um contêiner. A seguir, especificaremos a caixa de diálogo definindo um .modal-dialog
elemento como filho direto do .modal
. A caixa de diálogo conterá o conteúdo modal. Pode ser qualquer tipo de conteúdo, como texto, imagens, lightboxes, notificações/alertas de usuário, etc.
“Um pop-up (ou modal) é um pequeno elemento de UI que aparecerá em primeiro plano de um site, geralmente acionado como um prompt para o usuário fazer algo” – Adi Purdila
Para abrir um modal, precisaremos de qualquer elemento com o data-open
atributo (normalmente um button
). O valor deste atributo deve ser o ID do modal desejado.
Por padrão, um modal será fechado se clicarmos fora de seus limites ou quando o Esc
tecla é pressionada. Mas também podemos fechá-lo se clicarmos em qualquer elemento com o data-close
atributo (normalmente um button
).
Inicialmente o modal irá aparecer/desaparecer com um efeito de fade. Mas temos a capacidade de ajustar o efeito de animação do diálogo através do data-animation
atributo. O valor deste atributo que deve ser adicionado ao .modal
pode ser qualquer um dos seguintes valores:
slideInOutDown
slideInOutTop
slideInOutLeft
slideInOutRight
zoomInOut
rotateInOutDown
mixInAnimations
Veremos mais de perto esses valores em uma próxima seção.
Por enquanto, vamos nos familiarizar com a marcação necessária para representar um único modal:
1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
... |
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
2. Defina alguns estilos básicos
Com a marcação pronta, configuraremos algumas variáveis CSS e redefiniremos estilos:
1 |
:root { |
2 |
--lightgray: #efefef; |
3 |
--blue: steelblue; |
4 |
--white: #fff; |
5 |
--black: rgba(0, 0, 0, 0.8); |
6 |
--bounceEasing: cubic-bezier(0.51, 0.92, 0.24, 1.15); |
7 |
}
|
8 |
|
9 |
* { |
10 |
padding: 0; |
11 |
margin: 0; |
12 |
}
|
13 |
|
14 |
button { |
15 |
cursor: pointer; |
16 |
background: transparent; |
17 |
border: none; |
18 |
outline: none; |
19 |
font-size: inherit; |
20 |
}
|
A seguir, centralizaremos o conteúdo da página horizontal e verticalmente. Além disso, daremos alguns estilos ao botão responsável por abrir o modal:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
body { |
4 |
display: flex; |
5 |
align-items: center; |
6 |
justify-content: center; |
7 |
height: 100vh; |
8 |
font: 16px/1.5 sans-serif; |
9 |
}
|
10 |
|
11 |
.btn-group { |
12 |
text-align: center; |
13 |
}
|
14 |
|
15 |
.open-modal { |
16 |
font-weight: bold; |
17 |
background: var(--blue); |
18 |
color: var(--white); |
19 |
padding: .75rem 1.75rem; |
20 |
margin-bottom: 1rem; |
21 |
border-radius: 5px; |
22 |
}
|
Neste ponto focaremos nossa atenção nos estilos modais.
Cada modal terá os seguintes características:
- Será em tela cheia com uma posição fixa. Dito isto, parecerá uma sobreposição que cobre toda a largura e altura da janela.
- Terá uma cor de fundo escura.
- Ele ficará oculto por padrão.
- A caixa de diálogo será centralizada horizontal e verticalmente.
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.modal { |
4 |
position: fixed; |
5 |
top: 0; |
6 |
left: 0; |
7 |
right: 0; |
8 |
bottom: 0; |
9 |
display: flex; |
10 |
align-items: center; |
11 |
justify-content: center; |
12 |
padding: 1rem; |
13 |
background: var(--black); |
14 |
cursor: pointer; |
15 |
visibility: hidden; |
16 |
opacity: 0; |
17 |
transition: all 0.35s ease-in; |
18 |
}
|
A caixa de diálogo terá uma largura máxima e uma altura máxima. Sua altura será 80% da altura da janela. Nos casos em que sua altura ultrapasse esse valor, aparecerá uma barra de rolagem vertical:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.modal-dialog { |
4 |
position: relative; |
5 |
max-width: 800px; |
6 |
max-height: 80vh; |
7 |
border-radius: 5px; |
8 |
background: var(--white); |
9 |
overflow: auto; |
10 |
cursor: default; |
11 |
}
|
Por último, definiremos alguns estilos simples para as seções de conteúdo individuais:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.modal-dialog > * { |
4 |
padding: 1rem; |
5 |
}
|
6 |
|
7 |
.modal-header, |
8 |
.modal-footer { |
9 |
background: var(--lightgray); |
10 |
}
|
11 |
|
12 |
.modal-header { |
13 |
display: flex; |
14 |
align-items: center; |
15 |
justify-content: space-between; |
16 |
}
|
17 |
|
18 |
.modal-header .modal-close { |
19 |
font-size: 1.5rem; |
20 |
}
|
21 |
|
22 |
.modal p + p { |
23 |
margin-top: 1rem; |
24 |
}
|
3. Alternar Modal JavaScript
Uma página pode ter mais de um modal JavaScript. Mas, como já discutido anteriormente, todos os modais ficarão inicialmente ocultos.
Abra o Modal JavaScript
Da mesma forma, uma página pode ter mais de um gatilho aberto (elementos com o data-open
atributo). Cada vez que um gatilho é clicado, o modal associado deve ficar visível com uma animação fade-in. Lembre o data-open
o valor do atributo deve corresponder ao ID de um modal.
Aqui está o script que revela um modal:
1 |
const openEls = document.querySelectorAll("[data-open]"); |
2 |
const isVisible = "is-visible"; |
3 |
|
4 |
for(const el of openEls) { |
5 |
el.addEventListener("click", function() { |
6 |
const modalId = this.dataset.open; |
7 |
document.getElementById(modalId).classList.add(isVisible); |
8 |
});
|
9 |
}
|
E as classes CSS relevantes:
1 |
.modal { |
2 |
visibility: hidden; |
3 |
opacity: 0; |
4 |
transition: all 0.35s ease-in; |
5 |
}
|
6 |
|
7 |
.modal.is-visible { |
8 |
visibility: visible; |
9 |
opacity: 1; |
10 |
}
|
Fechar Modal JavaScript
Com nossa implementação, apenas um modal pode aparecer por vez (este código não oferece suporte a modais aninhados). Conforme mencionado na seção de marcação acima, existem três métodos disponíveis para ocultá-lo com um efeito de fade-out.
Vamos recapitular.
Em primeiro lugar, clicando no personalizado [data-close]
elemento que está localizado dentro do modal:
1 |
const closeEls = document.querySelectorAll("[data-close]"); |
2 |
const isVisible = "is-visible"; |
3 |
|
4 |
for (const el of closeEls) { |
5 |
el.addEventListener("click", function() { |
6 |
this.parentElement.parentElement.parentElement.classList.remove(isVisible); |
7 |
});
|
8 |
}
|
Em segundo lugar, clicando em tudo fora do modal:
1 |
const isVisible = "is-visible"; |
2 |
|
3 |
document.addEventListener("click", e => { |
4 |
if (e.target == document.querySelector(".modal.is-visible")) { |
5 |
document.querySelector(".modal.is-visible").classList.remove(isVisible); |
6 |
}
|
7 |
});
|
Neste caso o modal (overlay) se comporta como um botão gigante de fechar. Por esta razão nós demos cursor: pointer
.
Por último, pressionando o Esc
chave:
1 |
const isVisible = "is-visible"; |
2 |
|
3 |
document.addEventListener("keyup", e => { |
4 |
if (e.key == "Escape" && document.querySelector(".modal.is-visible")) { |
5 |
document.querySelector(".modal.is-visible").classList.remove(isVisible); |
6 |
}
|
7 |
});
|
Agora é um bom momento para ver o que criamos até agora:
O modal parece muito bom! Observe que cada vez que clicamos em um gatilho aberto, apenas os modais correspondentes são carregados.
Vamos dar um passo adiante e examinar algumas idéias para animar seu diálogo.
4. Adicionar animações de diálogo
Como dissemos anteriormente, o comportamento padrão do modal é aumentar e diminuir gradualmente. Mas existe a opção de ajustar o efeito de animação do pop-up.
Já criei vários efeitos de animação que você pode usar como alternativa ao efeito fade. Para isso, basta passar o data-animation="yourDesiredAnimation"
atribuir ao .modal
.
Por exemplo, se quiser que a caixa de diálogo apareça com uma animação de slide da esquerda para a direita, você precisará do slideInOutLeft
efeito.
Nos bastidores, existem duas regras que realizam a animação desejada:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
[data-animation="slideInOutLeft"] .modal-dialog { |
4 |
opacity: 0; |
5 |
transform: translateX(-100%); |
6 |
transition: all 0.5s var(--bounceEasing); |
7 |
}
|
8 |
|
9 |
[data-animation="slideInOutLeft"].is-visible .modal-dialog { |
10 |
opacity: 1; |
11 |
transform: none; |
12 |
transition-delay: 0.2s; |
13 |
}
|
Confira o modal com esse tipo de animação aqui:
Você pode conferir o resto das animações olhando o CSS guia do projeto de demonstração final. Dependendo da complexidade das animações, usei transições CSS ou animações para construí-las.
Eu também fiz uso do cubic-bezier()
função para definir a função de tempo para todas as transições. Se você não gostar do efeito de salto produzido, sinta-se à vontade para alterá-lo para algo mais suave por meio do --bounceEasing
Variável CSS.
Dê uma olhada na demonstração final com todos os efeitos de animação aqui:
Conclusão
É isso, pessoal! Durante este tutorial, aprendemos como construir caixas de diálogo modais JavaScript animadas e personalizadas sem depender de qualquer estrutura de front-end. Espero que você tenha gostado do resultado final e que construí-lo tenha ajudado a atualizar suas habilidades de front-end.
Tenha em mente que não consideramos a acessibilidade, então se você quiser aprimorar esta demonstração esse certamente poderá ser o próximo passo.
Como sempre, obrigado pela leitura!