Css keyframes animation свойства

An Interactive Guide to Keyframe Animations

CSS keyframe animations are awesome. They’re one of the most powerful, versatile tools in CSS, and we can use them for all sorts of nifty things.

But they’re also often misunderstood. They’re a bit quirky, and if you don’t understand those quirks, using them can be quite frustrating.

In this tutorial, we’re diving deep into CSS keyframes. We’ll figure out how they work, and see how to build some pretty swanky animations with them. ✨

This tutorial is written for JavaScript developers trying to become more comfortable with CSS. But it should be suitable for all developers comfortable with the basics of HTML/CSS.

If you’re pretty advanced with CSS, you’ll probably know most of what we cover, but I do share some pretty cool and obscure stuff near the end of this post. 😄

In this tutorial, we build on the knowledge shared in “An Interactive Guide to CSS Transitions”.

The main idea with a CSS keyframe animation is that it’ll interpolate between different chunks of CSS.

For example, here we define a keyframe animation that will smoothly ramp an element’s horizontal position from -100% to 0% :

Each @keyframes statement needs a name! In this case, we’ve chosen to name it slide-in . You can think of this like a global variable. *

Keyframe animations are meant to be general and reusable. We can apply them to specific selectors with the animation property:

(To re-run the animation, refresh the “Result” pane by clicking the

As with the transition property, animation requires a duration. Here we’ve said that the animation should last 1 second (1000ms).

The browser will interpolate the declarations within our from and to blocks, over the duration specified. This happens immediately, as soon as the property is set.

We can animate multiple properties in the same animation declaration. Here’s a fancier example that changes multiple properties:

In “An Interactive Guide to CSS Transitions”, we learned all about the different timing functions built into CSS.

We have access to the same library of timing functions for our keyframe animations. And, like with transition , the default value is ease .

We can override it with the animation-timing-function property:

By default, keyframe animations will only run once, but we can control this with the animation-iteration-count property:

It’s somewhat rare to specify an integer like this, but there is one special value that comes in handy: infinite .

For example, we can use it to create a loading spinner:

Note that for spinners, we generally want to use a linear timing function so that the motion is constant (though this is somewhat subjective—try changing it and see what you think!).

In addition to the from and to keywords, we can also use percentages. This allows us to add more than 2 steps:

The percentages refer to the progress through the animation. from is really just syntactic sugar ? for 0% . And to is sugar for 100% .

Importantly, the timing function applies to each step. We don’t get a single ease for the entire animation.

In this playground, both spinners complete 1 full rotation in 2 seconds. But multi-step-spin breaks it into 4 distinct steps, and each step has the timing function applied:

Unfortunately, we can’t control this behaviour using CSS keyframe animations, though it is configurable using the Web Animations API. If you find yourself in a situation where the step-by-step easing is problematic, I’d suggest checking it out!

Let’s suppose that we want an element to «breathe», inflating and deflating.

We could set it up as a 3-step animation:

It spends the first half of the duration growing to be 1.5x its default size. Once it reaches that peak, it spends the second half shrinking back down to 1x.

This works, but there’s a more-elegant way to accomplish the same effect. We can use the animation-direction property:

animation-direction controls the order of the sequence. The default value is normal , going from 0% to 100% over the course of the specified duration.

We can also set it to reverse . This will play the animation backwards, going from 100% to 0%.

The interesting part, though, is that we can set it to alternate , which ping-pongs between normal and reverse on subsequent iterations.

Instead of having 1 big animation that grows and shrinks, we set our animation to grow, and then reverse it on the next iteration, causing it to shrink.

Originally, our «breathe» animation lasted 4 seconds. When we switched to the alternate strategy, however, we cut the duration in half, down to 2 seconds.

This is because each iteration only performs half the work. It always took 2 seconds to grow, and 2 seconds to shrink. Before, we had a single 4-second-long animation. Now, we have a 2-second-long animation that requires 2 iterations to complete a full cycle.

We’ve picked up a lot of animation properties in this lesson, and it’s been a lot of typing!

Fortunately, as with transition , we can use the animation shorthand to combine all of these properties.

The above animation can be rewritten:

Here’s a piece of good news, as well: the order doesn’t matter. For the most part, you can toss these properties in any order you want. You don’t need to memorize a specific sequence.

There is an exception: animation-delay , a property we’ll talk more about shortly, needs to come after the duration, since both properties take the same value type (milliseconds/seconds).

For this reason, I prefer to exclude delay from the shorthand:

Probably the most confusing aspect of keyframe animations is fill modes. They’re the biggest obstacle on our path towards keyframe confidence.

Let’s start with a problem.

We want our element to fade out. The animation itself works fine, but when it’s over, the element pops back into existence:

If we were to graph the element’s opacity over time, it would look something like this:

Why does the element jump back to full visibility? Well, the declarations in the from and to blocks only apply while the animation is running.

After 1000ms has elapsed, the animation packs itself up and hits the road. The declarations in the to block dissipate, leaving our element with whatever CSS declarations have been defined elsewhere. Since we haven’t set opacity for this element anywhere else, it snaps back to its default value ( 1 ).

One way to solve this is to add an opacity declaration to the .box selector:

While the animation is running, the declarations in the @keyframes statement overrule the opacity declaration in the .box selector. Once the animation wraps up, though, that declaration kicks in and keeps the box hidden.

In CSS, conflicts are resolved based on the “specificity” of a selector. An ID selector ( #login-form ) will win the battle against a class one ( .thing ).

But what about keyframe animations? What is their specificity?

It turns out that specificity isn’t really the right way to think about this; instead, we need to think about cascade origins.

So, we can update our CSS so that the element’s properties match the to block, but is that really the best way?

Instead of relying on fallback declarations, let’s consider another approach, using animation-fill-mode :

animation-fill-mode lets us persist the final value from the animation, forwards in time.

«forwards» is a very confusing name, but hopefully seeing it on this graph makes it a bit clearer!

When the animation ends, animation-fill-mode: forwards will copy/paste the declarations in the final block, persisting them forwards in time.

We don’t always want our animations to start immediately! As with transition , we can specify a delay, with the animation-delay property.

Unfortunately, we run into a similar issue:

For that first half-second, the element is fully visible!

The CSS in the from and to blocks is only applied while the animation is running. Frustratingly, the animation-delay period doesn’t count. So for that first half-second, it’s as if the CSS in the from block doesn’t exist.

animation-fill-mode has another value that can help us here: backwards . This will apply the CSS from the first block backwards in time.

“Forwards” and “backwards” are confusing values, but here’s an analogy that might help: imagine if we had recorded the user’s session from the moment the page loaded. We could scrub forwards and backwards in the video. We can scrub backwards, before the animation has started, or forwards, after the animation has ended.

What if we want to persist the animation forwards and backwards? We can use a third value, both , which persists in both directions:

Personally, I wish that both was the default value. It’s so much more intuitive! Though it can make it a bit harder to understand where a particular CSS value has been set.

Like all of the animation properties we’re discussing, it can be tossed into the animation shorthand salad:

Keyframe animations are cool enough on their own, but when we mix them with CSS variables (AKA CSS custom properties), things get ⚡️ next-level ⚡️.

Let’s suppose that we want to create a bouncing-ball animation, using everything we’ve learned in this lesson:

To make the bounce animation a bit more realistic, I’m using a custom timing function, using cubic-bezier .

I’ll be publishing a blog post all about the magic of Bézier curves soon — subscribe to my newsletter if you’d like to be notified when it’s published! 😄

CSS animations are meant to be generic and reusable, but this animation will always cause an element to bounce by 20px. Wouldn’t it be neat if different elements could supply different «bounce heights»?

With CSS variables, we can do exactly that:

Our @keyframes animation has been updated so that instead of bouncing to -20px , it accesses the value of the —bounce-offset property. And since that property has a different value in each box, they each bounce to different amounts.

This strategy allows us to create reusable, customizable keyframe animations. Think of it like props to a React component!

So, something bothers me about the example above.

With the translateY function, positive values move the element down, negative values move the element up. We want to move the element up, so we have to use a negative value.

But this is an implementation detail. When I want to apply this animation, it’s weird that I need to use a negative value.

CSS variables work best when they’re semantic. Instead of setting —bounce-offset to a negative value, I’d much rather do this:

Using calc , we can derive the true value from the provided value, within our @keyframes at-rule:

We only define this keyframe animation once, but we’ll likely use it many times. It’s worth optimizing for the «consumer» side of things, to make it as pleasant to use as possible, even if it complicates the definition a bit.

calc lets us craft the perfect APIs for our keyframe animations. 💯

As I was building the last couple demos, I realized just how much CSS has evolved in the past few years!

It’s become an incredible language, expressive and flexible and powerful. I love writing CSS.

And yet, so many front-end developers have a very different relationship with the language. I’ve spoken to hundreds of JavaScript developers who find CSS frustrating and confusing. Sometimes, the exact same CSS will behave totally differently! It feels so inconsistent.

I have a theory about this: unlike with JS, so much of CSS is implicit and behind-the-scenes. It’s not enough to know the properties; you need to know the principles driving them.

I’ve spent the last year working full-time on a course that will help teach CSS at a deeper, more fundamental level. If you found this blog post helpful, you’ll love the course.

It’s called CSS for JavaScript Developers, and it’s just been released to the public. You can learn more at css-for-js.dev.

Источник

Читайте также:  Алгоритмические задачи для java
Оцените статью