Loading
Current section: Animation 7 exercises
solution

Controlling Animation Delays and Fill Modes

Loading solution

Transcript

00:00 We're going to start by defining a keyframes animation in our Tailwind config. Remember, in Tailwind version 4, this configuration is going to move to the CSS file, and at the end of this workshop, we're going to port our work we're doing now in the JS config into the CSS config. Here's the Tailwind config file in TypeScript, and here you can see that we asked to create

00:18 the slides top, slides up, or slides top. Well, let's call it slides top as it's how it's referred here. We're going to create a new keyframes definition. The way you do this is open the keyframes key in the config file, and then each keyframe animation will

00:36 have a key named after the keyframe. Here we want slide top. You can call it slide up if you want. At the zero percent keyframe, or we can also call it from, we want the element to be transparent, so opacity zero. Fun fact, you can see that TypeScript is going to tell us that it needs to be a string.

00:54 This is something that is commonly mistaken in a lot of Tailwind config files, but here because we use a TS file and we try to satisfy the config type, it's going to yell at us to be very specific. Opacity is zero, and then two is going to be opacity one. Again, let's make it a string.

01:14 You could have zero percent and 100 percent as well here. We're going to push it down with translate y by 20 pixel, and here Copilot knows exactly what we're doing. We want to transform it to translate y is zero. To sum up, we start transparent and 20 pixel lower,

01:32 and then go up and fade in nicely. This is just the keyframes definition, and then we also need to define an animation that essentially consumes, let me scroll down, that keyframe. You can call it completely differently, but we'll also call it slide top, but this could call be woof.

01:50 What matter is that it consume the actual, as you can see here, slide top keyframe, and this keyframe needs to match the ones defined here. But let's call it slide top as well. So animation slide top will create an animate-slidetop utility

02:07 that is going to use the slide keyframe and go from two over 0.3 seconds with the ease out easing curve. So we have done this. I will leave that comment here because we need to take care of that later, but let's try to implement what we've got,

02:25 the slide top animation using the slide top keyframe. My expectation is we have a new animate-slidetop utility available, and so we can go in app.tsx. As it's suggested, we can add that slide top animation that we've created. So here, animate, and you can see the default tailwind animation

02:43 and our new slide top utility that uses the slide top keyframes. Very cool. And as I refresh, look at the logo here. Starts down, fades in beautifully. So we're going to add the same animate-slidetop utility to the H1 and the paragraph.

03:04 Here and here. And now when we refresh, all three animate, which is super cool. But remember, we want to stagger these animations so it feels a little bit more polished and organized. So we're going to leave the logo starting right at the start, a 0.3 second animation delay to the heading

03:24 and 0.8 animation delay on the paragraph. Of course, we can play around with other values, but I think that feels pretty nice. So let's remove the comment here. And you might think, because tailwind has a delay utility, you might think that delay 300 is going to do what we want, but notice that is a transition delay

03:44 and not an animation delay. In other words, it applies to transition like this hover rotation. So you could delay the rotation of this hover effect here. And matter of fact, let me go down to the anchor tag here where we have our hover rotate and go delay 300. And that when I hover,

04:03 you can see that there is a slight delay before the animation occurs and on leave as well. Let me undo this. This is not what we want here, and this is not going to work. So I have my delay 300 here. And if I refresh, you can see that it still comes right away. We don't want a transition delay.

04:22 We want an animation delay. As of version three of tailwind, there is no such utility, but we can use an arbitrary property where the key and value are defined arbitrary and do animation delay, 300 milliseconds. And if we look at the output of this, now we have our animation delay, just like we want.

04:42 And of course you could also go 0.3 S. This will have the same result. Any CSS valid unit is going to work because these brackets are literally an escape hatch into any CSS syntax that you want. It's just a way to write CSS on the fly, create this funky looking class,

05:01 but generating exactly a CSS that you want. And I often joke that tailwind CSS supports every single CSS property under the sun, even the ones that don't exist yet. I even made a fun video about this, but this is why. These arbitrary properties are like on-demand custom CSS. You don't always have to use this.

05:18 There is nothing wrong with writing CSS in a CSS file or creating a plugin, but I think this is really useful. And here, that's a perfect use case for what we want. All right, so this is going to add a delay in our animation, but you will see that we have a problem. Let me refresh. Oh, so you can see the Epic stack headline

05:36 is delayed by 300 milliseconds, but it's already showing before it starts animating. And then after 300 milliseconds, it starts its animation. And turns out we need to configure something else to our animation, and it's called the animation fill mode.

