Revelados secuenciados
Tres formas de mostrar una lista de pasos, leyendas o imágenes de una en una a medida que la persona hace scroll: usando "Sequence children" (la forma moderna, de 3.1.1 en adelante), una variante de pantalla dividida donde el texto hace scroll normal pero una imagen fija lo sigue, y las ventanas ajustadas a mano que usarías antes de 3.1.1 o cuando los elementos necesitan duraciones distintas.
Secuencia: elementos que se turnan
Los pasos (leyendas, características) aparecen uno tras otro en el mismo lugar mientras el escenario está anclado: el actual sube y se desvanece mientras el siguiente asciende desde abajo. Añadir o quitar un paso no requiere reajustar nada en absoluto.
Estructura (construye primero la escena anclada — una escena de 400vh se ancla entre 20–80%):
div .pin__stage
└─ div .seq__steps "Sequence children", Start 20, End 80 (= la ventana anclada)
├─ div .seq__step "Get parent" + una fila Custom sin Start/End
├─ div .seq__step igual
└─ …
CSS:
.seq__steps {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
gap: 1.5rem;
}
.seq__step {
--seq-on: calc(var(--fa-scroll--custom) * 0 + 1);
--seq-row: calc(var(--fa-scroll--custom) * 0 + 1);
--seq-col: 1 / calc(-1 + var(--fa-scroll--custom) * 0);
--seq-in: min(var(--fa-scroll--custom, 0) * 4, 1);
--seq-out: min((1 - var(--fa-scroll--custom, 0)) * 4, 1);
grid-row: var(--seq-row, auto);
grid-column: var(--seq-col, auto);
opacity: calc(1 - var(--seq-on, 0) * (1 - min(var(--seq-in), var(--seq-out))));
transform: translateY(calc(var(--seq-on, 0) * ((1 - var(--seq-in)) - (1 - var(--seq-out))) * 1rem));
will-change: transform, opacity;
}
.seq__step:first-child { --seq-in: 1; }
.seq__step:last-child { --seq-out: 1; }
--seq-on, --seq-row y --seq-col solo son válidas mientras la animación está realmente en
marcha. Animado, cada paso se apila en la fila 1 a lo largo de todas las columnas; sin la animación
vuelven a auto y simplemente fluyen como una lista ordinaria, totalmente visible (en columnas, si
hay espacio).
Valores que puedes cambiar:
- Start/End de la secuencia: haz que coincidan con la ventana anclada de tu escena.
- Solape de la secuencia (10/25/50/100%): amplía cada ventana hacia sus vecinas. No lo uses para leyendas que se sustituyen entre sí en el mismo lugar — el texto que sale y el que entra quedan ambos medio visibles a la vez y se leen como un enredo. Es adecuado (incluso agradable) para imágenes, que funcionan bien con fundido cruzado.
- El
* 4en--seq-in/--seq-out: una cuarta parte de la ventana de cada paso se usa para el fundido de entrada, otra cuarta parte para el de salida. Un número más alto acorta los fundidos. - La distancia de recorrido de
1rempara el movimiento de entrada/salida.
- Bricks
- Etch
- Padre de los pasos: Sequence children activado, Start 20, End 80 (solape opcional).
- Cada paso: "Get parent" + una fila Custom, sin Start/End propio.
- Pega el CSS de arriba en el CSS personalizado de una clase global compartida por todos los pasos.
- Los pasos se reproducen en el orden en que Bricks realmente los renderiza (su orden interno de elementos) — mantenlo igual al orden que ves en el panel de Estructura.
- Clases del padre de los pasos:
fa--seq fa--seq--start-20 fa--seq--end-80(opcionalmentefa--seq--overlap-25). - Cada paso:
fa--parent fa--custom. :first-child/:last-childse anidan dentro de la clase de.seq__stepcon&.
Problemas comunes:
- Dos leyendas quedan una encima de la otra, ambas medio visibles. Se usó solape en pasos que comparten un mismo lugar — quítalo; el solape es para imágenes, no para leyendas.
- Todos los pasos se solapan en el constructor, o sin JavaScript. La celda de grid compartida se
activó mediante algo distinto a la propia variable de la animación (una clase en el body, o las
variables de índice, que solo existen una vez que JavaScript se ejecuta) — activa el layout usando
una variable calculada puramente a partir de la propia animación, como
--seq-onarriba. - Los pasos nunca cambian mientras está anclado. Falta "Get parent" en los pasos — están midiendo al padre de Sequence, que está él mismo anclado e inmóvil.
- Se ven dos pasos a la vez, o un hueco sin ninguno visible. Se fijó un Start/End a mano en algunos pasos. Deja el Start/End vacío en todos los pasos y ajusta el rango solo en el padre.
- Requiere 3.1.1. En versiones anteriores, usa el patrón de ventanas manuales de más abajo.
Scroll dividido: imagen fija, texto que hace scroll
Dos columnas: en un lado, un marco de imagen permanece fijo; en el otro, bloques de texto hacen scroll con normalidad. Cada imagen está a su plena visibilidad exactamente cuando su bloque de texto correspondiente está centrado en la pantalla, haciendo un fundido cruzado entre imágenes a medida que el texto avanza — y funciona para cualquier número de bloques, sin ventanas por bloque que ajustar.
Estructura:
section .split reinicio de overflow-x, padding 0
└─ div .split__row fila Custom, sin Start/End; suavizado del scroll ~0.2s; se mide a sí misma
├─ div .split__media sticky, una pantalla de alto
│ └─ div .split__frame "Index children"
│ └─ img .split__img ×n apiladas en una misma celda de grid
└─ div .split__texts "Index children"
└─ div .split__text ×n una pantalla de alto cada uno
├─ img .split__text-img una copia de la imagen, mostrada solo en móviles
└─ h3, p
Solo la fila tiene una fila de disparador de scroll; las imágenes y los bloques de texto heredan su
--fa-scroll--custom, y "Index children" le da a cada
uno su posición (--fa-i, desde 0) y el total (--fa-n). Mantén el mismo orden en ambas columnas.
CSS:
.split { padding: 0; overflow-x: initial; }
.split__row { display: flex; flex-direction: row; width: 100%; position: relative; }
.split__media { position: sticky; top: 0; height: 100vh; flex: 1; display: grid; place-items: center; padding: 2rem; }
.split__frame { display: grid; width: min(100%, 30rem); aspect-ratio: 4 / 5; overflow: hidden; border-radius: 1rem; }
.split__img { grid-area: 1 / 1; width: 100%; height: 100%; object-fit: cover; }
.split__texts { flex: 1; padding-inline: clamp(1rem, 5vw, 2rem); } /* la sección no tiene padding propio: el margen vive aquí, móviles incluidos */
.split__text { min-height: 100vh; display: flex; flex-direction: column; justify-content: center; max-width: 32rem; }
.split__text-img { display: none; }
.split__text :is(h2, h3) { color: inherit; } /* los encabezados tomarían el color de encabezado del tema si no — oscuro sobre una sección oscura */
/* el bloque i (desde 0) está centrado cuando p = (i + 1) / (n + 1); s = el bloque actualmente centrado, continuo */
.split__img, .split__text {
--sp-s: clamp(0, var(--fa-scroll--custom) * (var(--fa-n) + 1) - 1, var(--fa-n) - 1);
--sp-d: calc(var(--fa-i) - var(--sp-s));
--sp-on: clamp(0, 1 - (max(var(--sp-d), -1 * var(--sp-d)) - .3) / .4, 1); /* 1 dentro de ±.3, 0 pasado ±.7 */
}
.split__img { opacity: var(--sp-on, 1); scale: calc(1.06 - .06 * var(--sp-on, 1)); }
.split__img:not(:first-child) { opacity: var(--sp-on, 0); }
.split__text { opacity: calc(.3 + .7 * var(--sp-on, 1)); }
@media (max-width: 767px) {
.split .split__row { flex-direction: column; }
.split .split__media { display: none; }
.split .split__text { min-height: 0; padding-block: 3rem; opacity: 1; }
.split .split__text-img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: 1rem; margin-bottom: 1.5rem; }
}
Como cada bloque de texto mide exactamente una pantalla de alto, la fila mide n pantallas de alto
en total, y el bloque i queda centrado en p = (i + 1)/(n + 1) — lo cual funciona con precisión
para 5 o 7 bloques, donde una ventana de rejilla fija del 5% no podría encajar con exactitud. Sin
JavaScript, se muestra la primera imagen y cada bloque de texto está totalmente opaco; en móviles
cada bloque muestra su propia copia de la imagen apilada encima, en lugar de una columna fija.
Valores que puedes cambiar: el par .3/.4 (cuánto tiempo permanece una imagen totalmente
mostrada, y cuánto dura el fundido cruzado), el suelo de opacidad .3 + .7 para los bloques de
texto inactivos, y el zoom inicial 1.06 en las imágenes (usa 1 para ninguno). Mantén cada bloque
de texto exactamente a la misma altura — la fórmula de centrado depende de ello.
- Bricks
- Etch
- Fila: una fila Custom, suavizado del scroll ~0.2s. Columna del marco y de los textos: "Index children". Las propias imágenes y bloques de texto no necesitan ningún ajuste de Fancy.
- Todo el CSS de arriba va en el CSS personalizado de la sección, con cada elemento llevando su clase correspondiente.
- Clases de la fila:
fa--custom fa--smooth-20; columna del marco y de los textos:fa--index. - Las reglas de móvil se anidan como
@media (max-width: 767px) { … }dentro de cada clase.
Problemas comunes:
- Una imagen cambia antes o después de que su texto correspondiente esté realmente centrado. Los bloques de texto no tienen todos la misma altura, o un bloque no es un hijo directo de la columna de textos.
- Todas las imágenes se muestran a la vez. Falta "Index children" en el marco, así que no hay
--fa-icon el que trabajar. - La columna de imagen se desplaza en lugar de quedarse fija. La fila no está estirada a la
altura completa de la columna de textos, o un padre tiene
overflow: hiddenrecortando el comportamiento sticky.
Ventanas manuales
Antes de 3.1.1 (o cuando los elementos realmente necesitan duraciones distintas), dale a cada elemento su propio Start/End a mano en lugar de usar Sequence children. La regla: dale a los hermanos ventanas consecutivas dentro de la ventana anclada de la escena. Cuatro elementos en una escena de 300vh (anclada 25–75%): 35–45, 45–55, 55–65, 65–75. Fundidos de leyenda cortos: 35–40, 45–50, 55–60, y así sucesivamente.
Una baraja de cartas que vuelan una a una
div .pin__stage
└─ div .deck position: relative, flex-grow: 1
├─ div .deck__card "Get parent" + Custom 35–45
├─ div .deck__card "Get parent" + Custom 45–55
├─ div .deck__card … 55–65
└─ div .deck__card … 65–75
.deck { position: relative; flex-grow: 1; }
.deck__card {
position: absolute; top: 10%; height: 80%;
left: calc(3rem * var(--deck-k, 0)); width: calc(100% - 3rem * var(--deck-k, 0));
transform-origin: bottom right;
transform: translateX(calc(var(--fa-scroll--custom, 0) * 200px)) rotate(calc(var(--fa-scroll--custom, 0) * 90deg));
opacity: calc(1 - var(--fa-scroll--custom, 0));
}
.deck__card:nth-child(1) { --deck-k: 3; z-index: 4; }
.deck__card:nth-child(2) { --deck-k: 2; z-index: 3; }
.deck__card:nth-child(3) { --deck-k: 1; z-index: 2; }
.deck__card:nth-child(4) { --deck-k: 0; z-index: 1; }
La primera carta queda encima; cada una por debajo muestra un escalón de 3rem. Añadir una quinta
carta necesita una quinta ventana y una quinta regla :nth-child, y todos los desplazamientos se
corren una posición.
Leyendas con una pausa en el medio
"Reverse" (en la fila de Scroll trigger) produce un pico — entra, y vuelve directo a salir — no una pausa sostenida. Para entrada / pausa / salida, anida dos envoltorios, cada uno con su propia ventana:
div .captions display: grid
└─ div .caption exterior: Fade + Custom, ambos con la misma ventana de "entrada"
└─ div .caption__inner interior: Fade en la ventana de "salida", Inverted
.caption {
--cap-on: calc(var(--fa-scroll--fade) * 0 + 1);
grid-column: 1;
grid-row: calc(var(--cap-row, 1) - (var(--cap-row, 1) - 1) * var(--cap-on, 0));
transform: translateY(calc((1 - var(--fa-scroll--custom, 1)) * 2rem));
}
.caption:nth-child(2) { --cap-row: 2; }
.caption:nth-child(3) { --cap-row: 3; }
Animada, cada leyenda comparte la fila 1; sin la animación cada una obtiene su propia fila y la lista se lee como una lista ordinaria. La primera leyenda también necesita su propia fila de estilo entrada (terminando justo cuando el escenario se ancla), o no tiene nada que active su celda compartida. Para una lista de cualquier longitud real, "Sequence children" es el reemplazo moderno de todo este patrón.
Problemas comunes:
- Un efecto sobre un elemento, solo funciona parte de él. Solo un preset por propiedad CSS por elemento — pon el segundo efecto (la "salida", por ejemplo) en un envoltorio interior.
- Las leyendas se solapan en el constructor, o sin JavaScript. La celda compartida se activó
mediante algo distinto a la propia variable de la animación — actívala como lo hace
--cap-onarriba. - Añadir un elemento rompe toda la sincronización. Es la naturaleza de las ventanas manuales — con 3.1.1, cambia a Sequence children en su lugar.