Pierwsze kroki z animacjami przewijanymi w CSS

1. Zanim zaczniesz

Animacje sterowane przez przewijanie umożliwiają kontrolowanie odtwarzania animacji na podstawie pozycji przewijania kontenera. Oznacza to, że gdy przewijasz w górę lub w dół, animacja przesuwa się do przodu lub do tyłu. Ponadto w przypadku animacji sterowanych przewijaniem możesz też sterować animacją na podstawie pozycji elementu w swoim kontenerze przewijania. Dzięki temu możesz tworzyć ciekawe efekty, takie jak obraz tła z paralaksą, paski postępu przewijania i obrazy, które ujawniają się w miarę pojawiania się na ekranie.

Nowością w Chrome 115 jest obsługa zestawu klas JavaScript i właściwości CSS, które umożliwiają łatwe tworzenie deklaratywnych animacji sterowanych przewijaniem. Te nowe interfejsy API współpracują z dotychczasowymi interfejsami API animacji internetowych i animacji CSS.

Z tego ćwiczenia w Codelabs dowiesz się, jak tworzyć animacje uruchamiane przez przewijanie za pomocą CSS. Po ukończeniu tego ćwiczenia poznasz wiele nowych właściwości CSS wprowadzonych dzięki tej ekscytującej funkcji, takich jak scroll-timeline, view-timeline, animation-timeline i animation-range.

Czego się nauczysz

  • Jak utworzyć efekt tła paralaksy za pomocą oś czasu przewijania w CSS.
  • Jak utworzyć pasek postępu z osią czasu przewijania w CSS.
  • Jak utworzyć efekt ujawniania obrazu za pomocą widoku osi czasu w CSS.
  • Jak kierować reklamy na różne typy zakresów osi czasu w usłudze porównywania cen.

Czego potrzebujesz

Jedna z tych kombinacji urządzeń:

  • najnowsza wersja Chrome (115 lub nowsza) na ChromeOS, macOS lub Windows z włączoną opcją „Experimental Web Platform Features” (Eksperymentalne funkcje platformy internetowej).
  • podstawowa znajomość języka HTML;
  • podstawowa znajomość CSS, zwłaszcza animacji w CSS;

2. Konfiguracja

Wszystko, czego potrzebujesz do tego projektu, jest dostępne w repozytorium GitHub. Aby rozpocząć, skopiuj kod i otwórz go w ulubionym środowisku programistycznym.

  1. Otwórz nową kartę przeglądarki i wejdź na stronę https://github.com/googlechromelabs/io23-scroll-driven-animations-codelab.
  2. Sklonuj repozytorium.
  3. Otwórz kod w wybranym środowisku IDE.
  4. Uruchom npm install, aby zainstalować zależności.
  5. Uruchom npm start i otwórz stronę http://localhost:3000/.
  6. Jeśli nie masz zainstalowanego npm, otwórz plik src/index.html w Chrome.

3. Informacje o harmonogramach animacji

Domyślnie animacja przypisana do elementu jest odtwarzana na osi czasu dokumentu. Oznacza to, że gdy strona się wczytuje, animacja jest odtwarzana w miarę upływu czasu. Jest to domyślna oś czasu animacji i do tej pory była to jedyna oś czasu animacji, do której miałeś/miałaś dostęp.

Dzięki animacjom sterowanym przez przewijanie masz dostęp do 2 nowych typów osi czasu:

  • Przewijanie osi czasu postępu
  • Wyświetlanie osi czasu postępu

W CSS te osi czasu można dołączyć do animacji za pomocą właściwości animation-timeline. Dowiedz się, co oznaczają te nowe osi czasu i czym się od siebie różnią.

Przewijanie osi czasu postępu

Oś czasu postępu przewijania to oś czasu animacji, która jest powiązana z postępem w przesuwaniu pozycji elementu w kontenerze przewijania (zwanym też scrollportem lub scrollerem) wzdłuż określonej osi. Przekształca pozycję w zakresie przewijania w odsetek postępu na osi czasu.

Początkowa pozycja przewijania odpowiada 0% postępu, a końcowa pozycja przewijania – 100%. W tej wizualizacji postęp rośnie od 0% do 100%, gdy przesuwasz suwak w dół.

Wyświetlanie osi czasu postępu

Ten typ osi czasu jest powiązany z względnym postępem danego elementu w kontenerze przewijania. Podobnie jak w przypadku osi czasu postępu przewijania, śledzony jest przesunięcie suwaka. W odróżnieniu od osi czasu postępu przewijania to względna pozycja obiektu na liście sterowania określa postęp. Jest to podobne do IntersectionObserver, które śledzi, jak dużo elementu jest widoczne na liście. Jeśli element nie jest widoczny w rolce, nie przecina się z innymi elementami. Jeśli jest widoczne w rolce – nawet w najmniejszym stopniu – oznacza to, że się przecina.

