Crea hermosas animaciones durante el desplazamiento con la propiedad Clip-Path de CSS
Spanish (Español) translation by Carlos (you can also view the original English article)
En un tutorial anterior, aprendimos a crear un efecto de escala de grises a color durante el desplazamiento. Para implementarlo, aprovechamos las características modernas de front-end como CSS Grid, la propiedad clip-path y la API Intersection Observer.
Hoy, utilizaremos estas herramientas y los conocimientos adquiridos en ese tutorial para crear otro genial efecto de desplazamiento. A medida que nos desplacemos, los elementos de la página aparecerán de manera secuencial con una animación de deslizamiento. Este es un efecto de desplazamiento común que puedes ver en los sitios web de portafolios.
Lo que vamos a crear
Sin más preámbulos, revisemos lo que vamos a crear:
Nota: Asegúrate de leer el tutorial anteriormente citado, ya que tomaremos algunos fragmentos de código de él.
1. Empieza con el marcado HTML
Iniciaremos con un elemento section de envoltura que contendrá section s anidadas. Cada subsección tendrá uno de los siguientes tres posibles diseños:
- Una imagen a la izquierda, texto a la derecha.
- Texto grande a la derecha.
- Texto a la izquierda, imagen a la derecha.
Aquí está una representación visual de estos diseños:



Cabe señalar que para todos los diseños, vamos a usar la misma imagen de Pixabay. Quizá recuerdes que ya la hemos utilizado en otro tutorial de desplazamiento.
El marcado que se requiere:
1 |
<section class="main-section"> |
2 |
<section class="grid"> |
3 |
<figure>
|
4 |
<img src="IMG_SRC" alt=""> |
5 |
<figcaption>...</figcaption> |
6 |
</figure>
|
7 |
<p>...</p> |
8 |
</section>
|
9 |
<section class="big-text"> |
10 |
<p>...</p> |
11 |
</section>
|
12 |
<section class="grid grid-alternate"> |
13 |
<p>...</p> |
14 |
<figure>
|
15 |
<img src="IMG_SRC" alt=""> |
16 |
<figcaption>...</figcaption> |
17 |
</figure>
|
18 |
</section>
|
19 |
</section>
|
2. Define los estilos
A continuación, escribiremos los aspectos más importantes de nuestros estilos. Para esta demostración, no discutiremos las reglas de restablecimiento (reset), pues no son nada importante. Así que, vayamos directo al grano:
- Definiremos las clases
grid,grid-alternateybig-textpara registrar los diferentes diseños. Los dos primeros aprovechan CSS Grid, mientras que el último establece un ancho máximo conmargin-left: auto. - Solo para practicar con una nueva función de CSS, usaremos
clamp()para crear una tipografía fluida. - Cada elemento
figuretendrá un pseudoelemento::beforeposicionado de forma absoluta. Ese elemento actuará como una superposición de imágenes y se animará primero. - Todos los elementos animados se ocultarán al principio gracias a la propiedad
clip-path. Nuevamente, para entender realmente cómo funciona esta propiedad, revisa este tutorial. - Para encadenar las animaciones, pasaremos los valores apropiados a la propiedad
transition-delayde cada elemento. Puedes hacerlos dinámicos usando variables de CSS. - En pantallas de hasta 1000 px de ancho, todos los elementos estarán apilados. Asimismo, en las secciones de las imágenes, la imagen siempre aparecerá antes del texto.
Aquí están los estilos correspondientes basados en estas hipótesis:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
body { |
4 |
font: clamp(16px, 2vw, 22px) / 1.7 "Montserrat", sans-serif; |
5 |
}
|
6 |
|
7 |
.main-section { |
8 |
max-width: 1400px; |
9 |
padding: 0 30px; |
10 |
margin: 120px auto; |
11 |
}
|
12 |
|
13 |
.main-section section + section { |
14 |
margin-top: 120px; |
15 |
}
|
16 |
|
17 |
.main-section .grid { |
18 |
display: grid; |
19 |
grid-column-gap: 60px; |
20 |
grid-template-columns: 2fr 1fr; |
21 |
}
|
22 |
|
23 |
.main-section .grid-alternate { |
24 |
grid-template-columns: 1fr 2fr; |
25 |
}
|
26 |
|
27 |
.main-section .big-text { |
28 |
max-width: 800px; |
29 |
margin-left: auto; |
30 |
font-size: clamp(24px, 2vw, 32px); |
31 |
}
|
32 |
|
33 |
.main-section figure { |
34 |
position: relative; |
35 |
box-shadow: -1rem 1rem 3rem -2rem rgba(0, 0, 0, 0.5); |
36 |
}
|
37 |
|
38 |
.main-section figure::before { |
39 |
content: ""; |
40 |
position: absolute; |
41 |
top: 0; |
42 |
right: 0; |
43 |
bottom: 0; |
44 |
left: 0; |
45 |
background: var(--blue-sudo); |
46 |
transition: clip-path 0.3s; |
47 |
}
|
48 |
|
49 |
.main-section figure img { |
50 |
display: block; |
51 |
clip-path: inset(0 100% 0 0); |
52 |
transition: clip-path 0.6s 0.3s; |
53 |
}
|
54 |
|
55 |
.main-section figure figcaption { |
56 |
position: absolute; |
57 |
top: 20px; |
58 |
right: 20px; |
59 |
padding: 10px; |
60 |
font-weight: bold; |
61 |
text-transform: uppercase; |
62 |
color: var(--white); |
63 |
background: var(--blue); |
64 |
mix-blend-mode: overlay; |
65 |
transition: clip-path 0.3s 0.9s; |
66 |
}
|
67 |
|
68 |
.main-section figure::before, |
69 |
.main-section figure figcaption { |
70 |
clip-path: inset(0 0 0 100%); |
71 |
}
|
72 |
|
73 |
@media (max-width: 1000px) { |
74 |
.main-section { |
75 |
margin: 60px auto; |
76 |
}
|
77 |
|
78 |
.main-section section + section { |
79 |
margin-top: 60px; |
80 |
}
|
81 |
|
82 |
.main-section .grid { |
83 |
grid-template-columns: 1fr; |
84 |
grid-row-gap: 30px; |
85 |
}
|
86 |
|
87 |
.main-section .grid-alternate figure { |
88 |
order: -1; |
89 |
}
|
90 |
}
|
3. Anima durante el desplazamiento
Mientras nos desplacemos, animaremos únicamente las secciones de la imagen (es decir, las que tienen la clase grid). De manera más específica, animaremos los siguientes elementos con este orden:
- El pseudoelemento
::beforedel elementofigure(el que tiene el fondo oscuro). - La imagen.
- El texto de la imagen.



