Matemática del scroll y CSS personalizado
La mayoría de los efectos se consiguen por completo con los presets ya listos de Activador de scroll — no necesitas nada de esta página para el uso del día a día. Esta página es para desarrolladores y montajes avanzados: es lo que te da el preset Custom, y así es como están construidas de verdad las Recetas avanzadas.
El preset Custom en Activador de scroll no anima nada por sí mismo — solo expone el progreso de scroll acotado por ventana del elemento como una propiedad personalizada de CSS, para que la uses en tu propio CSS. Así es como controlas más de una propiedad desde una sola fila de scroll, o construyes un efecto que ninguno de los presets integrados cubre.
Las variables
| Variable | Dónde vive | Valor |
|---|---|---|
--fa-percent | En línea en todo elemento con activador de scroll | Progreso crudo, 0 a 1, sin ninguna ventana aplicada |
--fa-scroll--custom | Elementos con una fila Custom | La salida acotada por ventana de esa fila (0 a 1, siguiendo su Start/End/From/To/Invert) |
--fa-scroll--{preset} | Elementos con ese preset | La salida acotada por ventana de ese preset, p. ej. --fa-scroll--fade |
--fa-i, --fa-n | Ver Sequence / Index / Cover | La posición de un hijo (desde 0) y el conteo total |
Estas son todas propiedades CSS personalizadas normales, lo que significa que heredan — una sola fila Custom en un elemento padre puede controlar cualquier cantidad de descendientes a la vez. Un descendiente con su propia fila Custom obtiene su propio valor en su lugar, ensombreciendo el del padre para todo lo que esté por debajo.
Escribiendo el CSS
- Bricks
- Etch
- Gutenberg
Escribe el CSS en el campo de CSS personalizado propio del elemento, usando %root% como selector
(Bricks lo reemplaza por el id real del elemento al renderizar):
%root% {
opacity: var(--fa-scroll--custom, 1);
transform: translateY(calc((1 - var(--fa-scroll--custom, 1)) * 60px))
scale(calc(.9 + var(--fa-scroll--custom, 1) * .1));
}
En una clase global, %root% representa el propio selector de la clase.
Escribe las mismas declaraciones directamente dentro de la propia clase del elemento en el Style Manager:
.my-element {
opacity: var(--fa-scroll--custom, 1);
transform: translateY(calc((1 - var(--fa-scroll--custom, 1)) * 60px))
scale(calc(.9 + var(--fa-scroll--custom, 1) * .1));
}
Elige "Custom" como la Animation en el panel Scroll Trigger Animations, y luego escribe el CSS contra una clase que hayas añadido al bloque en Advanced → Additional CSS class(es).
Dale siempre a tu var() un valor de respaldo. La variable no existe en absoluto cuando el
script de scroll todavía no se ha ejecutado (sin JavaScript, o una vista previa del editor) — o
cuando "Disable from tablet/mobile" está activo en ese ancho. El valor de respaldo es lo que verán
los visitantes en ese estado: usa var(--fa-scroll--custom, 0) cuando el aspecto sin animar deba
coincidir con el inicio de la animación, o var(--fa-scroll--custom, 1) cuando deba coincidir con
el final (para algo que debe permanecer visible y en su sitio sin JavaScript).
Patrones matemáticos útiles
En la tabla de abajo, v representa var(--fa-scroll--custom, <respaldo>).
| Necesidad | CSS |
|---|---|
| Mapear a un rango A → B | calc(A + (B - A) * v) — p. ej. calc(20px + 180px * v) |
Una sub-ventana a a b de una fila | clamp(0, (v - a) / (b - a), 1) — p. ej. clamp(0, (v - .25) / .5, 1) |
| Aparecer durante el primer cuarto | min(v * 4, 1) |
| Desaparecer durante el último cuarto | min((1 - v) * 4, 1) |
| Entra, se mantiene y luego sale, desde una fila | min(v * 4, (1 - v) * 4, 1) |
| Una fase distinta por cada hijo | clamp(0, v * var(--fa-n, 1) - var(--fa-i, 0), 1) — ver Sequence / Index / Cover |
| "¿Realmente se está ejecutando la animación?" | Define --fa-on: calc(var(--fa-scroll--custom) * 0 + 1); sin respaldo a propósito, y léela en otro sitio como var(--fa-on, 0) |
Ese último patrón es útil para un layout que solo tiene sentido mientras se anima — leyendas que comparten una misma celda de grid, por ejemplo, que deberían apilarse como una lista normal cuando no hay ninguna animación en marcha:
%root% {
--row: calc(var(--fa-scroll--custom) * 0 + 1);
grid-row: var(--row, auto);
}
Prefiere una fila con varias fases recortadas con clamp() antes que varias filas separadas
apiladas en el mismo elemento — mantiene todo en una sola línea de tiempo y es mucho más fácil de
razonar.
Cualquier ventana, no solo múltiplos de 5
Start y End solo aceptan múltiplos de 5 en el panel del builder. Para usar un valor exacto como
.33, deja Start/End vacíos en el panel y define las variables subyacentes directamente en CSS en
su lugar:
%root% {
--fa-start--custom: .33;
--fa-end--custom: .67;
}
No combines esto con un valor de Start/End fijado en el panel para el mismo preset — cuál de los
dos gana entonces depende de la especificidad de CSS y del orden de origen, lo cual es frágil.
Ten en cuenta también que las ventanas heredan: una fila Custom anidada con Start/End vacíos usa
el --fa-start--custom / --fa-end--custom de su ancestro más cercano en lugar de recurrir por
defecto a 0–100. Dale a las filas anidadas su propio Start/End explícito, o resetéalas:
%root% { --fa-start--custom: 0; --fa-end--custom: 1; }.
Un número que cuenta ligado al scroll
Para animar un entero (digamos, una estadística que cuenta de 2015 a 2025), regístralo como una propiedad personalizada tipada y léelo con un contador CSS:
@property --year {
syntax: '<integer>';
inherits: true;
initial-value: 2015;
}
.year {
--year: calc(2015 + var(--fa-scroll--custom, 0) * 10);
counter-reset: year var(--year);
}
.year::before {
content: counter(year);
}
La regla @property debe estar en el nivel superior de tu CSS — en Bricks, fuera del bloque
%root% {}; en Etch, en una hoja de estilos global en lugar de dentro de una clase. Esto necesita
Chrome; Safari 16.4 y Firefox 128 o posteriores también lo soportan.
Vídeo explicativo
Este vídeo construye la animación escribiendo clases y CSS personalizado a mano, la vía de desarrollador. Para la mayoría de los efectos, el panel ScrollTrigger Animations llega más rápido y sin código: usa esto solo cuando ningún preset encaje.
Problemas comunes
- Piezas de texto que comparten una celda de grid se superponen en el builder o sin
JavaScript. El layout fue activado por algo distinto de la propia animación (una clase del
body, por ejemplo). Condiciónalo a
var(--fa-on, 0)como se muestra arriba en su lugar. - El progreso parece desviarse mientras el propio elemento escala o se mueve. El plugin mide la caja del elemento después de que se aplican los transforms — si el elemento medido (o su "I am parent") está siendo transformado él mismo, su propia medición sigue cambiando. Mantenlo sin transformar y anima un hijo en su lugar.
- Un valor basado en
round()omod()vuelve a 0 en lugar de tu respaldo. Un respaldo devar()no rescata una función CSS no soportada — toda la declaración es inválida. Pon la función moderna dentro de@supports, con un valor plano seguro fuera. - Una propiedad silenciosamente se vuelve 0 o
none. Estás leyendo una variable que no existe en ningún sitio — revisa bien el nombre exacto, o añade un respaldo.
- Bricks
- Una anulación de breakpoint dentro de
@media/@supportsnunca parece aplicarse. Bricks mueve todo bloque@media/@supportsdentro del CSS personalizado a la parte superior de la hoja de estilos generada al guardar, así que una regla pensada para anular algo más adelante en el archivo pierde por el orden de origen. Escribe el CSS específico de breakpoint en el campo de CSS personalizado por breakpoint del elemento (p. ej. "Custom CSS — Mobile Landscape") en lugar de un bloque@mediaescrito a mano, y dale al valor por defecto que estás anulando especificidad cero con:where(.your-class)para que el orden no pueda importar.