Czas wyświetlania zaczyna się w momencie, gdy obiekt zaczyna się pokrywać z rolką, i kończy, gdy przestaje się z nią pokrywać. W poniższej wizualizacji widać, że postępy zaczynają się od 0%, gdy obiekt wchodzi do kontenera przewijania, i kończą na 100%, gdy obiekt opuszcza kontener przewijania.

Domyślnie animacja powiązana z osią czasu wyświetlania jest dołączana do całego zakresu tej osi. Rozpoczyna się w momencie, gdy osoba wchodzi do obszaru przewijania, i kończy, gdy osoba opuszcza ten obszar.

Możesz też połączyć go z określoną częścią osi czasu wyświetlania postępu, określając zakres, do którego ma zostać dołączony. Może się to zdarzyć na przykład tylko wtedy, gdy obiekt wchodzi w obszar przewijania. W tej wizualizacji postęp zaczyna się od 0%, gdy obiekt wchodzi do kontenera przewijania, ale osiąga 100% od momentu, gdy całkowicie się z nim pokryje.

Dostępne zakresy osi czasu, na które możesz kierować reklamy, to cover, contain, entry, exit, entry-crossing i exit-crossing. Te zakresy są opisane w późniejszych częściach tego Codelab, ale jeśli nie możesz się już doczekać, aby je poznać, skorzystaj z narzędzia dostępnego pod adresem https://goo.gle/view-timeline-range-tool, aby dowiedzieć się, co oznacza każdy z nich.

4. Tworzenie efektu paralaksy w tle

Pierwszy efekt, który należy dodać do strony, to efekt tła paralaksy na głównym obrazie tła. Gdy przewijasz stronę w dół, obraz tła powinien się przesuwać, ale z inną prędkością. W tym celu możesz użyć osi czasu postępu przewijania.

Aby to zrobić, wykonaj 2 kroki:

  1. Utwórz animację, która zmienia pozycję obrazu tła.
  2. Połącz animację z przewijaniem dokumentu.

Tworzenie animacji

  1. Aby utworzyć animację, użyj zwykłego zestawu klatek kluczowych. Przesuń pozycję tła w pionie od 0% do 100%:

src/styles.css

@keyframes move-background {
  from {
    background-position: 50% 0%;
  }
  to {
    background-position: 50% 100%;
  }
}
  1. Teraz dołącz te klatki kluczowe do elementu body:

src/styles.css

body {
  animation: 1s linear move-background;
}

Dzięki temu kodowi animacja move-background zostanie dodana do elementu body. Właściwość animation-duration jest ustawiona na 1 sekundę i korzysta z wygładzania linear.

Najprostszym sposobem utworzenia osi czasu postępu przewijania jest użycie funkcji scroll(). Spowoduje to utworzenie anonimowej osi czasu postępu przewijania, którą możesz ustawić jako wartość właściwości animation-timeline.

Funkcja scroll() przyjmuje argumenty <scroller> i <axis>.

Akceptowane wartości argumentu <scroller>:

  • nearest. Używa kontenera przewijania najbliższego przodka (domyślnie).
  • root. Używa widoku dokumentu jako elementu przewijania.
  • self. Używa samego elementu jako kontenera przewijania.

Akceptowane wartości argumentu <axis>:

  • block. Używa pomiaru postępu wzdłuż osi bloku kontenera przewijania (domyślnie).
  • inline. Używa pomiaru postępu wzdłuż osi wstawionej w kontenerze przewijania.
  • y. Używa pomiaru postępu wzdłuż osi y kontenera przewijania.
  • x. Używa pomiaru postępu wzdłuż osi x kontenera przewijania.

Aby połączyć animację z głównym scrollerem na osi bloku, wartościami do przekazania do scroll()rootblock. Łączna wartość to scroll(root block).

  • Ustaw wartość scroll(root block) dla właściwości animation-timeline w treści.
  • Ponadto animation-duration wyrażone w sekundach nie ma sensu, dlatego ustaw czas trwania na auto. Jeśli nie podasz wartości animation-duration, zostanie użyta wartość domyślna auto.

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(root block);
}

Ponieważ scroller główny jest też najbliższym scrollerem nadrzędnym elementu body, możesz użyć wartości nearest:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll(nearest block);
}

Wartości nearestblock są wartościami domyślnymi, więc możesz je pominąć. W takim przypadku kod można uprościć do tego:

