En-tête qui rétrécit lors du défilement

Un en-tête qui rétrécit au défilement est un modèle d'interface utilisateur courant dans lequel un élément d'en-tête fixe en haut de la page passe progressivement à une taille plus petite lorsque l'utilisateur fait défiler la page vers le bas. Cet effet est souvent utilisé pour maximiser l'espace d'écran pour le contenu principal tout en gardant accessibles les éléments de navigation ou les éléments distinctifs essentiels. Avec les animations CSS liées au défilement, cet effet peut être obtenu de manière déclarative et performante, en associant une animation à la position de défilement du document.

Mise en œuvre

Voici comment créer un en-tête qui se réduit au défilement :

  1. Créer un en-tête fixe : commencez par un élément d'en-tête fixé en haut de la page et ayant une hauteur prédéfinie.

    <header>HEADER</header>
    
    header {
      position: fixed;
      height: 200px;
      top: 0;
      left: 0;
      right: 0;
    }
    
  2. Définir l'animation de réduction : créez une animation CSS qui modifie la hauteur de l'en-tête.

    @keyframes shrink {
      to {
        height: 50px;
      }
    }
    
  3. Appliquer l'animation et la chronologie de défilement : associez l'animation à l'en-tête et utilisez la fonction scroll() pour l'associer à la position de défilement du document.

    header {
      animation: shrink auto linear both;
      animation-timeline: scroll(block root);
    }
    
  4. Définir animation-range : utilisez la propriété animation-range pour spécifier la distance de défilement sur laquelle l'animation doit se produire. Par exemple, pour réduire l'en-tête sur les 150 premiers pixels de défilement, vous devez utiliser animation-range: 0px 150px;.

    header {
      animation-range: 0px 150px;
    }
    

Conseil : Pour éviter que le contenu qui suit l'en-tête ne soit masqué par celui-ci, ajoutez un padding-top au body (ou au conteneur de contenu principal) égal à la hauteur initiale de l'en-tête.

Conseil : Pour vous assurer que le contenu de la page défile de manière synchronisée avec l'en-tête qui rétrécit, définissez la propriété animation-range-end sur la différence entre les tailles de début et de fin. Cela garantit que l'animation se termine précisément lorsque l'en-tête atteint sa taille finale. Dans cette démonstration, l'en-tête passe de 200px à 50px. Par conséquent, animation-range-end est défini sur 150px.

Exemple de code

@keyframes shrink {
  to {
    height: 50px;
  }
}

header {
  animation: shrink auto linear both;
  animation-timeline: scroll(block root);
  animation-range: 0px 150px;
}

Bonnes pratiques

Lorsque vous utilisez des animations basées sur le défilement, il est important de suivre quelques bonnes pratiques pour garantir une expérience fluide et accessible :

  • À FAIRE : incluez la détection de fonctionnalités. Tous les navigateurs ne sont pas compatibles avec les animations déclenchées par le défilement. Utilisez @supports ((animation-timeline: scroll()) and (animation-range: 0% 100%)) pour vérifier la compatibilité et fournir une solution de remplacement pour les navigateurs qui ne sont pas compatibles.
    • La vérification (animation-range: 0% 100%) DOIT être incluse ici pour filtrer les navigateurs qui ne sont que partiellement compatibles.
    • N'UTILISEZ PAS le package scroll-timeline-polyfill pour la stratégie de remplacement, car il n'est pas complet et présente de nombreux problèmes connus.
    • Si l'animation n'est considérée que comme décorative, optez pour l'amélioration progressive et NE FOURNISSEZ PAS de solution de remplacement.
  • À FAIRE : Respectez les préférences des utilisateurs. Certains préfèrent avoir moins de mouvements sur le Web. Utilisez la requête média prefers-reduced-motion pour désactiver ou réduire vos animations pour ces utilisateurs.
  • À FAIRE : Essayez de n'animer que les propriétés CSS performantes. Pour des animations plus fluides, n'animez que les propriétés pouvant être gérées par le thread du compositeur du navigateur, telles que transform et opacity. L'animation d'autres propriétés telles que width ou height peut entraîner des problèmes de performances.
  • À FAIRE : Utilisez l'ordre de déclaration correct. Lorsque vous utilisez la propriété abrégée animation, déclarez animation-timeline et animation-range après pour éviter que la propriété abrégée ne réinitialise la chronologie.

Lorsque vous utilisez la fonction scroll() pour créer une animation basée sur le défilement :

  • FACULTATIF : soyez explicite concernant le conteneur de défilement. Lorsque vous ne ciblez pas le conteneur de défilement ancêtre le plus proche, indiquez explicitement celui que vous souhaitez utiliser avec scroll(root) ou scroll(self).
    • Lorsque root, nearest ou self ne suffisent pas, utilisez une chronologie de défilement nommée.
  • FACULTATIF : indiquez explicitement l'axe à suivre. Lorsque vous ne ciblez pas l'axe block par défaut (par exemple, dans un défilement horizontal), indiquez explicitement l'axe à suivre avec scroll(block) ou scroll(inline).

Pour ce cas d'utilisation spécifique :

  • L'élément que vous animez NE DOIT PAS être position: static ou position: relative lorsque vous utilisez des pourcentages dans animation-range.
    • En effet, ces éléments sont considérés comme "dans le flux". Réduire ces éléments lorsque vous faites défiler la page réduirait la distance de défilement totale, ce qui affecterait la valeur calculée de 10%, par exemple, dans le défilement.

Compatibilité des navigateurs et stratégies de remplacement

Par conséquent, une stratégie de remplacement est généralement requise.

Pour les navigateurs qui ne sont pas compatibles avec les animations déclenchées par le défilement, vous pouvez utiliser une solution de remplacement pour recréer les effets visuels. Les solutions de remplacement sont généralement créées avec un écouteur de défilement (pour les effets ScrollTimeline) ou l'API IntersectionObserver (pour les effets ViewTimeline).

Dans les navigateurs compatibles de manière native avec les animations liées au défilement, utilisez TOUJOURS l'implémentation CSS native, car elle est plus performante.

Notez que tous les effets ne peuvent pas être recréés à l'aide de l'approche de remplacement.

Pour ce cas d'utilisation spécifique, le script suivant applique la solution de remplacement pour les navigateurs qui ne sont pas compatibles avec les animations déclenchées par le défilement. Il utilise un écouteur de défilement pour suivre la position de défilement du document sur une distance de 150px et met à jour la hauteur de l'en-tête en conséquence.

// 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`;
  });
}