Vamos a crear una animación bastante simple utilizando una librería de JS Gsap que podría servir para crear una llamativa página animada utilizando el scroll.
Guía de navegación:
- ¿Qué es Gsap?
- Descripción
- Creación de archivos que vamos a necesitar
- HTML
- Head y Estilos
- Body y scripts
- CSS
- JavaScript
- Configuración de la línea de tiempo
- Reproduciendo el video durante el scroll
- ¿Como reparar el error?
¿Qué es Gsap?
Es un sólido conjunto de herramientas de JavaScript que permite crear una página animada utilizando el scroll, además ofrece alto rendimiento que funcionen en todos los principales navegadores. Anima CSS, SVG, lienzo, React, Vue, WebGL, colores, cadenas, trayectorias de movimiento, objetos genéricos. Si quieres ir más a fondo, recomiendo visitar su página de GitHub.
Antes de iniciar con el código hay unas recomendaciones que son importantes destacar.
Estas son:
- Tener conocimientos básicos de HTML, CSS, y JavaScript.
- Saber implementar librerías, estilos y scripts.
- Conocer más o menos Bootstrap framework.
En este tutorial paso a paso crearemos los archivos necesarios e iremos explicando cada línea de código que sea relévente para este proyecto. Es decir, solo se va a profundizar en los atributos y clases que están vinculados directamente para que la animación de la página funcione. Esto es para evitar que la publicación se haga demasiado extensa y además enfocarnos en los que realmente nos interesa.
Descripción
Esta página de ejemplo consta de una imagen de plantas o arbustos y un video. La imagen es de tipo PNG, con un fondo transparente que está posicionada sobre el video en una posición absoluta respecto al contenedor padre. Por último tenemos un formulario que está ubicado al final antes del pie de página. Para llegar al formulario tenemos que hacer scroll en la página, lo que provocara que la imagen se agrande dando una sensación de acercamiento para que en un determinado punto la imagen se desvanezca.
También al momento de hacer el scroll, el video se activa. Activamos el video para dar esa sensación de movimiento que junto con el agrandamiento de la imagen crea una experiencia inmersiva. Después que la imagen se termina de desvanecer, el video se agranda hasta un punto del scroll y empieza a activarse el scroll común. Después de que el video se haya agrandado, se activa el scroll normal mostrando el formulario para completar. Obteniendo de manera una página animada utilizando scroll.
Creación de archivos que vamos a necesitar
Como dijimos desde el inicio, esta publicación solo se enfocará en lo relevante de cada archivo. Por tal motivo es preciso tener los conocimientos antes mencionados. De todas formas se intentará ser lo más conciso posible para un mejor entendimiento.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<title>Animación scroll usando Gsap</title>
</head>
<body>
<div class="container-fluid px-0 mx-0">
<section id="home" class="section">
<div class="homeWrapper">
<div class="homeSlider homesections">
<video id="video" src="img/paisamontanas.mp4" muted playsinline poster="" loop="true"></video>
</div>
<div class="homeSliderReveal homesections">
<img id="imagen" src="img/2.png" alt="">
</div>
<div class="w-75 position-absolute top-50 start-50 translate-middle">
<h1 class="main-title">Landing Page animada utilizando scroll.</h1>
<h3 class="main-desc">Capta la atención de tus clientes ofreciendo experiencias inmersivas.</h3>
</div>
</div>
</section>
<section id="about" class="section">
<div class="container text-white mt-5 mx-2 mb-2 border border-radius p-3">
<h3 class="text-center">Completa el siguiente formulario</h3>
<form class="row g-3">
<div class="col-md-6">
<label for="inputEmail4" class="form-label">Email</label>
<input type="email" class="form-control" id="inputEmail4">
</div>
<div class="col-md-6">
<label for="inputPassword4" class="form-label">Nombre</label>
<input type="password" class="form-control" id="inputPassword4">
</div>
<div class="col-12">
<label for="inputAddress" class="form-label">dirección</label>
<input type="text" class="form-control" id="inputAddress" placeholder="1234 Main St">
</div>
<div class="col-md-6">
<label for="inputCity" class="form-label">Ciudad</label>
<input type="text" class="form-control" id="inputCity">
</div>
<div class="col-md-4">
<label for="inputState" class="form-label">Estado</label>
<select id="inputState" class="form-select">
<option selected>Escoge una opción...</option>
<option>...</option>
</select>
</div>
<div class="col-md-2">
<label for="inputZip" class="form-label">Código postal</label>
<input type="text" class="form-control" id="inputZip">
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="gridCheck">
<label class="form-check-label" for="gridCheck">
Mantenerme informado de las últimas novedades
</label>
</div>
</div>
<div class="col-12">
<button type="submit" class="btn btn-primary w-100">Enviar</button>
</div>
</form>
</div>
</section>
</div>
<script src="gsap-3.3.4/gsap.min.js"></script>
<script src="gsap-3.3.4/ScrollTrigger.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="main.js"></script>
</body>
</html>
Empezamos con los scripts necesarios para que la animación funcione. Dentro del head
encontramos las siguientes etiquetas que nos permitirán colocar los estilos. La primera etiqueta es la de Bootstrap, recordamos que estamos utilizando la versión 5. En este caso no estoy utilizando un CDN, pero tranquilamente podemos encontrar el CDN aquí.
Head y Estilos
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
Las primeras 3 meta etiquetas son las que casi siempre deben ir en cada proyecto. Las otras dos etiquetas restantes son las que están relacionadas con las hojas de estilo y hacen referencia al archivo CSS de bootstrap es decir bootstrap.min.css
y style.css
Body y scripts
<script src="gsap-3.3.4/gsap.min.js"></script>
<script src="gsap-3.3.4/ScrollTrigger.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="main.js"></script>
Acá viene la parte interesante y es el corazón de la animación, primero tenemos la etiqueta script que guarda el recurso de gsap-3.3.4/gsap.min.js
que es archivo principal de la librería Gsap que es la encargada de realizar las animaciones. La siguiente etiqueta es gsap-3.3.4/ScrollTrigger.min.js
es el archivo del plug-in de Gsap que nos permitirá utilizar el scroll para la animación. A continuación tenemos js/bootstrap.min.js
el archivo de JavaScript de bootstrap en caso de que lo necesitemos. Y por último el main.js
que es el archivo principal donde vamos a escribir toda la configuración de la animación.
Ahora vamos con el contenedor donde vamos a incluir las clases y atributos que vamos a utilizar.
- La clase:
container-fluid px-0 mx-0
de bootstrap es el contenedor principal de ancho completo sin relleno ni márgenes en x. - La etiqueta
section id="home" class="section"
es la que contendrá los elementos que vamos a animar donde el valorhome
lo vamos a utilizar en elmain.js
y la clase section enstyle.css
. - La clase
class="homeWrapper"
es la que nos permite mantener los elementos en un mismo bloque.
El resto de las clases y atributos no tienen mayor importancia, ya que solo están para ubicar los elementos en las respectivas posiciones. La última clase section
está para contener el formulario que fue sacado de la documentación de bootstrap.
CSS
/*Hoja de estilos principal*/
body{
margin: 0;
padding: 0;
background: #041921;
}
.section{
display: flex;
flex-direction: row;
justify-content: center;
margin: 0 auto;
padding: 0px;
overflow: hidden;
}
#imagen{
position: absolute;
top:0px;
}
.main-title{
top: 300px;
color: white;
text-align: center;
}
.main-desc{
color: white;
text-align: center;
}
La hoja de estilos principal, como se ve, es bastante simple y se explica a sí mismo. La clase más importante es section
que utiliza flex para centrar los elementos y hacer que no se deformen en los diferentes tamaños de viewports.
JavaScript
gsap.registerPlugin(ScrollTrigger);
ScrollTrigger.defaults({
toggleActions: 'restart pause resume pause',
markers: false,
})
const timelineHeader = gsap.timeline({
scrollTrigger: {
id: 'ZOOM',
trigger: '#home',
scrub: 1,
start: 'top top',
end: '+=100%',
pin: true
}
});
timelineHeader.
to('#imagen', {
scale: 3,
duration: 3
},'-=3'
).
to('#imagen', {
opacity:0,
duration:2,
}, '-=2'
).
to('#video', {
scale: 1.3,
duration: 2
}
)
//Autp play the video with the first scroll
const video = document.querySelector('#video')
document.addEventListener('scroll', playOnScroll)
function playOnScroll(){
video.playbackRate = 5.0 //Esto acelera el video 5.xx
// Show loading animation.
var playPromise = video.play()
if (playPromise !== undefined) {
playPromise.then(_ => {
// Automatic playback started!
// Show playing UI.
})
.catch(error => {
// Auto-play was prevented
// Show paused UI.
})
}
}
gsap.registerPlugin(ScrollTrigger);
Esta línea registra el plug-in ScrollTrigger.
ScrollTrigger.defaults()
El método defaults de ScrollTrigger guarda un objeto de configuración donde tenemos toggleActions
y markers
.
markers
lo tenemos false
, pero si lo cambiamos a true
, veríamos unas marcas de inicio y final que nos sirven de guía para saber donde inicia la animación.
toggleActions
: De forma predeterminada, ScrollTrigger simplemente reproduce la animación vinculada cuando se alcanza la posición de inicio de desplazamiento, pero puede realizar cualquiera de las siguientes acciones en cualquiera de los cuatro puntos de alternancia: play, pause, resume, reverse, complete, restart, reset, or none.
La variable timelineHeader
almacena una instancia de la línea de tiempo, gsap.timeline()
el método timeline contiene un objeto de configuración con diferentes propiedades.
id: "ZOOM"
: Agrega la clase adicionalpin-spacer-ZOOM
que es propia de Gsap.trigger: "#home"
: Es el contenedor principal donde vivirá la animación, es decir, todo lo que está dentro, podrá ser animado.scrub: 1
: Suaviza el vínculo entre la animación y la barra de desplazamiento para que tarde un cierto tiempo en “ponerse al día”, comoscrub: 1
, tomará un segundo en ponerse al día.start: 'top top'
: cuando la parte superior del gatillo golpea la parte superior del fin de la ventana gráfica. Funciona junto con la siguiente propiedad end: ‘+=100’, que en este caso es 100.end: '+=100%'
: End Termina después de desplazarse 100%, más allá de start. Supongamos que tiene una línea de tiempo con tres interpolaciones secuenciadas: una interpolación de 1 segundo, una interpolación de 3 segundos y luego otra interpolación de 1 segundo. Y el ScrollTrigger aplicado a él se animará a una distancia de altura completa de la ventana gráfica (quizás el disparador usa los valores destart: "center bottom"
yend: "center top"
). ¿Aún dudas? Siempre busca en la documentación oficial de Gsap ScrollTrigger.pin: true
: Fija el contenedor que queremos animar.
Configuración de la línea de tiempo:
Utilizamos la constante timelineHeader
y le aplicamos el método to()
. Donde el primer parámetro '#home'
es el elemento que queremos animar, el siguiente parámetro es un objeto que contendrá las propiedades de la animación. Estas propiedades son CSS, pero cuidado porque se escriben distintas.
Por ejemplo, si tenemos una propiedad background-color, en Gsap se escribe backgroundColor, es decir, quitamos el guion medio y ponemos la primera letra mayúscula de la primera palabra después del guion.
El objeto en este caso contiene { scale: 3, duration: 3 }
, es decir, que lo primero que hará la animación, será escalar, 3 veces el elemento seleccionado, con una duración de 3 segundos. El último parámetro es '-=3'
, es decir, que restara esa duración, haciendo que se vea al mismo tiempo los movimientos y no esperando que termine uno para comenzar el otro.
Este artículo para crear una página animada utilizando scroll se está volviendo demasiado extenso, por lo tanto, vamos a evitar repetir código que fue explicado.
Reproduciendo el video durante el scroll:
Por último creamos la función para reproducir el video que se activa desde el primer scroll. Para esto creamos una constante video
que almacenara el video utilizando document.getElementById('#video')
Después vamos a escuchar el evento scroll, llamando a la función playOnScroll()
.
La función para reproducir el video es poco particular y cambio un poco la forma habitual de reproducir automáticamente un video, veamos como es ahora.
Resulta que me había encontrado con el siguiente error en la consola de Chrome
Uncaught (in promise) DOMException: The play() request was interrupted by a call to pause()
<video id="video" preload="none" src="https://example.com/file.mp4"></video>
<script>
video.play(); // <-- This is asynchronous!
video.pause();
</script>
Tenía hecho algo como lo de arriba. Algo estaba haciendo que el código no se ejecutara correctamente. Buscando me encuentro con esta documentación aquí:
Desde Chrome 50, una play()
llamada a un elemento <video>
o <audio>
devuelve una Promesa, una función que devuelve un único resultado de forma asíncrona. Si la reproducción tiene éxito, la Promesa se cumple y el playing
evento se activa al mismo tiempo. Si la reproducción falla, la Promesa se rechaza junto con un mensaje de error que explica la falla.
¿Como reparar el error?
En primer lugar, nunca suponga que se reproducirá un elemento multimedia (video o audio). Mire la Promesa devuelta por la play
función para ver si fue rechazada. Vale la pena señalar que la Promesa no se cumplirá hasta que la reproducción realmente haya comenzado, lo que significa que el código dentro de then()
no se ejecutará hasta que se reproduzcan los medios.
Para la reproducción automática debemos hacer así:
<video id="video" preload="none" src="https://example.com/file.mp4"></video>
<script>
// Show loading animation.
var playPromise = video.play();
if (playPromise !== undefined) {
playPromise.then(_ => {
// Automatic playback started!
// Show playing UI.
})
.catch(error => {
// Auto-play was prevented
// Show paused UI.
});
}
</script>
Eso fue todo, vimos que fácil fue crear una página animada utilizando scroll. Espero que este mini tutorial de Gsap haya sido de utilidad y puedan aplicar alguno de estos conceptos en sus propios proyectos. Agradecería me dejaras un comentario si esta información ha resultado útil.