Siguiendo con la idea de mi anterior publicación, animación de una Landing usando la API Intersection Observer de Javascript, esta entrada también consiste en crear animación cuando las imágenes entran dentro del viewport
ralizando transformación de clip-path
según el porcentaje de la imagen dentro del viewport
También se ha creado animación del color de fondo de <body>
. El color dependará de la imagen que esté dentro del viewport. Para obtener el color se ha usado una librería externa, vibrantjs, que obtiene de una imagen, su color principal y paleta de colores
Puede verse una prueba funcionando aquí
Obtener color principal de la imagen
Cuando todas las imágenes están completamente cargadas inicializamos la librería vibrant.js tal como indica su documentación. Nos interesa guardar el valor rgb()
como data-attribute
, he guardado el color principal y la paleta de colores, aunque sólo use el color principal. Al mismo tiempo asigno el observer
que se encarga de cambiar el color de fondo de body
en función del color principal de la imagen actualmente visible
window.onload = () => {
//...
const imgs = document.querySelectorAll('.drop-shadow img');
const ioBgcolor = new IntersectionObserver(ioBgcolorHandler, ioConfigBg);
imgs.forEach(img => {
const vibrant = new Vibrant(img);
const swatches = vibrant.swatches()
for (let swatch in swatches)
if (swatches.hasOwnProperty(swatch) && swatches[swatch])
img.setAttribute(`data-${swatch}`, swatches[swatch].getRgb());
ioBgcolor.observe(img);
});
//...
};
Asignar color principal de la imagen como fondo
En el apartado anterior he comentado se cambia el color de fondo de body
cuando entra nueva imagen en el viewport. Además también se actualiza/modifica <meta name="theme-color" content="rgb()">
para cambiar el color de la aplicación para que en Mobile de la sensación de pantalla completa acorde a la imagen que se esté viendo
La configuración del Observer es simple. Cuando sea visible un 2% de la imagen se cambia el color de fondo con el valor guardado anteriormente data-darkvibrant="rgb"
const ioBgcolorHandler = entries => {
for (let entry of entries) {
if (entry.intersectionRatio > 0.2) {
document.body.style.backgroundColor = `rgb(${entry.target.dataset.darkvibrant})`;
let metaThemeColor = document.querySelector("meta[name=theme-color]");
if (metaThemeColor) metaThemeColor.setAttribute("content", `rgb(${entry.target.dataset.darkvibrant})`);
}
}
}
const ioConfigBg = {
root: null,
rootMargin: '0px',
threshold: .2
};
window.onload = () => {
//...
const imgs = document.querySelectorAll('.drop-shadow img');
const ioBgcolor = new IntersectionObserver(ioBgcolorHandler, ioConfigBg);
imgs.forEach(img => {
//...
ioBgcolor.observe(img);
});
//...
};
Animación de propiedad CSS clip-path
La animación será aplicada a todos los elementos que tengan la clase .clip-path-trapezoid
. Estos elementos tienen una variable CSS que he llamado --x-trapezoid
y su valor, en porcentaje, se modifica en función de la cantidad de imagen que se este mostrando
Se he creado la función para buildThreshold(steps)
para generar array entre 0 y 1 con la cantidad de pasos que debe llamarse el Intersection Observer
const buildThreshold = steps => Array(steps + 1)
.fill(0)
.map((_, index) => index / steps || 0)
const ioTrapezoidHandler = entries => {
for (let entry of entries) {
if (entry.isIntersecting) {
entry.target.style.setProperty('--x-trapezoid', `${entry.intersectionRatio * 100}%`);
}
}
}
const ioConfigTrapezoid = {
root: null,
rootMargin: '0px',
threshold: buildThreshold(150)
};
window.onload = () => {
//...
const trapezoids = document.querySelectorAll(".clip-path-trapezoid");
const ioTrapezoid = new IntersectionObserver(ioTrapezoidHandler, ioConfigTrapezoid);
//...
[].forEach.call(trapezoids, trapezoid => ioTrapezoid.observe(trapezoid));
};
Un recurso interesante para poder probar en que consiste clip-path
de CSS. Viendo la web se puede ver que existen diferentes tipos de formas polygon
, circle
, ellipse
e inset
y que son pares de cordenadas en polígonos/inset y punto inicial/radios en los circle/ellipse
Con CSS asigné variables CSS (con valores iniciales) a algunos puntos. La variable CSS se irá cambiando según el elemento esté más o menos visible
La animación se realiza con transition
CSS. Una de las animación no va Intersertion Observer y si con hover
No voy a copiar el código CSS, puede ver en GitHub