src/styles.css

body {
  animation: linear move-background;
  animation-duration: auto;
  animation-timeline: scroll();
}

Weryfikowanie zmian

Jeśli wszystko poszło dobrze, powinno to wyglądać tak:

Jeśli nie, przejdź do gałęzi kodu solution-step-1.

5. Tworzenie paska postępu dla galerii obrazów

Na stronie znajduje się pozioma karuzela, która wymaga paska postępu, aby wskazać, które zdjęcie jest aktualnie wyświetlane.

Oto jak wygląda znacznik rozkładu karuzeli:

src/index.html

<div class="gallery">
  <div class="gallery__scrollcontainer" style="--num-images: 3;">
    <div class="gallery__progress"></div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
    <div class="gallery__entry">
      ...
    </div>
  </div>
</div>

Klatki kluczowe paska postępu są już ustawione i wyglądają tak:

src/styles.css

@keyframes adjust-progress {
  from {
    transform: scaleX(calc(1 / var(--num-images)));
  }
  to {
    transform: scaleX(1);
  }
}

Animację należy dołączyć do .Element gallery__progress z osią czasu postępu przewijania. Jak pokazano w poprzednim kroku, możesz to zrobić, tworząc anonimową oś czasu postępu przewijania za pomocą funkcji scroll():

src/styles.css

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  animation-timeline: scroll(nearest inline);
}

Ten fragment kodu może się wydawać skuteczny, ale tak nie jest z powodu sposobu działania automatycznego wyszukiwania kontenera przewijania za pomocą funkcji nearest. Podczas wyszukiwania najbliższego scrollera element będzie uwzględniać tylko te elementy, które mogą wpływać na jego pozycję. Ponieważ element .gallery__progress ma pozycjonowanie bezwzględne, pierwszym elementem nadrzędnym, który określi jego położenie, jest element .gallery, ponieważ ma on zastosowane atrybuty position: relative. Oznacza to, że element .gallery__scrollcontainer, czyli suwak, który ma być docelowo obsługiwany, nie jest w ogóle uwzględniany podczas tego automatycznego wyszukiwania.

Aby rozwiązać ten problem, utwórz w elemencie .gallery__scrollcontainer o nazwie Czaszka postępu przewijania i połącz z nim element .gallery__progress, używając tej nazwy.

Aby utworzyć nazwany osi czasu postępu przewijania w elemencie, ustaw w przypadku właściwości CSS scroll-timeline-name w kontenerze przewijania dowolną wartość. Wartość musi się zaczynać od --.

Ponieważ galeria przewija się poziomo, musisz też ustawić właściwość scroll-timeline-axis. Dozwolone wartości są takie same jak argument <axis> funkcji scroll().

Aby połączyć animację z osią czasu postępu przewijania, ustaw w elementach, które mają być animowane, właściwość animation-timeline na taką samą wartość jak identyfikator użyty w elementach scroll-timeline-name.

  • Zmień plik styles.css, aby zawierał:

src/styles.css

.gallery__scrollcontainer {
  /* Create the gallery-is-scrolling timeline */
  scroll-timeline-name: --gallery-is-scrolling;
  scroll-timeline-axis: inline;
}

.gallery__progress {
  animation: linear adjust-progress;
  animation-duration: auto;
  /* Set gallery-is-scrolling as the timeline */
  animation-timeline: --gallery-is-scrolling;
}

Weryfikowanie zmian

Jeśli wszystko poszło dobrze, powinno to wyglądać tak:

Jeśli nie, przejdź do gałęzi kodu solution-step-2.

6. Animowanie obrazów w galerii, gdy pojawiają się i znikają z przesuwnego okienka

Konfigurowanie anonimowej osi czasu podglądu

Ciekawym efektem jest stopniowe pojawianie się obrazów w galerii. Możesz do tego użyć osi czasu wyświetlania postępu.

Aby utworzyć oś czasu wyświetlania postępów, możesz użyć funkcji view(). Akceptowane argumenty to <axis><view-timeline-inset>.

  • Wartość <axis> jest taka sama jak na osi czasu postępu przewijania i określa, którą oś ma być śledzona.
  • Za pomocą <view-timeline-inset> możesz określić przesunięcie (dodatnie lub ujemne), aby dostosować granice, w których element jest widoczny, a w których nie.
  • Kluczowe klatki są już ustawione, więc wystarczy je załączyć. Aby to zrobić, utwórz oś czasu wyświetlania postępu dla każdego elementu .gallery__entry.

src/styles.css

