animation — delay
Свойство задаёт задержку воспроизведения CSS-анимации.
Пример
Скопировать ссылку «Пример» Скопировано
.element animation-name: circle-to-square; animation-duration: 2s; animation-iteration-count: infinite; animation-direction: alternate-reverse; animation-timing-function: ease-in; animation-delay: 1s;>
.element animation-name: circle-to-square; animation-duration: 2s; animation-iteration-count: infinite; animation-direction: alternate-reverse; animation-timing-function: ease-in; animation-delay: 1s; >
Как пишется
Скопировать ссылку «Как пишется» Скопировано
Значением может быть любое число, как отрицательное, так и положительное. Если значение положительное, то будет задержка перед началом анимации. Если значение отрицательное, то анимация начнётся как бы за кадром.
Подсказки
Скопировать ссылку «Подсказки» Скопировано
Подробнее об анимациях написано в статье «CSS-анимации».
animation-delay
The animation-delay CSS property specifies the amount of time to wait from applying the animation to an element before beginning to perform the animation. The animation can start later, immediately from its beginning, or immediately and partway through the animation.
Try it
It is often convenient to use the shorthand property animation to set all animation properties at once.
Syntax
/* Single animation */ animation-delay: 3s; animation-delay: 0s; animation-delay: -1500ms; /* Multiple animations */ animation-delay: 2.1s, 480ms; /* Global values */ animation-delay: inherit; animation-delay: initial; animation-delay: revert; animation-delay: revert-layer; animation-delay: unset;
Values
The time offset, from the moment at which the animation is applied to the element, at which the animation should begin. This may be specified in either seconds ( s ) or milliseconds ( ms ). The unit is required.
A positive value indicates that the animation should begin after the specified amount of time has elapsed. A value of 0s , which is the default, indicates that the animation should begin as soon as it’s applied.
A negative value causes the animation to begin immediately, but partway through its cycle. For example, if you specify -1s as the animation delay time, the animation will begin immediately but will start 1 second into the animation sequence. If you specify a negative value for the animation delay, but the starting value is implicit, the starting value is taken from the moment the animation is applied to the element.
Note: When you specify multiple comma-separated values on an animation-* property, they are applied to the animations in the order in which the animation-name s appear. For situations where the number of animations and animation-* property values do not match, see Setting multiple animation property values.
Note: animation-delay has no effect on CSS scroll-driven animations.
Formal definition
How to Play and Pause CSS Animations with CSS Custom Properties
Let’s have a look CSS @keyframes animations, and specifically about how you can pause and otherwise control them. There is a CSS property specifically for it, that can be controlled with JavaScript, but there is plenty of nuance to get into in the details. We’ll also look at my preferred way of setting this up which gives lots of control. Hint: it involves CSS custom properties.
The importance of pausing animations
The basics of pausing an animation
The only way to truly pause an animation in CSS is to use the animation-play-state property with a paused value.
In JavaScript, the property is “camelCased” as animationPlayState and set like this:
element.style.animationPlayState = 'paused';
We can create a toggle that plays and pauses the animation by reading the current value of animationPlayState :
const running = element.style.animationPlayState === 'running';
…and then setting it to the opposite value:
element.style.animationPlayState = running ? 'paused' : 'running';
Another way to pause animations is to set animation-duration to 0s . The animation is actually running, but since it has no duration, you won’t see any action.
But if we change the value to 3s instead:
It works, but has a major caveat: the animations are technically still running. The animation is merely toggling between its initial position, and where it is next in the sequence.
Straight up removing the animation
We can remove the animation entirely and add it back via classes, but like animation-duration , this doesn’t actually pause the animation.
Since true pausing is really what we’re after here, let’s stick with animation-play-state and look into other ways of using it.
Using data attributes and CSS custom properties
Let’s use a data-attribute as a selector in our CSS. We can call those whatever we want, so I’m going to use a [data-animation] -attribute on all the elements where I’d like to play/pause animations. That way, it can be distinguished from other animations:
That attribute is the selector, and the animation shorthand is the property where we’re setting everything. We’ll toss in a bunch of CSS custom properties *(*using Emmet-abbreviations) as values:
With that in place, any animation with this data-attribute will be perfectly ready to accept animations, and we can control individual aspects of the animation with custom properties. Some animations are going to have something in common (like duration, easing-type, etc.), so fallback values are set on the custom properties as well.
Why CSS custom properties? First of all, they can be read and set in both CSS and JavaScript. Secondly, they help significantly reduce the amount of CSS we need to write. And, since we can set them within @keyframes (at least in Chrome at the time of writing), they offer new and exiting ways to work with animations!
For the animations themselves, I’m using class selectors and updating the variables from the [data-animation] -selector:
Why a class and a data-attribute? At this stage, the data-animation attribute might as well be a regular class, but we’re going to use it in more advanced ways later. Note that the .circle class name actually has nothing to do with the animation — it’s just a class for styling the element.
/* 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; >>
We only need to update the values that will change, so if we use some common values in the fallback values for the data-animation selector, we only need to update the name of the animation’s custom property, —animn .
Example: Pausing with the checkbox hack
To pause all the animations using the ol’ checkbox hack, let’s create a checkbox before the animations:
And update the —animps property when checked :
[data-animation-pause]:checked ~ [data-animation]
That’s it! The animations toggle between played and paused when clicking the checkbox — no JavaScript required.
Let’s put some of these ideas to work!
I‘ve played with the -tag a lot recently. It’s the obvious candidate for accordions, but it can also be used for tooltips, toggle-tips, drop-downs (styled -look-a-likes), mega-menus… you name it. It is the official HTML disclosure element, after all. Apart from the global attributes and global events that all HTML elements accept, has a single open attribute, and a single toggle event. So, like the checkbox hack, it’s perfect for toggling state — but even simpler:
details[open] < --state: 1; >details:not([open])
I decided to do a slideshow, where the slides change automatically via a primary animation called autoplay , and each individual slide has its own unique secondary animation. The animation-play-state is controlled by the —animps -property. Each individual slide can have it’s own, unique animation, defined in a —animn -property:
The animation-play-state of the secondary animations are controlled by the —img-animps -property. I found a bunch of nice Ken Burns-esque animations at Animista and switched between them in the —animn -properties of the slides.
Pausing an animation from another animation
In order to prevent GPU overload, it would be ideal for the primary animation to pause any secondary animations. We noted it briefly earlier, but only Chrome (at the time of writing, and it is a bit shaky) can update a CSS Custom Property from an @keyframe animation — which you can see in the following example where the —bgc -property and —counter -properties are modified at different frames:
The initial state of the secondary animation, the —img-animps -property, needs to be paused , even if the primary animation is running:
details[open] ~ .c-mm__inner .c-mm__frame
Then, in the main animation @keyframes , the property is updated to running :
@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) >>
To make this work in browsers other than Chrome, the initial value needs to be running , as they cannot update a CSS custom property from a @keyframe .
Here’s the slideshow, with a “details hack” play/pause-button — no JavaScript required:
Some people prefer no animations, or at least reduced motion. It might just be a personal preference, but can also be because of a medical condition. We talked about the importance of accessibility with animations at the very top of this post.
Both macOS and Windows have options that allow users to inform browsers that they prefer reduced motion on websites. This enables us to reach for the prefers-reduced-motion feature query, which Eric Bailey has written all about.
@media (prefers-reduced-motion)
Let’s use the [data-animation] -selector for reduced motion by giving it different values that are applied when prefers-reduced-motion is enabled*:*
- alternate = run a different animation
- once = set the animation-iteration-count to 1
- slow = change the animation-duration -property
- stop = set animation-play-state to paused
These are just suggestions and they can be anything you want, really.
And the updated 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; >>
If this is too generic, and you prefer having unique, alternate animations per animation class, group the selectors like this:
.a-slide[data-animation="alternate"] < /* etc. */ >
Here’s a Pen with a checkbox simulating prefers-reduced-motion . Scroll down within the Pen to see the behavior change for each circle:
To re-create the “Pause all animations”-checkbox in JavaScript, iterate all the [data-animation] -elements and toggle the same —animps custom property:
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'); >) >);
It’s exactly the same concept as the checkbox hack, using the same custom property: —animps , only set by JavaScript instead of CSS. If we want to support older browsers, we can toggle a class, that will update the animation-play-state .
To play and pause all [data-animation] -animations automatically — and thus not unnecessarily overloading the GPU — we can use an IntersectionObserver .
First, we need to make sure that no animations are running at all:
Then, we’ll create the observer and trigger it when an element is 25% or 75% in viewport. If the latter is matched, the animation starts playing; otherwise it pauses.
By default, all elements with a [data-animation] -attribute will be observed, but if prefers-reduced-motion is enabled (set to “reduce”), the elements with [data-animation=»stop»] will be ignored.
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); >);
You have to play around with the threshold -values, and/or whether you need to unobserve some animations after they’ve triggered, etc. If you load new content or animations dynamically, you might need to re-write parts of the observer as well. It’s impossible to cover all scenarios, but using this as a foundation should get you started with auto-playing and pausing CSS animations!
Bonus: Adding to the slideshow with minimal JavaScript
Here’s an idea to add music to the slideshow we built. First, add an audio -tag:
const audio = document.querySelector('your-audio-selector'); const details = document.querySelector('your-details-selector'); details.addEventListener('toggle', () => < details.open ? audio.play() : audio.pause(); >)
I did a “Silent Movie” (with audio)-demo here, where you get to know my geeky past. 🙂