Advertisement
  1. Web Design
  2. HTML/CSS
  3. Animation

Cómo crear un modal emergente con JavaScript desde cero

Scroll to top
Read Time: 7 min

() translation by (you can also view the original English article)

En este tutorial aprenderemos a crear modales emergentes con JavaScript (ventanas de diálogo) sin utilizar un framework de trabajo como Bootstrap, o una biblioteca de terceros. Crearemos todo desde cero, ofreciéndonos un control completo sobre cómo funciona y cómo se ve.

Aquí está la demostración que vamos a crear:

1. Inicia con el marcado de la página

Primero crearemos un modal. Para hacerlo, añadiremos la clase .modal y una ID única a un contenedor. Después especificaremos el diálogo estableciendo un elemento .modal-dialog como elemento secundario directo del .modal.     El diálogo contendrá el contenido del modal. Puede ser cualquier tipo de contenido como texto, imágenes, lightboxes, notificaciones/alertas de usuarios, etc.

«Una ventana de diálogo (o modal) es un pequeño elemento de interfaz de usuario (UI) que aparece en primer plano en un sitio web, por lo general se activa como un aviso para que el usuario haga algo» - Adi Purdila

Para abrir un modal, necesitaremos cualquier elemento con el atributo data-open (normalmente button). El valor de este atributo debe ser el ID del modal deseado.

Por defecto, un modal se cerrará si hacemos clic fuera de sus límites o cuando presionemos la tecla Esc. Pero también podemos cerrarlo si hacemos clic en cualquier elemento con el atributo data-close (normalmente button).

Al principio, el modal aparecerá/desaparecerá con un efecto de desvanecimiento. Pero tenemos la capacidad de ajustar el efecto de animación del diálogo mediante el atributo data-animation. El valor de este atributo que se tiene que añadir a .modal puede ser cualquiera de los siguientes valores:

  • slideInOutDown
  • slideInOutTop
  • slideInOutLeft
  • slideInOutRight
  • zoomInOut
  • rotateInOutDown
  • mixInAnimations

Veremos más de cerca estos valores en una próxima sección.

Por ahora, vamos a familiarizarnos con el marcado que se necesita para representar un solo modal:

1
<button type="button" class="open-modal" data-open="modal1">...</button>
2
3
<div class="modal" id="modal1">
4
  <div class="modal-dialog">
5
    <header class="modal-header">
6
      ...
7
      <button class="close-modal" aria-label="close modal" data-close></button>
8
    </header>
9
    <section class="modal-content">...</section>
10
    <footer class="modal-footer">...</footer>
11
  </div>
12
</div>

2. Define algunos estilos básicos

Con el marcado preparado, configuraremos algunas variables CSS y reiniciaremos los 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
}

Después, centraremos de manera horizontal y vertical el contenido de la página. Además, le daremos algunos estilos al botón responsable de abrir el 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
}

En este punto, centraremos nuestra atención en los estilos del modal.

Cada modal tendrá las siguientes características:

  • Será a pantalla completa con una posición fija. Es decir, se verá como una superposición que cubre todo el ancho y alto de la ventana.
  • Tendrá un color de fondo oscuro.
  • Estará oculto de manera predeterminada.
  • El diálogo estará centrado de forma horizontal y vertical.
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
}

El diálogo tendrá una anchura y una altura máximas. Su altura será el 80% de la altura de la ventana. En los casos en que su altura exceda ese valor, aparecerá una barra de desplazamiento 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 unos cuantos estilos simples para cada una de las secciones de contenido:

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. Alternando el modal

Una página puede tener más de un modal. Pero como se comentó anteriormente, todos los modales estarán ocultos al principio.

Abre el modal

De igual modo, una página puede tener más de un activador abierto (elementos con el atributo data-open). Cada vez que se haga clic en un activador, el modal asociado debería hacerse visible con una animación apareciendo gradualmente (fade-in). Recuerda que el valor del atributo data-open debe coincidir con el ID de un modal.

Aquí está el script que revela un 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
}

Y las clases relevantes de CSS:

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
}

Cierra el modal

Con nuestra implementación únicamente puede aparecer un modal a la vez (este código no soporta modales anidados). Como se mencionó en la sección de marcado anterior, hay tres métodos disponibles para ocultarlo con un efecto de desvanecimiento (fade-out).

Recapitulemos.

En primer lugar, haciendo clic en el elemento personalizado [data-close] que se localiza dentro del 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
}

En segundo lugar, haciendo clic en en cualquier parte fuera del 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
});

En este caso, el modal (la superposición) se comporta como un botón gigante de cierre. Por esta razón le dimos cursor: pointer.

Por último, presionando la tecla Esc:

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
});

Es un buen momento para ver lo que hemos creado hasta ahora:

¡El modal se ve muy bien! Observa que cada vez que hacemos clic en un activador abierto, uúnicamente se carga el modal correspondiente.

Demos un paso más y examinemos algunas ideas para animar su diálogo.

4. Añade animaciones al diálogo

Como lo indicamos antes, el comportamiento por defecto del modal es aparición gradual (fade-in) y desvanecimiento gradual (fade-out). Pero existe la opción de ajustar el efecto de animación de la ventana emergente.

Ya he creado bastantes efectos de animación que podrías utilizar como alternativa al efecto de desvanecimiento. Para hacerlo, simplemente tienes que pasar el atributo data-animation="yourDesiredAnimation" a .modal.

Por ejemplo, si quieres que el diálogo aparezca con una animación de deslizamiento de izquierda a derecha, necesitarás el efecto slideInOutLeft.

Detrás de escenas, hay dos reglas que logran esta animación:

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
}

Revisa el modal con este tipo de animación aquí:

Puedes revisar el resto de las animaciones mirando la pestaña de CSS del proyecto final de la demostración. Dependiendo de la complejidad de las animaciones, he utilizado transiciones CSS o animaciones para crearlas.

También he usado la función cubic-bezier() para ajustar la función de tiempo de todas las transiciones. Si no te gusta el efecto de rebote que produce, siéntete libre de cambiarlo a algo más suave mediante la variable --bounceEasing CSS.

Mira la demostración final con todos los efectos de animación aquí:

Conclusión

¡Eso es todo, amigos! Durante este tutorial aprendimos a crear diálogos modales animados personalizados sin depender de ningún framework de front-end .

Espero que hayas disfrutado del resultado final y que su creación te haya ayudado a poner al día tus habilidades de front-end.

Ten presente que no hemos considerado la accesibilidad, así que si quieren mejorar esta demostración, ese podría ser el siguiente paso.

¡Como siempre, gracias por leernos!

Más lecturas sobre ventanas emergentes

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Web Design tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.