Saltar al contenido principal

Matemática del scroll y CSS personalizado

nota

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​

VariableDónde viveValor
--fa-percentEn línea en todo elemento con activador de scrollProgreso crudo, 0 a 1, sin ninguna ventana aplicada
--fa-scroll--customElementos con una fila CustomLa salida acotada por ventana de esa fila (0 a 1, siguiendo su Start/End/From/To/Invert)
--fa-scroll--{preset}Elementos con ese presetLa salida acotada por ventana de ese preset, p. ej. --fa-scroll--fade
--fa-i, --fa-nVer Sequence / Index / CoverLa 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​

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.

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>).

NecesidadCSS
Mapear a un rango A → Bcalc(A + (B - A) * v) — p. ej. calc(20px + 180px * v)
Una sub-ventana a a b de una filaclamp(0, (v - a) / (b - a), 1) — p. ej. clamp(0, (v - .25) / .5, 1)
Aparecer durante el primer cuartomin(v * 4, 1)
Desaparecer durante el último cuartomin((1 - v) * 4, 1)
Entra, se mantiene y luego sale, desde una filamin(v * 4, (1 - v) * 4, 1)
Una fase distinta por cada hijoclamp(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​

El método difícil

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.

Grabado con Fancy Animations 2.0 (agosto de 2024). El panel se ve distinto hoy; la idea que explica sigue valiendo.

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() o mod() vuelve a 0 en lugar de tu respaldo. Un respaldo de var() 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.
  • Una anulación de breakpoint dentro de @media/@supports nunca parece aplicarse. Bricks mueve todo bloque @media/@supports dentro 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 @media escrito 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.