Zmniejszający się nagłówek podczas przewijania to powszechny wzorzec interfejsu, w którym stały element nagłówka u góry strony płynnie zmniejsza się, gdy użytkownik przewija stronę w dół. Ten efekt jest często używany do maksymalizacji miejsca na ekranie dla głównych treści przy jednoczesnym zachowaniu dostępu do podstawowych elementów nawigacji lub marki. Dzięki animacjom CSS opartym na przewijaniu można osiągnąć ten efekt w sposób deklaratywny i wydajny, łącząc animację z pozycją przewijania dokumentu.
Jak to zrobić?
Aby utworzyć nagłówek, który zmniejsza się podczas przewijania:
Utwórz stały nagłówek: zacznij od elementu nagłówka, który jest przymocowany u góry strony i ma wstępnie zdefiniowaną wysokość.
<header>HEADER</header>header { position: fixed; height: 200px; top: 0; left: 0; right: 0; }Zdefiniuj animację zmniejszania: utwórz animację CSS, która zmienia wysokość nagłówka.
@keyframes shrink { to { height: 50px; } }Zastosowanie animacji i osi czasu przewijania: dołącz animację do nagłówka i użyj funkcji
scroll(), aby połączyć ją z pozycją przewijania dokumentu.header { animation: shrink auto linear both; animation-timeline: scroll(block root); }Ustaw właściwość
animation-range: użyj właściwościanimation-range, aby określić odległość przewijania, na której powinna wystąpić animacja. Na przykład, aby zmniejszyć nagłówek po przewinięciu pierwszych 150 pikseli, użyjanimation-range: 0px 150px;.header { animation-range: 0px 150px; }
Wskazówka: aby zapobiec zasłanianiu treści pod nagłówkiem, dodaj do elementu body (lub kontenera treści głównej) właściwość padding-top o wartości równej początkowej wysokości nagłówka.
Wskazówka: aby zawartość strony przewijała się synchronicznie ze zmniejszającym się nagłówkiem, ustaw animation-range-end na różnicę między rozmiarem początkowym i końcowym. Dzięki temu animacja zakończy się dokładnie wtedy, gdy nagłówek osiągnie ostateczny rozmiar. W tym przykładzie nagłówek zmniejsza się z 200px do 50px, więc właściwość animation-range-end jest ustawiona na 150px.
Przykładowy kod
@keyframes shrink {
to {
height: 50px;
}
}
header {
animation: shrink auto linear both;
animation-timeline: scroll(block root);
animation-range: 0px 150px;
}
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 funkcji scroll() do tworzenia animacji sterowanej przewijaniem:
- OPCJONALNIE Określ element przewijany: jeśli nie kierujesz na najbliższy element przewijany, określ, którego elementu przewijanego chcesz użyć, za pomocą
scroll(root)lubscroll(self).- Jeśli
root,nearestlubselfnie wystarczą, użyj nazwanej osi czasu przewijania.
- Jeśli
- 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ąscroll(block)lubscroll(inline).
W tym konkretnym przypadku użycia:
- Element, który animujesz, NIE MOŻE być elementem
position: staticaniposition: relative, gdy używasz wartości procentowych wanimation-range.- Dzieje się tak, ponieważ te elementy są uważane za „w przepływie”. Zmniejszanie tych elementów podczas przewijania zmniejszałoby całkowitą odległość przewijania, co wpływałoby na obliczoną wartość, na przykład
10%, podczas przewijania.
- Dzieje się tak, ponieważ te elementy są uważane za „w przepływie”. Zmniejszanie tych elementów podczas przewijania zmniejszałoby całkowitą odległość przewijania, co wpływałoby na obliczoną wartość, na przykład
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 detektora przewijania do śledzenia pozycji przewijania dokumentu na odległość 150px i odpowiednio aktualizuje wysokość nagłówka.
// Fallback for browsers that don't support scroll-driven animations
if (!CSS.supports('(animation-timeline: scroll()) and (animation-range: 0% 100%)')) {
const header = document.querySelector('header');
const initialHeight = 200;
const finalHeight = 50;
const scrollDistance = 150;
window.addEventListener('scroll', () => {
const scrollY = window.scrollY;
const scrollPercent = Math.min(1, scrollY / scrollDistance);
const newHeight = initialHeight - (initialHeight - finalHeight) * scrollPercent;
header.style.height = `${newHeight}px`;
});
}