05:53 So just like we did an arbitrary property here for the delay, we can do animation fill mode backwards. And now when I refresh, beautiful, you can see that the Epic stack headline is stuck at the from key frame,

06:11 which is 0% opacity and translated down. And then when the delay happens, it eases into its final form. So we're going to do the exact same. I'll copy these two properties from the H1 tag, and we're going to paste them on the paragraph as well,

06:28 but change the delay from 0.3 to 0.8 milliseconds. And the result should be fabulous. Zoop, zoop, zoop. And we could leave it like this, and this works, but this is going to create some frustration as we start doing responsive adjustments to our animation.

06:45 So let me quickly show you why we need to make a change, and we'll make a change before we move forward. Let's take the H1, and to illustrate the friction we're going to face, I'm going to redefine the same animation, animate slide top, at the small breakpoint. So here we are on mobile below the small breakpoint,

07:04 and you can see the animation and delay work fine. But if I grow past the small breakpoint, it looks like we have lost our animation delay and the animation triggers immediately. And if I inspect what is happening with our animation here, we're going to look at the small animation slide top class that we've just added.

07:26 And if you look just below, animation fill mode backwards has been overridden, and so has the animation delay. Uh-oh, why is that? Well, let's toggle the animation shorthand. When you just use animation, it's a shorthand property to define a lot of different CSS animation properties.

07:44 Duration, timing function, delay, iteration. And would you look at this? Every property that is not defined explicitly inside the animation shorthand will be reset to its initial value. So the animation delay is reset to zero seconds,

08:00 and the animation fill mode is reset to none. That's a problem, and this is exactly why we are losing the delay on our animation. So why is that a frustration? Well, plain and simple, every single time that you redefine an animation at a breakpoint,

08:19 you are going to wipe out this definition. There's a way to work around it, and it is to duplicate these and prefix them at the small breakpoint. So when we redefine the animation, we redefine these to override the default initial values at that small breakpoint.

08:38 And now if I refresh, this is going to work again, because you can see that we're redefining the animation fill mode backwards. But interestingly, if I toggle this here, you can see that now these are being overridden by the small animation. If I turn that off, this one is going to win once again

08:58 and set it to, where is it, fill mode, back to none. And if I turn it back on, the none gets overwritten. So you get the idea. Every time you make a responsive adjustment, you have to repeat yourself and redefine specific components of the animation properties. So is there a better way to handle this? And yes, there is.

09:18 Well, partially. Okay, so why do I say partially? Well, there are things that never change. Every time we want to have an animation delay, we're going to have this animation fill mode backwards here and here, and essentially anywhere we want to have a delay, we're going to have to add this animation fill mode backwards property

09:37 to make sure that the thing is hidden until it shows up. And because this is always going to be exactly the same definition, we can bake that in to our animation here. And that's the comment that I left before. You can see that you want to define the animation fill mode CSS property

09:53 to the appropriate value that we've established is backwards. And we can do that directly inside the animation shorthand. So we have duration, keyframes, timing function, and fill mode. In other words, we can add here backwards, which means that anytime we use our animate slide top

10:13 at the default or responsive breakpoints, it is going to bake in that animation fill mode backwards. And in turns, it means that I can get rid of that one. And let's get rid of the small overrides that I had done for my example. And we can get rid of the animation fill mode here as well.

10:30 And now the animation works. We still have the redefinition just for debugging purposes on the small breakpoint. But if I go way past the small breakpoint, you can see that, oh, this is still a problem. So the problem is actually not related to the animation fill mode

10:48 because now we are still baking that in. You can see animation fill mode is set to backwards here. The problem is our animation delay is still being reset to zero seconds. And what is sad here is we cannot bake the animation delay inside the animation definition

11:08 because we want this to be changing every time we use this. We want to be able to stagger our delays. And so we can't hard code the value. It would be pretty nice if we could pass a function with a value inside the animation property. So do something like animate slide top 300 MS or something like this. But what we're going to do here

11:28 is we're manually applying our animation delay. This is kind of a trade-off, but at least we've got rid of the animation fill mode backwards repetition. But now if we wanted to redefine the animation at the small breakpoint, we would unfortunately have to also redefine the animation delay like so.

11:47 And this is now going to work responsively. All right, I want you to make sure this is super clear before we move on. I am going to remove this small animate slide top and the small animation delay override. And with that, we have our beautiful slide top animation

12:08 and we are ready to move on to the next step.