Scrollytelling to popularna technika używana do tworzenia angażujących i wciągających treści internetowych. Polega na animowaniu elementów na stronie podczas przewijania, co pozwala na skuteczne opowiedzenie historii lub przeprowadzenie użytkownika przez narrację. Dzięki animacjom CSS opartym na przewijaniu możesz tworzyć te efekty bezpośrednio w CSS, bez konieczności korzystania z JavaScriptu. Animacje są kontrolowane przez pozycję przewijania, a nie przez zegar, co zapewnia ich synchronizację z przewijaniem przez użytkownika.
Jak to zrobić?
Aby utworzyć efekt scrollytellingu, potrzebujesz 2 zestawów elementów: jednego do śledzenia pozycji przewijania i drugiego do animacji.
Najpierw zdefiniuj nazwany view-timeline w elementach, które chcesz śledzić. Będą one służyć jako czynniki sterujące animacjami.
#tracked {
section:nth-child(1){ view-timeline: --tl-1 block; }
section:nth-child(2){ view-timeline: --tl-2 block; }
section:nth-child(3){ view-timeline: --tl-3 block; }
section:nth-child(4){ view-timeline: --tl-4 block; }
section:nth-child(5){ view-timeline: --tl-5 block; }
}
Następnie zastosuj animacje do elementów, które chcesz animować, i połącz je z utworzonymi osiami czasu za pomocą właściwości animation-timeline.
#animated {
section {
animation: animate-in auto linear both, animate-out auto linear forwards;
animation-range: entry 25% cover 50%, exit 50% exit 75%;
}
section:nth-child(1){ animation-timeline: --tl-1; }
section:nth-child(2){ animation-timeline: --tl-2; }
section:nth-child(3){ animation-timeline: --tl-3; }
section:nth-child(4){ animation-timeline: --tl-4; }
section:nth-child(5){ animation-timeline: --tl-5; }
}
Aby animation-timeline mogła odwoływać się do nazwanych osi czasu, muszą one znajdować się w tym samym zakresie. Możesz użyć właściwości timeline-scope we wspólnym elemencie nadrzędnym, aby udostępnić osie czasu wszystkim elementom, które ich potrzebują. Często dobrym wyborem jest element :root.
html {
timeline-scope: --tl-1, --tl-2, --tl-3, --tl-4, --tl-5;
}
Możesz też użyć właściwości animation-range, aby określić dokładny zakres osi czasu, w którym animacja ma być odtwarzana. Dzięki temu masz pełną kontrolę nad tym, kiedy animacje są uruchamiane i jak przebiegają.
#animated section {
animation-range: entry 25% cover 50%, exit 50% exit 75%;
}
Przykładowy kod
html {
timeline-scope: --tl-1, --tl-2, --tl-3, --tl-4, --tl-5;
}
#tracked {
section:nth-child(1){ view-timeline: --tl-1 block; }
section:nth-child(2){ view-timeline: --tl-2 block; }
section:nth-child(3){ view-timeline: --tl-3 block; }
section:nth-child(4){ view-timeline: --tl-4 block; }
section:nth-child(5){ view-timeline: --tl-5 block; }
}
@keyframes animate-in {
from { scale: 0.5; opacity: 0; transform: rotateY(-180deg); }
to { transform: rotateY(0deg); }
}
@keyframes animate-out {
to { translate: 100% 0; opacity: 0; }
}
#animated {
section {
animation: animate-in auto linear both, animate-out auto linear forwards;
animation-range: entry 25% cover 50%, exit 50% exit 75%;
backface-visibility: hidden;
}
section:nth-child(1){ animation-timeline: --tl-1; }
section:nth-child(2){ animation-timeline: --tl-2; }
section:nth-child(3){ animation-timeline: --tl-3; }
section:nth-child(4){ animation-timeline: --tl-4; }
section:nth-child(5){ animation-timeline: --tl-5; }
}
/* MANDATORY Copy-Paste Safety: Disable continuous storytelling motion for sensitive users */
@media (prefers-reduced-motion: reduce) {
#animated section {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
}
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: scroll()) and (animation-range: 0% 100%)), 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: 0% 100%), aby odfiltrować przeglądarki, które obsługują tylko częściowo. - NIE używaj pakietu
scroll-timeline-polyfillw 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.
- MUSISZ uwzględnić tutaj sprawdzenie
- 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
transformandopacity. Animowanie innych właściwości, takich jakwidthlubheight, może powodować problemy z wydajnością. - DO use the correct declaration order: When using the
animationshorthand property, declareanimation-timelineandanimation-rangeafter it to prevent the shorthand from resetting the timeline.
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ść nazwyview-timeline, używająctimeline-scopewe wspólnym przodku.
Strategie zastępcze
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 IntersectionObserver do śledzenia widoczności każdego elementu #tracked section i odpowiednio aktualizuje właściwość transform odpowiedniego elementu #animated section.
const animatedSections = document.querySelectorAll('#animated section');
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
const sectionIndex = Array.from(document.querySelectorAll('#tracked section')).indexOf(entry.target);
if (sectionIndex !== -1) {
const animatedSection = animatedSections[sectionIndex];
const ratio = entry.intersectionRatio;
// Animate-in
animatedSection.style.opacity = ratio;
animatedSection.style.transform = `scale(${0.5 + ratio * 0.5}) rotateY(${-180 + ratio * 180}deg)`;
// Animate-out
if (ratio < 0.5) {
animatedSection.style.translate = `${(0.5 - ratio) * 2 * 100}% 0`;
} else {
animatedSection.style.translate = '0 0';
}
}
});
}, { threshold: Array.from({length: 101}, (_, i) => i / 100) });
document.querySelectorAll('#tracked section').forEach(section => {
observer.observe(section);
});
I odpowiedni kod CSS:
#animated section {
opacity: 0;
transform: scale(0.5) rotateY(-180deg);
backface-visibility: hidden;
}
/* MANDATORY Copy-Paste Safety: Ensure content remains fully visible and legible for assistive technologies or users with motion sensitivities */
@media (prefers-reduced-motion: reduce) {
#animated section {
opacity: 1 !important;
transform: none !important;
translate: 0 0 !important;
}
}
Ta kreacja zastępcza zapewnia dokładniejszą animację sterowaną przewijaniem w przeglądarkach, które nie obsługują natywnej funkcji CSS, co zapewnia bardziej spójne wrażenia wszystkim użytkownikom. Używając serii progów dla elementu IntersectionObserver, możemy dokładniej śledzić pozycję przewijania i tworzyć płynniejsze animacje.