Animacje przewijane to typowy wzorzec UX w internecie. Animacja wywoływana przez przewijanie jest powiązana z pozycją przewijania kontenera. Oznacza to, że podczas przewijania w górę lub w dół powiązana animacja przewija się do przodu lub do tyłu w odpowiedzi bezpośredniej. Przykładami takich efektów są obrazy tła z paralaksą lub wskaźniki czytania, które poruszają się podczas przewijania.
Deweloperzy zwykle tworzyli animacje sterowane przewijaniem, używając JavaScriptu do reagowania na zdarzenia przewijania na głównym wątku. Utrudnia to tworzenie wydajnych animacji opartych na przewijaniu, które są zsynchronizowane z przewijaniem. Wynika to z tego, że zdarzenia przewijania są przesyłane asynchronicznie, co często powoduje opóźnienia, ponieważ są one wykonywane w wątku głównym.
Jednak w ramach nowych funkcji CSS i UI, które pojawiają się w przeglądarkach, możesz teraz tworzyć deklaratywnie animacje sterowane przewijaniem. Dzięki przewijaniu osi czasu i wyświetlania osi czasu nowe koncepcje integrujące się z istniejącymi interfejsami Web Animation API (WAAPI) i CSS Animations API sprawią, że za pomocą kilku linijek kodu będziesz mieć płynne animacje oparte na przewijaniu. Z tego studium przypadku dowiesz się, jak Tokopedia, redBus i Policybazaar korzystają z tej nowej funkcji.
Tokopedia
Firma Tokopedia zastąpiła poprzednie implementacje niestandardowego kodu JavaScript animacjami sterowanymi przez przewijanie, aby zoptymalizować wydajność strony i poprawić ogólne wrażenia użytkowników podczas przeglądania ścieżki konwersji w e-commerce.
Udało nam się zmniejszyć liczbę linii kodu nawet o 80% w porównaniu z wykorzystywaniem konwencjonalnych zdarzeń przewijania w JavaScript. Zauważyliśmy też, że podczas przewijania średnie wykorzystanie procesora spadło z 50% do 2%. Andy Wihalim, starszy inżynier oprogramowania, Tokopedia
Kod
W tej implementacji funkcja scroll()
służy do ustawienia anonimowej osi czasu postępu przewijania, która służy do sterowania postępem animacji CSS. Widoczność górnego paska przyklejonego zmienia się w zależności od pozycji przewijania w określonym animationRange
.
const toggleBar = keyframes({
to: { height: 48 },
});
export const cssWrapper = css({
position: 'fixed',
left: 0,
width: '100vw',
pointerEvents: 'none',
marginTop: 120,
height: 0,
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end',
animation: `${toggleBar} linear both`,
animationTimeline: 'scroll()',
animationRange: '20px 70px',
});
redBus
Na stronie docelowej Atrakcje firmy redBus, która jest wyświetlana na początku ścieżki konwersji wszystkim użytkownikom, znajdują się różne animacje na potrzeby urządzeń mobilnych i komputerów. W przypadku animacji sterowanych przewijaniem udało im się zastąpić niestandardowe implementacje JavaScriptu kodem CSS, aby uzyskać ten sam efekt.
Przypadki użycia
Galeria zdjęć z efektem wyświetlania obrazu (na urządzeniach mobilnych) i Cover Flow (na komputerach).
Kod (urządzenia mobilne)
W poprzednim przykładzie Tokopedia używała anonimowego wykresu postępu przewijania. W poniższym kodzie redBus korzysta z osi czasu nazwanego widoku postępu. Animacja zmienia właściwości opacity
i clip-path
elementu <img>
w zdefiniowanym elemencie animation-range
w obszarze przewijania najbliższego elementu nadrzędnego, którym jest w tym przypadku przewijanie galerii zdjęć.
const reveal = keyframes`
from {
opacity: 0;
clip-path: inset(45% 20% 45% 20%);
}
to {
opacity: 1;
clip-path: inset(0% 0% 0% 0%);
}`
const CardImage = styled.div`
width: 100%;
height: 100%;
img {
border-top-left-radius: 0.75rem;
border-top-right-radius: 0.75rem;
height: 100%;
width: 100%;
object-fit: cover;
view-timeline-name: --revealing-image;
view-timeline-axis: block;
/* Attach animation, linked to the View Timeline */
animation: linear ${reveal} both;
animation-timeline: --revealing-image;
/* Tweak range when effect should run*/
animation-range: entry 25% cover 50%;
}
`;
Cieszymy się, że ta funkcja łączy w doskonały sposób wydajność z lepszymi wrażeniami użytkowników, co zwiększa skuteczność sygnałów dotyczących jakości stron w ramach SEO. Co więcej, minimalna krzywizna uczenia się sprawia, że jest to niezbędna funkcja dla każdej witryny e-commerce. Otrzymaliśmy też pozytywne opinie i wsparcie od innych zespołów, które pomagają nam wykorzystać technologię SDA do zwiększania liczby interakcji użytkowników – Amit Kumar, starszy kierownik ds. inżynierii, redBus.
Policybazaar
Porównywanie planów ubezpieczenia to kluczowe działanie, które użytkownicy powtarzają, aby ułatwić sobie podejmowanie decyzji. Za pomocą animacji wywoływanych przez przewijanie zespół Policybazaar zmniejszał rozmiar elementów o mniejszym priorytecie w odpowiedzi na przewijanie tabeli przez użytkownika. Dzięki temu użytkownicy mogą płynnie przewijać strony, a jednocześnie poprawia się czytelność.
Dzięki animacjom sterowanym przez przewijanie mogliśmy zmaksymalizować przestrzeń widoku dla użytkownika, aby mógł porównywać plany. Dzięki temu czytanie jest bardziej skoncentrowane i nie jest utrudnione przez nagromadzone treści. – Rishabh Mehrotra, dyrektor ds. projektowania w dziale ubezpieczeń na życie w firmie PolicyBazaar
Kod
Podobnie jak w poprzednim przykładzie z Tokopedia, Policybazaar używa funkcji scroll()
do ustawiania anonimowej osi czasu postępu przewijania w celu sterowania postępem animacji CSS. W tym przypadku zmniejszenie rozmiaru czcionki i wyblaknięcie nagłówka na podstawie pozycji przewijania w określonym obszarze animation-range
.
@supports (animation-timeline: scroll()) {
.plan-comparison .inner-header {
animation: move-and-fade-header linear both;
}
.plan-comparison .left-side {
animation: shrink-name linear both;
}
.plan-comparison .inner-header, .plan-comparison .left-side {
animation-timeline: scroll();
animation-range: 0 150px;
}
}
@keyframes move-and-fade-header {
to {
translate: 0% -5%;
top:103px;
}
}
@keyframes shrink-name {
to {
font-size: 1.5rem;
}
}
Animacje wywoływane przez przewijanie jako typowy element ścieżki użytkownika
Wszystkie polecane firmy z zakresu e-commerce używały animacji sterowanych przewijaniem na stronach z kartami, aby przyciągnąć uwagę użytkowników do tych kart . Poniższe przykłady pokazują efekty przewijania kart w różnych częściach ścieżki użytkownika. Zwykle odbywa się to za pomocą anonimowego widoku osi czasu postępu, który służy do kontrolowania postępu niestandardowej animacji CSS, jak pokazano w tym fragmencie kodu CSS.
@keyframes animate-in {
0% { opacity: 0; transform: translateY(10%); }
100% { opacity: 1; transform: translateY(0); }
}
@keyframes animate-out {
0% { opacity: 1; transform: translateY(0); }
100% { opacity: 0; transform: translateY(-10%); }
}
.flyin_animate {
animation: animate-in linear forwards;
animation-timeline: view();
animation-range: entry;
}
redBus (strona główna)
Policybazaar (strona z informacjami o produkcie)
Tokopedia (strona ze szczegółami produktu)
Co należy wziąć pod uwagę podczas korzystania z interfejsu Animations API opartej na przewijaniu
Na potrzeby nieobsługiwanych przeglądarek można zastosować polyfill na potrzeby animacji opartych na przewijaniu, np. polyfill na osi czasu przewijania. W takim przypadku musisz przeprowadzić dodatkowe testy, aby upewnić się, że działa dobrze równolegle z ramką, a przeglądarki korzystające z kodu Polyfill nie wykazują błędów animacji ani zakłóceń.
W CSS możesz użyć funkcji @supports
, aby sprawdzić, czy animacja-oś czasu jest obsługiwana, zanim użyjesz animacji sterowanych przewijaniem. Na przykład:
@supports (animation-timeline: scroll()) {
}
Zasoby
- Prezentacje animacji uruchamianych przez przewijanie
- Animowanie elementów podczas przewijania za pomocą animacji sterowanych przez przewijanie
- Codelab: pierwsze kroki z animacjami sterowanymi przez przewijanie w CSS
- Rozszerzenie do Chrome: debuger animacji sterowanej przez przewijanie
- Scroll-timeline Polyfill
- Czy chcesz zgłosić błąd lub nową funkcję? Chętnie poznamy Twoją opinię.
Przeczytaj inne artykuły z tej serii, aby dowiedzieć się, jak firmy e-commerce korzystają z nowych funkcji CSS i interfejsu użytkownika, takich jak przejścia między widokami, okienka pop-up, zapytania kontenerowe i selektor has()
.