Un encabezado que se reduce al desplazarse es un patrón de IU común en el que un elemento de encabezado fijo en la parte superior de la página cambia de forma fluida a un tamaño más pequeño a medida que el usuario se desplaza hacia abajo. Este efecto se suele usar para maximizar el espacio de la pantalla para el contenido principal, a la vez que se mantienen accesibles los elementos de navegación o de desarrollo de la marca esenciales. Con las animaciones basadas en desplazamientos de CSS, este efecto se puede lograr de forma declarativa y eficiente, ya que se vincula una animación a la posición de desplazamiento del documento.
Cómo implementarlo
Sigue estos pasos para crear un encabezado que se reduzca al desplazarse:
Crea un encabezado fijo: Comienza con un elemento de encabezado que esté fijo en la parte superior de la página y tenga una altura predefinida.
<header>HEADER</header>header { position: fixed; height: 200px; top: 0; left: 0; right: 0; }Define la animación de reducción: Crea una animación de CSS que cambie la altura del encabezado.
@keyframes shrink { to { height: 50px; } }Aplica la animación y la línea de tiempo de desplazamiento: Adjunta la animación al encabezado y usa la función
scroll()para vincularla a la posición de desplazamiento del documento.header { animation: shrink auto linear both; animation-timeline: scroll(block root); }Establece el
animation-range: Usa la propiedadanimation-rangepara especificar la distancia de desplazamiento en la que debe ocurrir la animación. Por ejemplo, para reducir el encabezado en los primeros 150 píxeles de desplazamiento, usaríasanimation-range: 0px 150px;.header { animation-range: 0px 150px; }
Sugerencia: Para evitar que el encabezado oculte el contenido que lo sigue, agrega un padding-top al body (o al contenedor de contenido principal) que sea igual a la altura inicial del encabezado.
Sugerencia: Para asegurarte de que el contenido de la página se desplace en sincronización con el encabezado que se reduce, establece el animation-range-end en la diferencia entre los tamaños de inicio y finalización. Esto garantiza que la animación se complete exactamente cuando el encabezado alcance su tamaño final. En esta demostración, el encabezado se reduce de 200px a 50px, por lo que animation-range-end se establece en 150px.
Ejemplo de código
@keyframes shrink {
to {
height: 50px;
}
}
header {
animation: shrink auto linear both;
animation-timeline: scroll(block root);
animation-range: 0px 150px;
}
Prácticas recomendadas
Cuando uses animaciones controladas por el desplazamiento, es importante que sigas algunas prácticas recomendadas para garantizar una experiencia fluida y accesible:
- SÍ incluye la detección de funciones: No todos los navegadores admiten animaciones controladas por el desplazamiento. Usa
@supports ((animation-timeline: scroll()) and (animation-range: 0% 100%))para verificar la compatibilidad y proporcionar un resguardo para los navegadores que no lo admiten.- La verificación de
(animation-range: 0% 100%)DEBE incluirse aquí para filtrar los navegadores que solo tienen compatibilidad parcial. - NO uses el paquete
scroll-timeline-polyfillpara la estrategia de resguardo, ya que no tiene todas las funciones y tiene muchos problemas conocidos. - Si la animación solo se considera decorativa, opta por la mejora progresiva y NO proporciones un resguardo.
- La verificación de
- SÍ respeta las preferencias del usuario: Algunos usuarios prefieren tener menos movimiento en la Web. Usa la consulta de medios
prefers-reduced-motionpara inhabilitar o reducir las animaciones para estos usuarios. - SÍ intenta animar solo las propiedades de CSS que tengan un buen rendimiento: Para obtener las animaciones más fluidas, limítate a animar las propiedades que pueda controlar el subproceso del compositor del navegador, como
transformyopacity. Animar otras propiedades, comowidthoheight, puede provocar problemas de rendimiento. - SÍ uses el orden de declaración correcto: Cuando uses la propiedad abreviada
animation, declaraanimation-timelineyanimation-rangedespués de ella para evitar que la abreviatura restablezca la línea de tiempo.
Cuando uses la función scroll() para crear una animación controlada por el desplazamiento, ten en cuenta lo siguiente:
- OPCIONAL Sé explícito sobre el elemento de desplazamiento: Cuando no se oriente al elemento de desplazamiento principal más cercano, sé explícito sobre qué elemento de desplazamiento deseas usar con
scroll(root)oscroll(self).- Cuando
root,nearestoselfno sean suficientes, usa un scroll-timeline con nombre.
- Cuando
- OPCIONAL Sé explícito sobre el eje que se debe seguir: Cuando no se oriente al eje
blockpredeterminado (como en un desplazador horizontal), sé explícito sobre qué eje se debe seguir conscroll(block)oscroll(inline).
En cuanto a este caso de uso específico:
- El elemento que animas DEBE no ser
position: staticniposition: relativecuando se usan porcentajes enanimation-range.- Esto se debe a que esos elementos se consideran “en flujo”. Reducir esos elementos a medida que te desplazas reduciría la distancia total de desplazamiento, lo que afectaría el valor calculado de, por ejemplo,
10%en el desplazamiento.
- Esto se debe a que esos elementos se consideran “en flujo”. Reducir esos elementos a medida que te desplazas reduciría la distancia total de desplazamiento, lo que afectaría el valor calculado de, por ejemplo,
Compatibilidad con navegadores y estrategias de resguardo
Por lo tanto, suele ser necesaria una estrategia de resguardo.
En el caso de los navegadores que no admiten animaciones basadas en el desplazamiento, puedes usar un resguardo para recrear los efectos visuales. Por lo general, las alternativas se crean con un objeto de escucha de desplazamiento (para los efectos de ScrollTimeline) o la API de IntersectionObserver (para los efectos de ViewTimeline).
En los navegadores con compatibilidad integrada para animaciones basadas en el desplazamiento, usa SIEMPRE la implementación nativa de CSS, ya que tiene un mejor rendimiento.
Ten en cuenta que no todos los efectos se pueden recrear con el enfoque de resguardos.
Específicamente para este caso de uso, la siguiente secuencia de comandos aplica el resguardo para los navegadores que no admiten animaciones controladas por el desplazamiento. Usa un objeto de escucha de desplazamiento para hacer un seguimiento de la posición de desplazamiento del documento en una distancia de 150px y actualiza la altura del encabezado según corresponda.
// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
const header = document.querySelector('header');
const initialHeight = 200;
const finalHeight = 50;
const scrollDistance = 150;
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const scrollPercent = Math.min(1, scrollY / scrollDistance);
const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;
header.style.height = `${newHeight}px`;
});
}