Schauen wir uns CSS-@keyframes-Animationen an, insbesondere wie man sie pausiert und anderweitig steuert. Es gibt eine CSS-Eigenschaft speziell dafür, die mit JavaScript gesteuert werden kann, aber es gibt viele Nuancen zu beachten. Wir werden auch meinen bevorzugten Weg zur Einrichtung betrachten, der viel Kontrolle bietet. Tipp: Es beinhaltet CSS-Custom-Properties.
Die Bedeutung des Pausierens von Animationen
Kürzlich, während ich an der CSS-gesteuerten Diashow arbeitete, die Sie später in diesem Artikel sehen werden, habe ich die Animationen im Ebenen-Panel der DevTools inspiziert. Mir fiel etwas Interessantes auf, worüber ich noch nie nachgedacht hatte: Animationen, die sich nicht im sichtbaren Bereich befanden, liefen immer noch!
Vielleicht ist das nicht so unerwartet. Wir wissen, dass Videos das tun. Videos laufen einfach weiter, bis man sie pausiert. Aber es ließ mich fragen, ob diese spielenden Animationen immer noch CPU/GPU verbrauchen? Verbrauchen sie unnötige Verarbeitungsleistung, was andere Teile der Seite verlangsamt?
Die Inspektion von Frames im Leistung-Panel der DevTools brachte kein weiteres Licht darauf, da ich keine "außerhalb des Bildschirms"-Frames sehen konnte. Aber als ich von meiner "CSS-Only-Diashow" zur ersten Folie wegscrollte, dann wartete und zurückscrollte, war sie bei Folie fünf. Die Animation hatte sich nicht pausiert. Animationen laufen einfach weiter und weiter, bis man sie pausiert.
Also begann ich zu recherchieren, wie, warum und wann Animationen pausieren sollten. Leistung ist aus den obigen Erkenntnissen ein offensichtlicher Grund. Ein weiterer Grund ist Kontrolle. Nutzer lieben es nicht nur, Kontrolle zu haben, sie sollten auch Kontrolle haben. Vor ein paar Jahren hatte meine Frau eine wirklich schlimme Gehirnerschütterung. Seitdem meidet sie Webseiten mit zu vielen Animationen, da sie ihr Schwindel verursachen. Daher halte ich Barrierefreiheit vielleicht für den wichtigsten Grund, Animationen pausieren zu können.
Zusammenfassend ist das wichtig. Wir sprechen speziell über CSS-Keyframe-Animationen, aber im Allgemeinen bedeutet das, dass wir darüber sprechen
- Leistung
- Kontrolle
- Barrierefreiheit
Die Grundlagen des Pausierens einer Animation
Die einzige Möglichkeit, eine Animation in CSS wirklich zu pausieren, ist die Verwendung der Eigenschaft animation-play-state mit dem Wert paused.
.paused {
animation-play-state: paused;
}
In JavaScript ist die Eigenschaft „camelCased“ als animationPlayState und wird so gesetzt
element.style.animationPlayState = 'paused';
Wir können einen Schalter erstellen, der die Animation abspielt und pausiert, indem wir den aktuellen Wert von animationPlayState lesen
const running = element.style.animationPlayState === 'running';
…und dann den entgegengesetzten Wert setzen
element.style.animationPlayState = running ? 'paused' : 'running';
Die Dauer einstellen
Eine andere Möglichkeit, Animationen zu pausieren, ist, animation-duration auf 0s zu setzen. Die Animation läuft tatsächlich, aber da sie keine Dauer hat, sehen Sie keine Aktion.
Aber wenn wir den Wert stattdessen auf 3s ändern
Es funktioniert, hat aber einen großen Nachteil: Die Animationen laufen technisch gesehen immer noch. Die Animation wechselt lediglich zwischen ihrer Ausgangsposition und dem nächsten Punkt in der Sequenz.
Die Animation komplett entfernen
Wir können die Animation vollständig entfernen und sie über Klassen wieder hinzufügen, aber wie bei animation-duration pausiert dies die Animation nicht wirklich.
.remove-animation {
animation: none !important;
}
Da wir wirklich ein echtes Pausieren wollen, bleiben wir bei animation-play-state und schauen uns andere Möglichkeiten der Verwendung an.
Verwendung von Datenattributen und CSS-Custom-Properties
Verwenden wir ein Datenattribut als Selektor in unserem CSS. Wir können diese nennen, wie wir wollen, daher verwende ich ein [data-animation]-Attribut auf allen Elementen, bei denen ich Animationen abspielen/pausieren möchte. Auf diese Weise kann es von anderen Animationen unterschieden werden.
<div data-animation></div>
Dieses Attribut ist der Selektor, und die animation-Kurzschreibweise ist die Eigenschaft, bei der wir alles setzen. Wir fügen eine Reihe von CSS-Custom-Properties hinzu *(*mit Emmet-Abkürzungen) als Werte.
[data-animation] {
animation:
var(--animn, none)
var(--animdur, 1s)
var(--animtf, linear)
var(--animdel, 0s)
var(--animic, infinite)
var(--animdir, alternate)
var(--animfm, none)
var(--animps, running);
}
Damit ist jede Animation mit diesem Datenattribut perfekt bereit, Animationen zu akzeptieren, und wir können einzelne Aspekte der Animation mit benutzerdefinierten Eigenschaften steuern. Einige Animationen werden etwas gemeinsam haben (wie Dauer,easing-Typ usw.), daher werden Fallback-Werte auch für die benutzerdefinierten Eigenschaften gesetzt.
Warum CSS-Custom-Properties? Erstens können sie sowohl in CSS als auch in JavaScript gelesen und gesetzt werden. Zweitens helfen sie erheblich, die Menge an CSS zu reduzieren, die wir schreiben müssen. Und da wir sie innerhalb von @keyframes setzen können (zum Zeitpunkt des Schreibens zumindest in Chrome), bieten sie neue und aufregende Möglichkeiten, mit Animationen zu arbeiten!
Für die Animationen selbst verwende ich Klassenselektoren und aktualisiere die Variablen aus dem [data-animation]-Selektor.
<div class="circle a-slide" data-animation></div>
Warum eine Klasse und ein Datenattribut? Zu diesem Zeitpunkt könnte das data-animation-Attribut genauso gut eine reguläre Klasse sein, aber wir werden es später auf fortgeschrittenere Weise verwenden. Beachten Sie, dass der Klassenname .circle eigentlich nichts mit der Animation zu tun hat – es ist nur eine Klasse zum Stylen des Elements.
/* Animation classes */
.a-pulse {
--animn: pulse;
}
.a-slide {
--animdur: 3s;
--animn: slide;
}
/* Keyframes */
@keyframes pulse {
0% { transform: scale(1); }
25% { transform: scale(.9); }
50% { transform: scale(1); }
75% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes slide {
from { margin-left: 0%; }
to { margin-left: 150px; }
}
Wir müssen nur die Werte aktualisieren, die sich ändern werden. Wenn wir also einige gängige Werte in den Fallback-Werten für den data-animation-Selektor verwenden, müssen wir nur den Namen der benutzerdefinierten Animationseigenschaft, --animn, aktualisieren.
Beispiel: Pausieren mit dem Checkbox-Hack
Um alle Animationen mit dem alten Checkbox-Hack zu pausieren, erstellen wir eine Checkbox vor den Animationen.
<input type="checkbox" data-animation-pause />
Und aktualisieren Sie die --animps-Eigenschaft, wenn sie checked ist.
[data-animation-pause]:checked ~ [data-animation] {
--animps: paused;
}
Das ist alles! Die Animationen wechseln beim Anklicken der Checkbox zwischen abgespielt und pausiert – kein JavaScript erforderlich.
CSS-Only-Diashow
Lassen Sie uns einige dieser Ideen in die Tat umsetzen!
Ich habe in letzter Zeit viel mit dem <details>-Tag herumgespielt. Es ist der offensichtliche Kandidat für Akkordeons, kann aber auch für Tooltips, Toggle-Tips, Dropdowns (gestylte <select>-Look-a-likes), Mega-Menüs ... Sie nennen es. Es ist schließlich das offizielle HTML-Disclosure-Element. Abgesehen von den globalen Attributen und globalen Ereignissen, die alle HTML-Elemente akzeptieren, hat <details> ein einzelnes open-Attribut und ein einzelnes toggle-Ereignis. Daher ist es, ähnlich wie der Checkbox-Hack, perfekt zum Umschalten des Zustands – aber sogar einfacher.
details[open] {
--state: 1;
}
details:not([open]) {
--state: 0;
}
Ich habe mich für eine Diashow entschieden, bei der sich die Folien automatisch über eine primäre Animation namens autoplay ändern, und jede einzelne Folie hat ihre eigene einzigartige sekundäre Animation. Der animation-play-state wird über die --animps-Eigenschaft gesteuert. Jede einzelne Folie kann ihre eigene, einzigartige Animation haben, die in einer --animn-Eigenschaft definiert ist.
<figure style="--animn:kenburns-top;--index:0;">
<img src="some-slide-image.jpg" />
<figcaption>Caption</figcaption>
</figure>
Der animation-play-state der sekundären Animationen wird über die --img-animps-Eigenschaft gesteuert. Ich habe eine Reihe von schönen Ken-Burns-ähnlichen Animationen bei Animista gefunden und sie in den --animn-Eigenschaften der Folien gewechselt.
Eine Animation aus einer anderen Animation heraus pausieren
Um eine Überlastung der GPU zu vermeiden, wäre es ideal, wenn die primäre Animation sekundäre Animationen pausiert. Wir haben es oben kurz erwähnt, aber nur Chrome (zum Zeitpunkt des Schreibens, und es ist ein wenig wackelig) kann eine CSS-Custom-Property aus einer @keyframe-Animation aktualisieren – was Sie im folgenden Beispiel sehen können, wo die Eigenschaften --bgc und --counter in verschiedenen Frames modifiziert werden.
Der Anfangszustand der sekundären Animation, die --img-animps-Eigenschaft, muss paused sein, auch wenn die primäre Animation läuft.
details[open] ~ .c-mm__inner .c-mm__frame {
--animps: running;
--img-animps: paused;
}
Dann wird in den Haupt-@keyframes-Animationen die Eigenschaft auf running aktualisiert.
@keyframes autoplay {
0.1% {
--img-animps: running; /* START */
opacity: 0;
z-index: calc(var(--z) + var(--slides))
}
5% { opacity: 1 }
50% { opacity: 1 }
51% { --img-animps: paused } /* STOP! */
100% {
opacity: 0;
z-index: var(--z)
}
}
Um dies in anderen Browsern als Chrome zu ermöglichen, muss der Anfangswert running sein, da diese keine CSS-Custom-Property aus einem @keyframe aktualisieren können.
Hier ist die Diashow mit einem "Details-Hack"-Play/Pause-Button – kein JavaScript erforderlich.
prefers-reduced-motion aktivieren
Manche Leute bevorzugen keine Animationen oder zumindest reduzierte Bewegungen. Es mag nur eine persönliche Vorliebe sein, kann aber auch an einer medizinischen Bedingung liegen. Wir haben ganz am Anfang dieses Beitrags über die Bedeutung von Barrierefreiheit bei Animationen gesprochen.
Sowohl macOS als auch Windows bieten Optionen, mit denen Benutzer Browser informieren können, dass sie reduzierte Bewegungen auf Webseiten bevorzugen. Dies ermöglicht uns, die prefers-reduced-motion-Abfrage zu verwenden, über die Eric Bailey umfassend geschrieben hat.
@media (prefers-reduced-motion) { ... }
Verwenden wir den [data-animation]-Selektor für reduzierte Bewegungen, indem wir ihm verschiedene Werte geben, die angewendet werden, wenn prefers-reduced-motion aktiviert ist*:
alternate= eine andere Animation ausführenonce= setzen Sieanimation-iteration-countauf 1slow= ändern Sie dieanimation-duration-Eigenschaftstop= setzen Sieanimation-play-stateaufpaused
Dies sind nur Vorschläge und sie können wirklich alles sein, was Sie wollen.
<div class="circle a-slide" data-animation="alternate"></div>
<div class="circle a-slide" data-animation="once"></div>
<div class="circle a-slide" data-animation="slow"></div>
<div class="circle a-slide" data-animation="stop"></div>
Und die aktualisierte Media-Query
@media (prefers-reduced-motion) {
[data-animation="alternate"] {
/* Change animation duration AND name */
--animdur: 4s;
--animn: opacity;
}
[data-animation="slow"] {
/* Change animation duration */
--animdur: 10s;
}
[data-animation="stop"] {
/* Stop the animation */
--animps: paused;
}
}
Wenn dies zu generisch ist und Sie lieber eindeutige, alternative Animationen pro Animationsklasse haben möchten, gruppieren Sie die Selektoren wie folgt:
.a-slide[data-animation="alternate"] { /* etc. */ }
Hier ist ein Pen mit einer Checkbox, die prefers-reduced-motion simuliert. Scrollen Sie im Pen nach unten, um das geänderte Verhalten für jeden Kreis zu sehen.
Mit JavaScript pausieren
Um die "Alle Animationen pausieren"-Checkbox in JavaScript nachzubilden, iterieren Sie alle [data-animation]-Elemente und schalten Sie dieselbe --animps-Benutzerdefinierte Eigenschaft um.
<button id="js-toggle" type="button">Toggle Animations</button>
const animations = document.querySelectorAll('[data-animation');
const jstoggle = document.getElementById('js-toggle');
jstoggle.addEventListener('click', () => {
animations.forEach(animation => {
const running = getComputedStyle(animation).getPropertyValue("--animps") || 'running';
animation.style.setProperty('--animps', running === 'running' ? 'paused' : 'running');
})
});
Es ist genau dasselbe Konzept wie beim Checkbox-Hack, das dieselbe benutzerdefinierte Eigenschaft verwendet: --animps, nur von JavaScript statt von CSS gesetzt. Wenn wir ältere Browser unterstützen wollen, können wir eine Klasse umschalten, die animation-play-state aktualisiert.
Verwendung von IntersectionObserver
Um alle [data-animation]-Animationen automatisch abzuspielen und zu pausieren – und somit die GPU nicht unnötig zu überlasten – können wir einen IntersectionObserver verwenden.
Zuerst müssen wir sicherstellen, dass überhaupt keine Animationen laufen.
[data-animation] {
/* Change 'running' to 'paused' */
animation: var(--animps, paused);
}
Dann erstellen wir den Observer und lösen ihn aus, wenn ein Element zu 25 % oder 75 % im Sichtbereich ist. Wenn letzteres übereinstimmt, beginnt die Animation zu spielen; andernfalls pausiert sie.
Standardmäßig werden alle Elemente mit einem [data-animation]-Attribut beobachtet, aber wenn prefers-reduced-motion aktiviert ist (auf „reduce“ gesetzt), werden die Elemente mit [data-animation="stop"] ignoriert.
const IO = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const state = (entry.intersectionRatio >= 0.75) ? 'running' : 'paused';
entry.target.style.setProperty('--animps', state);
}
});
}, {
threshold: [0.25, 0.75]
});
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
const elements = mediaQuery?.matches ? document.querySelectorAll(`[data-animation]:not([data-animation="stop"]`) : document.querySelectorAll('[data-animation]');
elements.forEach(animation => {
IO.observe(animation);
});
Sie müssen mit den threshold-Werten herumspielen und/oder ob Sie einige Animationen unobserve müssen, nachdem sie ausgelöst wurden usw. Wenn Sie neue Inhalte oder Animationen dynamisch laden, müssen Sie möglicherweise Teile des Observers neu schreiben. Es ist unmöglich, alle Szenarien abzudecken, aber die Verwendung als Grundlage sollte Ihnen den Einstieg in das automatische Abspielen und Pausieren von CSS-Animationen ermöglichen!
Bonus: Hinzufügen von <audio> zur Diashow mit minimalem JavaScript
Hier ist eine Idee, wie man Musik zur Diashow hinzufügt. Zuerst fügen wir ein audio-Tag hinzu.
<audio src="/asset/audio/slideshow.mp3" hidden loop></audio>
Dann, in Javascript
const audio = document.querySelector('your-audio-selector');
const details = document.querySelector('your-details-selector');
details.addEventListener('toggle', () => {
details.open ? audio.play() : audio.pause();
})
Ziemlich einfach, oder?
Ich habe hier eine "Stummfilm" (mit Ton)-Demo gemacht, wo Sie meine geekige Vergangenheit kennenlernen. :)
Dieser Artikel ist super!
Ist es möglich, den Abspielprozentsatz von CSS @keyframes zu steuern? Zum Beispiel mit einem input[type=”range”]
Danke!
Ja, das können Sie erreichen, indem Sie eine negative "animation-delay" setzen und dann einen Bereich mit "max" auf die Animationsdauer setzen.
Dann, wenn Sie "animation-delay" aktualisieren, setzen Sie es auf
0 - input.value, damit Sie den negativen Wert erhalten.Ich habe hier ein Beispiel gemacht.
Guten Morgen Herr Mads Stoumann!
Wunderbar, diese Arbeit über das Abspielen und Pausieren von CSS-Animationen.
Ich bin kein Experte für CSS, aber ich würde gerne wissen, ob Sie den Code haben, der es ermöglicht, die CSS-Animation des STAR WARS INTRO TEXTS wie diesen abzuspielen, zu pausieren und zurückzuspulen, bitte!
Star Wars 3D-Animation CSS. So dass das Abspielen, Stoppen und Zurückspulen zur besseren Lesbarkeit möglich ist!
Vielen Dank
https://www.google.com/search?q=star+wars+intro+css+animation+text+&tbm=isch&ved=2ahUKEwjCha-YxPnxAhVQsJUCHWrQA-oQ2-cCegQIABAA&oq=star+wars+intro+css+animation+text+ &gs_lcp=CgNpbWcQDFDBFFicamCsemgBcAB4AIABzwGIAa4KkgEGMTAuMi4xmAEAoAEBqgELZ3dzLXdpei1pbWfAAQE&sclient=img&ei=k-P6YILwJ9Dg1BR1W1z0B1QP6&sclient=img&ei=k-P6YILwJ9Dg1BR_1x8hr2&bQP6