Animacje przy przewijaniu bez wtyczek: scroll-driven animations i View Transitions

Efekty, które kiedyś wymagały biblioteki JavaScript i nasłuchiwania przewijania, dziś da się opisać kilkoma linijkami CSS. Strona jest przez to ładniejsza i szybsza jednocześnie.
Picture of Bartosz Womuczył

Bartosz Womuczył

Projektant stron internetowych, Lublin

W tym artykule

Problem z animacjami z wtyczek

Na wielu stronach WordPress efekt „pojawiania się przy przewijaniu” kosztuje więcej, niż daje. Wtyczka dokłada bibliotekę JavaScript, która przy każdym ruchu kółkiem myszy sprawdza położenie elementów. Na słabszym telefonie oznacza to przycięcia, a w Core Web Vitals gorszy wynik INP.

Przeglądarki nauczyły się robić to same, wydajniej, bo animacje oparte na CSS mogą działać poza głównym wątkiem, na którym wykonuje się JavaScript.

Scroll-driven animations: animacja sterowana przewijaniem

Właściwość animation-timeline pozwala powiązać zwykłą animację CSS z przewijaniem zamiast z czasem. Są dwa rodzaje osi czasu:

  • scroll(): postęp przewijania całej strony lub kontenera, od 0 do 100%,
  • view(): położenie konkretnego elementu względem widocznego obszaru, czyli od wejścia na ekran do wyjścia.

Chrome i Edge obsługują tę funkcję od wersji 115 (lipiec 2023), a Safari od wersji 26 (wrzesień 2025). W stabilnym Firefoksie w połowie 2026 roku funkcja wciąż wymaga włączenia flagi, dlatego traktuję ją jako ulepszenie, a nie warunek działania strony.

Dwa przykłady, które możesz wdrożyć od razu

Pasek postępu czytania

Ten sam pasek widzisz u góry tego artykułu. Cały efekt to kilka linijek:

.progress {
  position: fixed; inset: 0 0 auto; height: 2px;
  background: #C2A67E;
  transform-origin: 0 50%;
  transform: scaleX(0);
}
@supports (animation-timeline: scroll()) {
  .progress {
    animation: grow linear both;
    animation-timeline: scroll(root block);
  }
  @keyframes grow { to { transform: scaleX(1); } }
}

Przeglądarka, która nie zna animation-timeline, po prostu nie pokaże paska. Nic się nie psuje.

Delikatne pojawianie się sekcji

@supports (animation-timeline: view()) {
  .reveal {
    animation: fade-up linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 60%;
  }
  @keyframes fade-up {
    from { opacity: 0; transform: translateY(32px); }
  }
}

Animuj wyłącznie transform i opacity. Zmiana top, height czy margin zmusza przeglądarkę do ponownego przeliczania układu całej strony.

View Transitions: płynne przejścia między podstronami

Drugie narzędzie to View Transitions. Przez lata płynne przejścia między podstronami były domeną aplikacji w React czy Vue. Teraz klasyczna, wielostronicowa witryna może je mieć jedną regułą CSS:

@view-transition { navigation: auto; }

::view-transition-old(root) { animation: out .35s ease both; }
::view-transition-new(root) { animation: in .55s ease both; }

Przejścia między dokumentami obsługują przeglądarki oparte na Chromium od wersji 126 i Safari od wersji 18.2. Pozostałe przeglądarki przełączają podstrony zwyczajnie, bez animacji. Ta strona korzysta z tego mechanizmu, więc przejdź do innej zakładki w menu i zobacz efekt.

Dostępność: szanuj ustawienia użytkownika

Część osób ma w systemie włączone ograniczenie ruchu, na przykład z powodu zaburzeń błędnika. Każda animacja dekoracyjna powinna to respektować:

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
  @view-transition { navigation: none; }
}

Druga zasada: treść nie może zależeć od animacji. Jeśli element jest ukryty w stanie początkowym, a animacja się nie uruchomi, użytkownik nie może zostać z pustą sekcją. Dlatego stan ukryty włączam dopiero wtedy, gdy wiem, że przeglądarka obsłuży jego odkrycie.

Kiedy jednak sięgnąć po JavaScript

CSS nie zastąpi wszystkiego. Złożone, wieloetapowe sekwencje, animacje zależne od danych albo sceny 3D nadal wymagają skryptu. Wtedy warto pamiętać o dwóch zasadach:

  • zamiast nasłuchiwać zdarzenia scroll, używaj IntersectionObserver, który informuje o wejściu elementu na ekran bez ciągłego sprawdzania,
  • ładuj bibliotekę tylko na podstronie, która jej potrzebuje, a nie globalnie.

Proces na stronie głównej tego serwisu, w którym warstwy strony składają się w całość podczas przewijania, działa właśnie tak: IntersectionObserver przełącza etapy, a samą animację wykonuje CSS.

Chcesz, żeby Twoja strona zyskała ruch bez utraty szybkości? Porozmawiajmy.

Picture of Bartosz Womuczył

Bartosz Womuczył

Projektuję i buduję strony oraz sklepy internetowe na WordPressie. Więcej o mnie

Czytaj dalej

Wolisz, żeby ktoś zrobił to za Ciebie?

Sprawdzę Twoją stronę pod kątem szybkości, SEO i konwersji, a potem powiem wprost, co warto poprawić najpierw.

Przewijanie do góry