Cuando al menos el 50% de cada elemento de figure ingrese a la ventana gráfica, recibirá la clase is-animated. De lo contrario, perderá esta clase y quedará oculto.
Así que, cuando la mitad de una figura (figure) esté dentro de la ventana gráfica, los elementos secundarios asociados aparecerán de manera secuencial desde diferentes direcciones. Primero, el pseudoelemento ::before aparecerá desde la derecha, luego la imagen desde la izquierda y finalmente su texto desde la derecha.
El código JavaScript que vamos a necesitar se tomará del tutorial de efectos de escala de grises a color. Solamente tenemos que hacer coincidir diferentes elementos:
1 |
const targets = document.querySelectorAll(".main-section .grid figure"); |
2 |
const isAnimated = "is-animated"; |
3 |
const threshold = 0.5; |
4 |
|
5 |
function callback(entries, observer) { |
6 |
entries.forEach((entry) => { |
7 |
const elem = entry.target; |
8 |
if (entry.intersectionRatio >= threshold) { |
9 |
elem.classList.add(isAnimated); |
10 |
//observer.unobserve(elem);
|
11 |
} else { |
12 |
elem.classList.remove(isAnimated); |
13 |
}
|
14 |
});
|
15 |
}
|
16 |
|
17 |
const observer = new IntersectionObserver(callback, { threshold }); |
18 |
for (const target of targets) { |
19 |
observer.observe(target); |
20 |
}
|
Aquí están las reglas CSS asociadas que crean la secuencia de las animaciones:
1 |
.main-section figure::before { |
2 |
transition: clip-path 0.3s; |
3 |
}
|
4 |
|
5 |
.main-section figure img { |
6 |
clip-path: inset(0 100% 0 0); |
7 |
transition: clip-path 0.6s 0.3s; |
8 |
}
|
9 |
|
10 |
.main-section figure figcaption { |
11 |
transition: clip-path 0.3s 0.9s; |
12 |
}
|
13 |
|
14 |
.main-section figure::before, |
15 |
.main-section figure figcaption { |
16 |
clip-path: inset(0 0 0 100%); |
17 |
}
|
18 |
|
19 |
.main-section figure.is-animated::before, |
20 |
.main-section figure.is-animated img, |
21 |
.main-section figure.is-animated figcaption { |
22 |
clip-path: inset(0); |
23 |
}
|
Nota: En vez de la propiedad clip-path, también podríamos haber utilizado transform para lograr el mismo efecto. Revisa el tercer ejemplo de este tutorial para que obtengas más información.
Conclusión
¡Eso es todo, amigos! Hoy examinamos una forma de revelar elementos secuencialmente durante el desplazamiento aprovechando las nuevas y sorprendentes herramientas de front-end. Sobre todo, creamos este efecto sin utilizar ninguna biblioteca.
Esperemos que puedas enriquecer tus páginas con un efecto similar.
Como nota al margen, antes de que decidas usar estas funciones en un proyecto que requiera soporte para navegadores más antiguos, verifica la compatibilidad en caniuse.com.
Aquí hay un recordatorio de lo que hemos creado:
Si alguna vez has usado la propiedad clip-path para crear algo útil, ¡háznoslo saber! Y como siempre, ¡muchas gracias por leer!





