Dodawanie efektów wejścia i wyjścia do elementów, gdy wchodzą do obszaru przewijania lub go opuszczają

Funkcje internetowe: Animacje sterowane przewijaniem

Efekty wejścia i wyjścia to animacje, które są wywoływane, gdy element pojawia się w obszarze widocznym lub z niego znika. Można go używać do tworzenia atrakcyjnych i dynamicznych treści dla użytkowników. Możesz na przykład użyć efektu wejścia, aby element pojawiał się stopniowo, gdy jest przewijany do widoku, lub efektu wyjścia, aby zmniejszyć element, gdy jest przewijany poza widok.

Jak to zrobić?

Aby dodać do elementu efekty wejścia i wyjścia, musisz połączyć kilka właściwości CSS. Oto szczegółowe instrukcje:

  1. Utwórz osobne @keyframes dla animacji wejść i wyjść obiektów. Animacja wejścia zostanie zastosowana, gdy element pojawi się w widocznym obszarze, a animacja wyjścia – gdy go opuści.

    @keyframes slide-in {
      from { transform: translateX(-100%); }
    }
    @keyframes slide-out {
      to { transform: translateX(100%); }
    }
    
  2. Dołącz do elementu klatki kluczowe wejścia i wyjścia. Możesz to zrobić, definiując wiele animacji we właściwości animation.

    • Ustaw właściwość animation-fill-mode animacji wejścia na backwards, aby zastosować jej stan początkowy przed rozpoczęciem animacji.
    • Ustaw właściwość animation-fill-mode animacji wyjściowej na forwards, aby po zakończeniu animacji zachować jej stan końcowy.
    .animated-element {
      animation:
        slide-in 1s linear backwards,
        slide-out 1s linear forwards;
    }
    
  3. Utwórz oś czasu widoku i połącz ją z animacjami. Oś czasu widoku to typ osi czasu powiązany z widocznością elementu w widocznym obszarze. Możesz utworzyć funkcję za pomocą funkcji view(), a następnie zastosować ją do animacji za pomocą właściwości animation-timeline.

    .animated-element {
      animation-timeline: view();
    }
    

    Domyślnie view() śledzi element na osi block. Jeśli chcesz śledzić go na osi inline, możesz użyć view(inline).

  4. Ogranicz animacje do zakresów entry i exit. Właściwość animation-range pozwala określić, w której części osi czasu ma być odtwarzana animacja.

    • Zakres entry obejmuje czas od momentu, gdy element po raz pierwszy pojawi się w widocznym obszarze, do momentu, gdy będzie w pełni widoczny.
    • Zakres exit obejmuje czas od momentu, gdy element zaczyna opuszczać widoczny obszar, do momentu, gdy jest całkowicie ukryty.
    .animated-element {
      animation-range: entry, exit;
    }
    

Przykładowy kod

Ten kod animuje bezpośrednie elementy podrzędne elementu przewijania podczas przewijania za pomocą anonimowej osi czasu widoku:

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: view()) and (animation-range: entry)) {
    @keyframes grow {
      from {
        scale: 0.5;
      }
    }
    @keyframes shrink {
      to {
        scale: 0.5;
      }
    }

    .scroller > * {
      animation:
        grow auto linear backwards,
        shrink auto linear forwards;
      animation-timeline: view(inline);
      animation-range: entry, exit;
    }
  }
}

Gdy elementy pojawiają się w obszarze przewijania, odtwarzana jest animacja grow, a gdy go opuszczają – animacja shrink.

Poniższy kod daje taki sam efekt wizualny, ale animuje bezpośrednie elementy podrzędne paska przewijania podczas przewijania za pomocą nazwanej osi czasu widoku:

@media (prefers-reduced-motion: no-preference) {
  @supports ((animation-timeline: view()) and (animation-range: entry)) {
    @keyframes grow {
      from {
        scale: 0.5;
      }
    }
    @keyframes shrink {
      to {
        scale: 0.5;
      }
    }

    .scroller > * {
      view-timeline: --tl inline;
      animation:
        grow auto linear backwards,
        shrink auto linear forwards;
      animation-timeline: --tl;
      animation-range: entry, exit;
    }
  }
}

Sprawdzone metody