@keyframes animate-in {
  from {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  to {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Ograniczanie zakresu osi czasu podglądu

Jeśli zapiszesz kod CSS i załadujesz stronę, elementy będą się rozjaśniać, ale coś będzie nie tak. Zaczną się od wartości krycia 0, gdy są całkowicie niewidoczne, i skończą dopiero przy wartości krycia 1, gdy całkowicie znikną.

Dzieje się tak, ponieważ domyślny zakres osi czasu „Postęp oglądania” obejmuje cały film. Nazywamy to zakresem cover.

  1. Aby kierować animację tylko na zakres entry obiektu, użyj właściwości CSS animation-range, aby ograniczyć czas jej działania.

src/styles.css

.gallery__entry {
  animation: linear fade-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry 0% entry 100%;
}

Animacja przebiega teraz od entry 0% (przedmiot wkracza w scroller) do entry 100% (przedmiot wkracza w scroller).

Dostępne zakresy widoku osi czasu:

  • cover. Reprezentuje pełny zakres osi czasu postępu wyświetlania.
  • entry. Reprezentuje zakres, w którym główne pole wchodzi w zakres widoczności postępu wyświetlania.
  • exit. Określa zakres, w którym główne pole opuszcza zakres widoczności postępu widoku.
  • entry-crossing. Określa zakres, w którym główne pole przecina krawędź końcową.
  • exit-crossing. Określa zakres, w którym główne pole przecina krawędź początkową.
  • contain. Reprezentuje zakres, w którym pole główne jest w pełni zawarte w zakresie widoczności postępu wyświetlania w obszarze przewijania lub całkowicie pokrywa ten zakres. To zależy od tego, czy obiekt jest wyższy czy niższy od kółka przewijania.

Aby dowiedzieć się, co oznaczają poszczególne zakresy i jak odnoszą się do siebie wartości procentowe na pozycjach początkowych i końcowych, skorzystaj z narzędzia dostępnego pod adresem https://goo.gle/view-timeline-range-tool.

  1. Ponieważ zakresy początkowy i końcowy są tu takie same i używane są domyślne przesunięcia, uprość animation-range do pojedynczej nazwy zakresu animacji:

src/styles.css

.gallery__entry {
  animation: linear animate-in;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry;
}
  • Aby obrazy znikały po opuszczeniu scrollera, możesz użyć tej samej animacji, co w przypadku animacji wjazdu, ale z innym zakresem.

src/styles.css

@keyframes animate-out {
  from {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  to {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}

.gallery__entry {
  animation: linear animate-in, linear animate-out;
  animation-duration: auto;
  animation-timeline: view(inline);
  animation-range: entry, exit;
}

Klatki kluczowe animate-in zostaną zastosowane do zakresu entry, a klatki kluczowe animate-out do zakresu exit.

Weryfikowanie zmian

Jeśli wszystko poszło dobrze, powinno wyglądać to tak:

Jeśli nie, przejdź do gałęzi kodu solution-step-3.

7. Animowanie obrazów w galerii, gdy wchodzą i wychodzą z przesuwania, za pomocą jednego zestawu klatek kluczowych

Przypadek jednego zestawu klatek kluczowych

Zamiast dołączać 2 animacji do różnych zakresów, możesz utworzyć jeden zestaw klatek kluczowych, który zawiera informacje o zakresie.

Kształt klatek 2D wygląda tak:

@keyframes keyframes-name {
  range-name range-offset {
    ...
  }
  range-name range-offset {
    ...
  }
}
  1. Połącz klatki kluczowe z efektem łagodnego pojawiania się i znikania w ten sposób:

src/styles.css

@keyframes animate-in-and-out {
  entry 0% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
  entry 90% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }

  exit 10% {
    opacity: 1;
    clip-path: inset(0% 0% 0% 0%);
  }
  exit 100% {
    opacity: 0;
    clip-path: inset(50% 0% 50% 0%);
  }
}
  1. Gdy informacje o zakresie są obecne w klatkach kluczowych, nie musisz już osobno określać wartości animation-range. Załącz klatki kluczowe jako właściwość animation.

src/styles.css

.gallery__entry {
  animation: linear animate-in-and-out both;
  animation-duration: auto;
  animation-timeline: view(inline);
}

Weryfikowanie zmian

Jeśli wszystko przebiegło prawidłowo, powinieneś uzyskać ten sam wynik co w poprzednim kroku. Jeśli nie, przejdź do gałęzi kodu solution-step-4.

8. Gratulacje!

Po ukończeniu tego ćwiczenia wiesz, jak tworzyć ścieżki postępu przewijania i wyświetlania w CSS.

Więcej informacji

Zasoby: