Die Spezifikation für Scroll-Linked Animations ist eine kommende und experimentelle Erweiterung, die es uns ermöglicht, die Animationsdauer an den Scroll-Fortschritt zu koppeln: Während Sie durch einen Scroll-Container nach oben und unten scrollen, schreitet eine verknüpfte Animation entsprechend voran oder spult zurück.
Wir haben einige Anwendungsfälle in einem früheren Beitrag hier auf CSS-Tricks behandelt, die alle durch die CSS-Regel @scroll-timeline und die Eigenschaft animation-timeline gesteuert wurden, die die Spezifikation bereitstellt — ja, das ist richtig: all diese Anwendungsfälle wurden nur mit HTML und CSS erstellt. Kein JavaScript.
Abgesehen von der CSS-Schnittstelle, die wir mit der Scroll-linked Animations-Spezifikation erhalten, beschreibt sie auch eine JavaScript-Schnittstelle zur Implementierung von scroll-verknüpften Animationen. Werfen wir einen Blick auf die Klasse ScrollTimeline und wie sie mit der Web Animations API verwendet wird.
Web Animations API: Eine kurze Wiederholung
Die Web Animations API (WAAPI) wurde hier auf CSS-Tricks schon einmal behandelt. Eine kurze Wiederholung: Die API ermöglicht es uns, Animationen zu erstellen und ihre Wiedergabe mit JavaScript zu steuern.
Nehmen Sie zum Beispiel die folgende CSS-Animation, bei der sich ein Balken am oberen Rand der Seite befindet und
- von
redzudarkredanimiert, dann - von Nullbreite zu voller Breite animiert (durch Skalierung der x-Achse).
Wenn wir die CSS-Animation in ihr WAAPI-Gegenstück übersetzen, wird der Code wie folgt aussehen
new Animation(
new KeyframeEffect(
document.querySelector('.progressbar'),
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
)
).play();
Oder alternativ mit einer kürzeren Syntax mit Element.animate()
document.querySelector('.progressbar').animate(
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
},
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
);
In diesen beiden letzten JavaScript-Beispielen können wir zwei Dinge unterscheiden. Erstens ein keyframes-Objekt, das beschreibt, welche Eigenschaften animiert werden sollen
{
backgroundColor: ['red', 'darkred'],
transform: ['scaleX(0)', 'scaleX(1)'],
}
Zweitens ein options-Objekt, das die Animationsdauer, das Timing usw. konfiguriert.
{
duration: 2500,
fill: 'forwards',
easing: 'linear',
}
Erstellen und Anhängen eines Scroll-Timelines
Damit unsere Animation durch Scrollen angetrieben wird — anstatt durch das monotone Ticken einer Uhr — können wir unseren bestehenden WAAPI-Code beibehalten, müssen ihn aber erweitern, indem wir eine ScrollTimeline-Instanz daran anhängen.
Diese Klasse ScrollTimeline ermöglicht es uns, eine AnimationTimeline zu beschreiben, deren Zeitwerte nicht durch die Wanduhrzeit, sondern durch den Scroll-Fortschritt in einem Scroll-Container bestimmt werden. Sie kann mit einigen Optionen konfiguriert werden
source: Das scrollbare Element, dessen Scrollen die Aktivierung auslöst und den Fortschritt der Timeline steuert. Standardmäßig ist diesdocument.scrollingElement(d. h. der Scroll-Container, der das gesamte Dokument scrollt).orientation: Bestimmt die Scroll-Richtung, die die Aktivierung auslöst und den Fortschritt der Timeline steuert. Standardmäßig ist diesvertical(oderblockals logischer Wert).scrollOffsets: Diese bestimmen die effektiven Scroll-Offsets, die sich in der durch den Wert vonorientationangegebenen Richtung bewegen. Sie bilden gleichmäßig beabstandete Intervalle im Fortschritt, in denen die Timeline aktiv ist.
Diese Optionen werden in den Konstruktor übergeben. Zum Beispiel
const myScrollTimeline = new ScrollTimeline({
source: document.scrollingElement,
orientation: 'block',
scrollOffsets: [
new CSSUnitValue(0, 'percent'),
new CSSUnitValue(100, 'percent'),
],
});
Es ist kein Zufall, dass diese Optionen genau dieselben sind wie die CSS-@scroll-timeline-Deskriptoren. Beide Ansätze ermöglichen es Ihnen, dasselbe Ergebnis zu erzielen, wobei der einzige Unterschied die Sprache ist, mit der Sie sie definieren.
Um unsere neu erstellte ScrollTimeline-Instanz an eine Animation anzuhängen, übergeben wir sie als zweites Argument in den Animation-Konstruktor
new Animation(
new KeyframeEffect(
document.querySelector('#progress'),
{ transform: ['scaleX(0)', 'scaleX(1)'], },
{ duration: 1, fill: 'forwards' }
),
myScrollTimeline
).play();
Wenn Sie die Element.animate()-Syntax verwenden, setzen Sie sie als timeline-Option im options-Objekt
document.querySelector("#progress").animate(
{
transform: ["scaleX(0)", "scaleX(1)"]
},
{
duration: 1,
fill: "forwards",
timeline: myScrollTimeline
}
);
Mit diesem Code an Ort und Stelle wird die Animation von unserer ScrollTimeline-Instanz angetrieben und nicht von der Standard-DocumentTimeline.
Die aktuelle experimentelle Implementierung in Chromium verwendet scrollSource anstelle von source. Das ist der Grund, warum Sie sowohl source als auch scrollSource in den Codebeispielen sehen.
Ein Wort zur Browserkompatibilität
Zum Zeitpunkt der Erstellung unterstützten nur Chromium-Browser die Klasse ScrollTimeline hinter einem Feature-Flag. Glücklicherweise gibt es das Scroll-Timeline Polyfill von Robert Flack, das wir verwenden können, um die nicht unterstützten Lücken in allen anderen Browsern zu schließen. Tatsächlich sind alle Demos, die in diesem Artikel eingebettet sind, enthalten.
Das Polyfill ist als Modul verfügbar und registriert sich selbst, wenn keine Unterstützung erkannt wird. Um es einzubinden, fügen Sie die folgende import-Anweisung zu Ihrem JavaScript-Code hinzu
import 'https://flackr.github.io/scroll-timeline/dist/scroll-timeline.js';
Das Polyfill registriert auch die erforderlichen CSS Typed Object Model-Klassen, falls der Browser diese nicht unterstützt. (👀 Schauen wir dich an, Safari.)
Fortgeschrittene Scroll-Timelines
Neben absoluten Offsets können scroll-verknüpfte Animationen auch mit elementbasierten Offsets arbeiten
Mit dieser Art von Scroll-Offsets basiert die Animation auf der Position eines Elements innerhalb des Scroll-Containers.
Typischerweise wird dies verwendet, um ein Element zu animieren, während es in den Viewport scrollt, bis es den Viewport verlässt; z. B. während es sich überschneidet.
Ein elementbasierter Offset besteht aus drei Teilen, die ihn beschreiben
target: Das verfolgte DOM-Element.edge: Dies ist das, was dieScrollTimeline-sourceüberwacht, damit dastargetes überschreiten kann.threshold: Eine Zahl von0.0bis1.0, die angibt, wie viel vomtargetamedgeim Scroll-Port sichtbar ist. (Vielleicht kennen Sie das vonIntersectionObserver.)
Hier ist eine Visualisierung
Wenn Sie mehr über elementbasierte Offsets erfahren möchten, einschließlich ihrer Funktionsweise und Beispiele für häufig verwendete Offsets, lesen Sie diesen Artikel.
Elementbasierte Offsets werden auch von der JS ScrollTimeline-Schnittstelle unterstützt. Um einen zu definieren, verwenden Sie ein reguläres Objekt
{
target: document.querySelector('#targetEl'),
edge: 'end',
threshold: 0.5,
}
Typischerweise übergeben Sie zwei dieser Objekte an die scrollOffsets-Eigenschaft.
const $image = document.querySelector('#myImage');
$image.animate(
{
opacity: [0, 1],
clipPath: ['inset(45% 20% 45% 20%)', 'inset(0% 0% 0% 0%)'],
},
{
duration: 1,
fill: "both",
timeline: new ScrollTimeline({
scrollSource: document.scrollingElement,
timeRange: 1,
fill: "both",
scrollOffsets: [
{ target: $image, edge: 'end', threshold: 0.5 },
{ target: $image, edge: 'end', threshold: 1 },
],
}),
}
);
Dieser Code wird in der folgenden Demo verwendet. Es ist ein JavaScript-Remake von dem Effekt, den ich letztes Mal behandelt habe: Wenn ein Bild in den Viewport scrollt, wird es eingeblendet und freigeschaltet.
Weitere Beispiele
Hier sind noch ein paar weitere Beispiele, die ich mir ausgedacht habe.
Horizontaler Scroll-Bereich
Dies basiert auf einer Demo von Cameron Knight, die einen horizontalen Scroll-Bereich aufweist. Es verhält sich ähnlich, verwendet aber ScrollTimeline anstelle von GSAPs ScrollTrigger.
Mehr darüber, wie dieser Code funktioniert und eine reine CSS-Version zu sehen, finden Sie in diesem Beitrag.
CoverFlow
Erinnern Sie sich an CoverFlow von iTunes? Nun, hier ist eine Version, die mit ScrollTimeline erstellt wurde
Diese Demo verhält sich nicht zu 100% wie erwartet in Chromium wegen eines Fehlers. Das Problem ist, dass die Start- und Endpositionen falsch berechnet werden. Eine Erklärung (mit Videos) finden Sie in diesem Twitter-Thread.
Weitere Informationen zu dieser Demo finden Sie in diesem Artikel.
CSS oder JavaScript?
Es gibt keinen wirklichen Unterschied bei der Verwendung von CSS oder JavaScript für die Scroll-Linked Animations, außer der verwendeten Sprache: beide verwenden dieselben Konzepte und Konstrukte. Im Geiste des progressiven Enhancements würde ich für diese Art von Effekten zu CSS greifen.
Allerdings, wie wir bereits besprochen haben, ist die Unterstützung für die CSS-basierte Implementierung zum Zeitpunkt der Erstellung ziemlich schlecht
- Chromium unterstützt es hinter einem Feature-Flag.
- Firefox bereitet einige Arbeiten dafür vor. (Mozilla Ticket #1676780)
- Noch keine Neuigkeiten von Safari. (WebKit Ticket #222295)
Aufgrund dieser schlechten Unterstützung werden Sie im Moment sicher weiter mit JavaScript kommen. Stellen Sie nur sicher, dass Ihre Website auch dann angezeigt und konsumiert werden kann, wenn JavaScript deaktiviert ist. 😉
Hey, wenn ich versuche, "new ScrollTimeline" zu verwenden, erhalte ich den Fehler, dass ScrollTimeline nicht definiert ist. Was ist der Grund und die Lösung dafür?