view-timeline-inset: mover los bordes
Recortar o ampliar el rango de visibilidad para que el efecto arranque antes o después, y su relación con scroll-padding.
Los seis rangos se miden contra el rango de visibilidad, y hasta ahora hemos asumido que ese rectángulo es el scrollport entero. No tiene por qué serlo. view-timeline-inset desplaza sus dos bordes hacia dentro o hacia fuera, y con eso mueve de golpe las cuatro posiciones clave sin tocar una sola línea de animation-range. Es la pieza que convierte “quiero que empiece un poco antes” en una declaración en vez de en una tarde de ajustar porcentajes.
- Declarar
view-timeline-insetcon uno y con dos valores y saber a qué borde afecta cada uno. - Usar valores negativos para adelantar el arranque de un efecto.
- Explicar la relación con
scroll-paddingy por qué existe el valorauto. - Decidir entre ajustar el inset o ajustar el rango ante un mismo requisito.
Dos bordes, dos valores
view-timeline-inset acepta uno o dos valores. Con dos, el primero afecta al borde de inicio del rango de visibilidad y el segundo al borde final. Con uno, se aplica a los dos. Cada valor puede ser auto, una longitud o un porcentaje; los porcentajes se resuelven contra el tamaño del scrollport en el eje de la timeline.
Los valores positivos encogen el rango de visibilidad hacia dentro. Los negativos lo agrandan hacia fuera, más allá de los bordes reales del scrollport.
.tarjeta {
animation: aparecer linear both;
animation-timeline: view();
/* El rango de visibilidad empieza 20% mas abajo del borde superior
y acaba 20% mas arriba del borde inferior */
view-timeline-inset: 20%;
animation-range: entry;
}
Con ese 20%, el elemento no “asoma” a efectos de la timeline hasta que ha entrado un veinte por ciento de la altura de la pantalla. El efecto arranca más tarde y termina antes, y la sensación es la de un revelado más centrado, menos pegado a los bordes.
También se puede pasar dentro de la función anónima, junto al eje:
.tarjeta {
animation-timeline: view(block 20% 10%);
}
Y forma parte del atajo view-timeline, en tercer lugar tras el nombre y el eje:
.hero {
view-timeline: --hero block auto 15%;
}
Con la forma nombrada hay una asimetría importante: el inset se declara en el sujeto, junto al nombre, no en el elemento animado. Tiene todo el sentido —el rango de visibilidad es una propiedad de la timeline, no de quien la consume— y sin embargo es el error de colocación más frecuente cuando se separan sujeto y animado.
Los valores negativos y el arranque anticipado
El caso de uso que justifica la propiedad por sí solo es el revelado que llega tarde. Con animation-range: entry y un elemento pequeño, el efecto empieza cuando el elemento asoma por el borde inferior, es decir, cuando el usuario todavía no lo está mirando, y termina cuando ya está bien dentro. Visualmente el elemento aparece “ya animado” y la animación se desperdicia.
La solución instintiva es tocar el rango: entry 30% entry 100%. Funciona, pero ata el efecto al tamaño del elemento, porque entry dura lo que mide el sujeto. La solución correcta es mover el borde:
.tarjeta {
animation: aparecer linear both;
animation-timeline: view();
view-timeline-inset: auto 25%; /* recorta solo por abajo */
animation-range: entry;
}
Ahora el elemento se considera visible cuando ha subido un veinticinco por ciento de la pantalla, y entry empieza ahí. La diferencia con la solución anterior es que este ajuste está medido contra el viewport, no contra el elemento, así que todas las tarjetas de la página arrancan en el mismo punto de la pantalla independientemente de lo altas que sean. Eso es exactamente lo que quiere el diseño cuando dice “que aparezcan al llegar al tercio inferior”.
Los valores negativos hacen lo contrario: extienden el rango de visibilidad fuera de la pantalla, de modo que la animación arranca antes de que el elemento sea visible de verdad y para cuando aparece ya lleva camino recorrido. Sirve para efectos de continuidad, donde el elemento debe entrar ya en movimiento.
El inset no mueve la ventana: la encoge por los dos lados, y eso significa que un inset simétrico del veinticinco por ciento reduce el rango de visibilidad a la mitad de la pantalla, no a tres cuartos. La aritmética importa porque los rangos nombrados se definen contra ese rectángulo encogido, no contra el scrollport. Con un rango de visibilidad reducido a la mitad, un elemento que medía el sesenta por ciento de la pantalla pasa de ser “más pequeño que el scrollport” a ser más grande que el rango de visibilidad, y con ese cambio de categoría contain invierte su definición: deja de significar “el elemento cabe entero” y pasa a significar “el elemento tapa la ventana”. Tu efecto no se rompe: se convierte en otro efecto, silenciosamente, y solo en los tamaños de pantalla donde el cruce ocurre. Es la causa de una clase entera de bugs que solo se reproducen en tablet y que nadie sabe explicar. La disciplina que los evita: cuando uses insets grandes, comprueba la relación entre la altura del sujeto y el rango de visibilidad resultante, no la del scrollport. Y si necesitas un efecto que no cambie de naturaleza al cruzar ese umbral, usa entry-crossing o exit-crossing, que miden contra un borde y no contra el rectángulo entero.
El valor auto y scroll-padding
El valor inicial es auto, y no significa cero. Significa: usa el scroll-padding correspondiente del scrollport.
Esa conexión existe por un motivo concreto. scroll-padding es la propiedad con la que se le dice al navegador qué zona del scrollport está tapada por interfaz fija —una cabecera pegajosa, una barra de herramientas— para que al hacer scroll a un ancla el destino no quede debajo. Si ya has declarado que los primeros ochenta píxeles de la pantalla están ocupados por una cabecera, sería absurdo que las view timelines siguieran considerando esa franja como visible.
html {
scroll-padding-block-start: 4.5rem; /* la altura de la cabecera fija */
}
/* Sin escribir nada mas, las view timelines de la pagina
consideran que el area visible empieza bajo la cabecera */
Es un valor por defecto bien elegido: hace lo correcto sin que tengas que enterarte, y el día que quieras otra cosa lo sobrescribes con un número. Merece la pena aprovecharlo en lugar de duplicar la altura de la cabecera en dos sitios.
Un solo aviso: auto toma el scroll-padding del scrollport, que en el caso de la página es el que declares en html. Si lo declaras en body, no cuenta.
Inset o rango: cómo decidir
Los dos mecanismos pueden producir el mismo resultado visual en un caso concreto, y por eso conviene tener un criterio en lugar de elegir el que salga primero.
Usa view-timeline-inset cuando lo que quieres expresar es una condición sobre la pantalla: “que empiece cuando llegue al tercio inferior”, “que ignore la franja de la cabecera”, “que se considere fuera cuando le quedan cien píxeles”. El resultado es consistente entre elementos de tamaños distintos.
Usa animation-range cuando lo que quieres expresar es una condición sobre el elemento: “que ocupe la segunda mitad de su entrada”, “que solo se anime mientras está entero en pantalla”, “que empiece a la mitad de su recorrido”.
La prueba para saber cuál toca: pregúntate si el requisito seguiría significando lo mismo con un elemento del doble de alto. Si sí, es una condición de pantalla y va en el inset. Si no, es una condición de elemento y va en el rango.