Podczas korzystania z animacji sterowanych przewijaniem warto stosować kilka sprawdzonych metod, aby zapewnić płynne i dostępne działanie:

  • DO include feature detection: Not all browsers support scroll-driven animations. Użyj @supports ((animation-timeline: view()) and (animation-range: entry)), aby sprawdzić, czy jest obsługiwany, i zapewnić kreację zastępczą w przypadku przeglądarek, które go nie obsługują.
    • MUSISZ uwzględnić tutaj sprawdzenie (animation-range: entry), aby odfiltrować przeglądarki, które obsługują tylko częściowo.
    • NIE używaj pakietu scroll-timeline-polyfill w strategii zastępczej, ponieważ nie jest on kompletny i ma wiele znanych problemów.
    • Jeśli animacja ma charakter wyłącznie dekoracyjny, wybierz progresywne ulepszanie i NIE podawaj kreacji zastępczej.
  • DO respect user preferences: Some users prefer to have less motion on the web. Użyj zapytania o media prefers-reduced-motion, aby wyłączyć lub ograniczyć animacje dla tych użytkowników.
  • DO try to animate only performant CSS properties: For the smoothest animations, stick to animating properties that can be handled by the browser's compositor thread, such as transform and opacity. Animowanie innych właściwości, takich jak width lub height, może powodować problemy z wydajnością.
  • DO use the correct declaration order: When using the animation shorthand property, declare animation-timeline after it to prevent the shorthand from resetting the timeline.

Gdy używasz funkcji view() do tworzenia animacji sterowanej przewijaniem:

  • OPCJONALNIE: określ oś, którą chcesz śledzić. Jeśli nie kierujesz reklam na domyślną oś block (np. w przypadku poziomego paska przewijania), określ oś, którą chcesz śledzić, za pomocą view(block) lub view(inline).
  • Jeśli animacja nie jest stosowana do śledzonego obiektu, użyj osi czasu widoku nazwanego.

Gdy używasz właściwości view-timeline do tworzenia animacji sterowanej przewijaniem:

  • UŻYWAJ nazwy usługi porównywania cen <dashed-ident>.
  • OPCJONALNIE: określ oś, którą chcesz śledzić. Jeśli nie kierujesz reklam na domyślną oś block (np. w przypadku poziomego paska przewijania), określ, którą oś chcesz śledzić za pomocą view-timeline-axis.
  • ZADBAJ o to, aby zakres wyszukiwania działał: gdy element, który deklaruje view-timeline, nie jest przodkiem elementu animowanego w płaskim drzewie, zwiększ widoczność nazwy view-timeline, używając timeline-scope we wspólnym przodku.

Jeśli chcesz animować wiele elementów lub elementów podrzędnych śledzonego obiektu, użyj nazwanego elementu view-timeline.

Obsługa przeglądarek i strategie zastępcze

Dlatego zwykle wymagana jest strategia zastępcza.

W przypadku przeglądarek, które nie obsługują animacji sterowanych przewijaniem, możesz użyć kreacji zastępczej, aby odtworzyć efekty wizualne. Kreacje zastępcze są zwykle tworzone za pomocą detektora przewijania (w przypadku efektów ScrollTimeline) lub interfejsu IntersectionObserver API (w przypadku efektów ViewTimeline).

W przeglądarkach z wbudowaną obsługą animacji opartych na przewijaniu ZAWSZE używaj natywnej implementacji CSS, ponieważ jest ona bardziej wydajna.

Pamiętaj, że nie każdy efekt można odtworzyć za pomocą kreacji zastępczych.

W tym konkretnym przypadku poniższy skrypt stosuje kreację zastępczą w przeglądarkach, które nie obsługują animacji sterowanych przewijaniem. Używa IntersectionObserver do śledzenia widoczności elementu .wrapper i aktualizuje właściwość transform warstw na podstawie pozycji przewijania.

<script>
  if (!CSS.supports('(animation-timeline: view()) and (animation-range: entry)')) {
    const observer = new IntersectionObserver(
      (entries) => {
        for (const entry of entries) {
          // This matches the effect as defined in the CSS example above.
          // Customize this further if needed.
          entry.target.style.scale = 0.5 + entry.intersectionRatio * 0.5;
        }
      },
      {
        threshold: Array.from({ length: 101 }, (_, i) => i / 100),
      }
    );

    document.querySelectorAll('.scroller > *').forEach((el) => {
      observer.observe(el);
    });
  }
</script>