Tworzenie efektów slajdów karuzeli

Efekty slajdów karuzeli to świetny sposób na uatrakcyjnienie karuzeli. Gdy użytkownik przewija slajdy, każdy z nich może być animowany, gdy pojawia się, jest wyśrodkowany i znika z obszaru przewijania. Slajdy mogą na przykład pojawiać się i znikać, obracać się lub zmieniać rozmiar. Dzięki temu użytkownicy mogą korzystać z dynamicznych i angażujących treści. W przeciwieństwie do prostych animacji wejścia i wyjścia ten efekt wykorzystuje jedną ciągłą animację do kontrolowania wyglądu slajdu w całym oknie przewijania.

Jak to zrobić?

Aby utworzyć efekty slajdów karuzeli:

  1. Utwórz przewijak: ten element będzie działać jako kontener slajdów karuzeli. W tym przykładzie użyto elementu overflow-x: scroll, aby umożliwić przewijanie w poziomie.

    <ul class="scroller">
      <li class="entry">1</li>
      <li class="entry">2</li>
      <li class="entry">3</li>
      …
    </ul>
    
    .scroller {
      overflow-x: scroll;
    }
    
  2. Zdefiniuj animację: utwórz animację CSS, która definiuje różne stany slajdów podczas ich przechodzenia przez obszar przewijania. Klatki kluczowe możesz definiować dla dowolnej części animacji. Możesz na przykład zdefiniować stan, w którym slajdy znajdują się na środku obszaru przewijania, dodając klatkę kluczową 50%. W tym przykładzie właściwość scale powoduje, że slajdy powiększają się, gdy zbliżają się do środka, i zmniejszają, gdy się od niego oddalają.

    @keyframes animate {
      0% {
        scale: 0.5;
      }
      50% {
        scale: 1;
      }
      100% {
        scale: 0.5;
      }
    }
    
  3. Zastosuj animację i view-timeline: dołącz animację do slajdów karuzeli i połącz ją z view-timeline, która śledzi element podczas przewijania kontenera.

    .scroller > * {
      animation: animate auto linear both;
      animation-timeline: view(inline);
    }
    

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

Przykładowy kod

Ten kod animuje elementy karuzeli w poziomym przewijaniu za pomocą anonimowej osi czasu widoku:

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Sets the animation timeline to use an anonymous view progress timeline, tracking the element's progress through the scroller on the inline axis */
  animation-timeline: view(inline);
}

Ten kod animuje elementy karuzeli w poziomym elemencie przewijania podczas przewijania za pomocą nazwanej osi czasu widoku:

@keyframes animate {
  0% {
    scale: 0.5;
  }

  50% {
    scale: 1;
  }

  100% {
    scale: 0.5;
  }
}

/* This creates a named view-timeline on each carousel item. The timeline is used to drive the animation that is applied on the same element. */
.scroller > * {
  /* Applies the animation using an `auto` duration */
  animation: animate auto linear both;
  /* Defines a named view progress timeline, tracking the element's progress through the scroller on the inline axis */
  view-timeline: --item inline;
  /* Sets the animation timeline to use the named view progress timeline defined above */
  animation-timeline: --item;
}

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ć rozwiązanie zastępcze 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 and animation-range after it to prevent the shorthand from resetting the timeline.

Używaj nazwanej właściwości view-timeline, gdy wiele elementów DOM musi być animowanych na podstawie tej samej osi czasu lub gdy chcesz animować elementy podrzędne elementu, który ma zdefiniowaną właściwość view-timeline. Jeśli element, który animujesz, jest również elementem definiującym view-timeline, możesz użyć anonimowej osi czasu widoku za pomocą view().

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

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

  • UŻYWAJ nazwy klasy CSS <dashed-ident> (np. view-timeline: --my-custom-name).
  • 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.

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 interfejsu Web Animations API (Element.animate()) do tworzenia wstrzymanej animacji dla każdego elementu w karuzeli. Następnie nasłuchuje zdarzenia scroll w elemencie przewijającym i aktualizuje currentTime każdej animacji na podstawie postępu przewijania elementu w elemencie przewijającym.

// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: view()) and (animation-range: entry)')) {
  const scroller = document.querySelector('.scroller');
  const entries = document.querySelectorAll('.entry');

  // Create a map to store animations
  const animations = new Map();

  entries.forEach(entry => {
    const animation = entry.animate(
      {
        scale: ['0.5', '1', '0.5']
      },
      {
        duration: 1, // We'll control the time ourselves
        fill: 'both'
      }
    );
    animation.pause();
    animations.set(entry, animation);
  });

  // Update animations on scroll
  const tick = () => {
    const scrollerRect = scroller.getBoundingClientRect();

    entries.forEach(entry => {
      const animation = animations.get(entry);
      if (!animation) return;

      const entryRect = entry.getBoundingClientRect();
      const progress = (entryRect.left + entryRect.width / 2 - scrollerRect.left) / scrollerRect.width;

      animation.currentTime = progress;
    });
  };
    
  scroller.addEventListener('scroll', tick);
  tick();
}