CSS Animations and Transitions
Watch on YouTube (MasterDotDev)
What is this talk about?
“We could add that same animation to the input and button, and let's see how that looks.”
“Instead of doing animation duration times two or animation duration plus animation duration, we could do a little bit of math here and just to calc the animation duration plus the input duration.”
From the opening of the talk.
Key takeaways
- We could add that same animation to the input and button, and let's see how that looks. 1:00
- Instead of doing animation duration times two or animation duration plus animation duration, we could do a little bit of math here and just to calc the animation duration plus the input duration. 3:00
- Remember over here, every animation frame we want to move a portion of the way towards the target points, and so that's what's going to get us our smooth animation. 13:00
- Let's kick it off by actually lerping and then that's going to recursively call lerp every single animation frame. 16:00
Quoted from the transcript.
Full transcript
From the uploaded captions. Technical terms were normalized; some errors remain. 2,209 words.
0:00 Introduction
[MUSIC].Hey, my name is David Khourshid and I'm a web developer who is passionate about animations in frontend technology. I created this course on CSS animations because animations bring user interfaces to life, and I want you to know how to add meaningful animation to your web projects. In this course you will learn about CSS transitions, animations, custom properties, data attributes, choreography, animation states, layout animation and reactive animations with a little bit of JavaScript. I hope you enjoy the course. So, let's add some choreography to this animation over here or lack of animation. Let's add some animation and some choreography to that. So, what we're gonna do is, we're gonna jump into style.scss. And we already have a few keyframes set up, of course we have the shake but we also have slide up. So let's use that slide up and do a little bit of choreography. So first of all, we have the form sliding up, which is great, but now I want the input and the button to sort of appear after the form slides up.
So, we could add that same animation to the input and button, and let's see how that looks. So, now you see that they all signed up at the same time. We sort of wanted those to be a little bit separate from each other. So, instead of this, I'm gonna separate this a little bit. We're gonna say animation name slide-up, we are going to give it the same duration. So animation duration, far animation duration, and we also wanna give it the same easing. Since this easing is already on the parent, we could do this. We could say animation timing function, inherit, and it's just going to grab that same easing. Now, we want these to appear after this animation duration, which we've set in a CSS variable. So we could give this input a delay of that duration, so animation duration, and so let's see how that looks, Okay, remember, we need fill mode both, and I'd like to just use fill mode both as a default, at least when something like this happens you know that we could adjust the fill mode.
So now this is sliding-up after the entire form slides-up. Okay, so now we have to do a little bit of math here because the animation delay over here is going to be that same animation duration, but we also want it to happen a little bit after the input. So, instead of doing a lot of extra math here, again, you could hoist this up to the parents. So, we could say that, we had the animation duration over here. And so this is basically going to be the animation duration of both the input and the button. So, for now I'm going to set. Input duration, and this is just going to be the same as the animation duration. And so we could set that here. Input duration. And so now instead of doing animation duration times two or animation duration plus animation duration, we could do a little bit of math here and just to calc the animation duration plus the input duration.
So now, this is going to appear right after the input appears now of course we could do a little bit of staggering here as well or we could adjust like the durations. So, let's say I want this input duration to actually be half the length of the total sliding up animation duration. So I could say calc animation duration divided by 2. And now this will happen a little bit faster and the button will come in at the right time. So, that's just one of the many examples that you could do with choreography and hopefully you all had like a creative twist or just something custom that you wanna do, but that's basically how you choreograph animations. So let's control this a little bit better with some JavaScript just the same example over here. So, we're going to be adding some a script over here, and remember we puts the data-state attribute on the app elements.
5:00 We could say machine, we have states, loading, success, and initial
So, what we could do is just have a way of just toggling that's from JavaScript itself. So first, like we showed before, I'm gonna grab that app element, document.querySelector, and we're gonna grab the app. And then what I want to do is, this button, so let's grab the button as well. Const button=document.querySelector. Just the same button. We're going to add an event listener so that when you click the button, we change the data states of the app. So, button, call this buttonEL.add event listener, click. And we are going to say appEL.dataset.state=loading. Okay, so now, let's actually make this even more prominent. When this data state equals loading. Let's just change the backgrounds to orange. So I'm just gonna say bg, let's call this well, firstly it will be white. And then we want it to be orange. So now, for the entire app, let's just say background bj. Okay, right now it's loading just because the data state is already loading, so if we remove that's then we have a plain app and when we click the button, now it changes to loading.
So, we could toggle between these, and so we could read that dataset, state and say if the dataset.state is already loading, then make it success, otherwise keep it as loading. So now it's going to basically toggle back and forth between loading, success, loading, success, et cetera. Now, there's other techniques for how you could transition between states. One of my favorite techniques is by using an object, so I could just say const machine. And this is related to my other workshops on state machines. But you could do this like without using any libraries. So we could say machine, we have states, loading, success, and initial. This is just a plain object, and so we can see that we're starting in the loading state, and so, on click success and in the success state on click we go to loading. And so now instead of doing this, especially when your logic gets a lot more complex, we could just say, read whatever the current state is and figure out using this object, what the next state should be.
So, we could say const currentstate = appEL.dataset.state. And so, the next state should be the machine.states, in so we're going to look for what the current state is. So just two current state, and then.on and then we're just gonna say this is a CLICK. And if that doesn't exist then just stay with the current state. And so now that is going to allow us to just use that logic and set the state from there. Now, you don't have to do all this but it does make it a lot easier to visualize exactly how states can change in your app. So, let's see, we have a little error, cannot read on. Okay, so we want to get the current state. So that can be that or the initial state. Okay, so, yeah, now we're going back and forth between the three. And so, we could even like let's just have a start state and then on click.
We're gonna go to loading, so it's going to start in the start state, and when you click it goes to loading, and then when you click again it's gonna go to success and then back and forth between loading and success. And again going back to data state attributes, we could change the background to let's say green, make it a nicer green, so what are these greens, on the success state? So now, when we reload, we're toggling back and forth between each of those states. We just have to set the initial state to start and there we go. Instead of it moving directly with your mouse, a lot of websites do this where it's actually doing a very smooth transition from where it was to your mouse. And so, because the distance isn't known ahead of time, you can't just calculate keyframes or animation duration or any anything like that on the fly, instead, it's using a different technique in which there is no defined animation.
11:00 With 0.5, we could say hey on the next frame go…
So here's the technique, let's say that instead of doing this like going from this frame to this frame, like basically doing going from here to there like the blue to the red in two frames. We want to do that over a series of frames but we wanna do it in a smooth way, well here's what we could do. Let's pick a fraction like 0.5. So with 0.5, we could say hey on the next frame go halfway there, and then repeat, so on the next frame go halfway there, in fact that should be there, there. And then repeat again on the next frame, halfway there, on the next frame halfway there, you get the idea. So, if you look at this as sorta like positions over time, you can see that it's going really fast and then slowing down as it reaches its position. And by following the same formula, you could call it, by going only halfway every time. It doesn't matter where this is. So let's say that this is here, we're going to apply the same thing. So we're gonna go halfway, and halfway, and halfway. And so you could see that over time, we're going from here to here and it's smoothly animating to wherever your cursor is.
All right, so how can we do that? Well, we could use both a combination of CSS variables and lerp which again stands for linear interpolation I believe. Don't quote me on that. Okay, so how does lerp work? So, for loop to work, I'm just going to take these two over here. Let's keep track of our current points which we're just going to say is x at 0 and y at 0, and our targetPoints,which is wherever the mouse cursor currently is. So instead of setting the x and y from the event, we are gonna set the target points to whatever that x and y is. So we're going to say targetPoints.x is client x and targetPoints.y is clients y. Now, remember over here, every animation frame we want to move a portion of the way towards the target points, and so that's what's going to get us our smooth animation. All right, so, that's something that we're going to do in the lerp function, okay?
So, to do this we have to calculate a couple of things. First of all, the delta between the x I know this is sort of a flashback to our previous exercise on layout animation. But we're calculating the delta for the x value and the delta for the y value just to see how do we get to the middle of those two points. So const dx=targetPoint.x minus the currentPoint.x. dy= targetPoint.y- the currentPoint.y. And then we are going to make the currentPoint such that it's moving closer to the targetPoint by some percentage. So to do that, we're gonna say currentPoint.x= currentPoint.x plus a fraction of this. So let's just say 0.5, dx times 0.5. And then we're gonna do the same here, dy times 0.5, and then we are going to set those styles inside of that lerp function, so we're gonna do it over here. So this is going to run continuously.
And I'll show you what I mean in a minute. So this is going to be currentPoint.x, and currentPoints.y. Okay, so right now this isn't gonna do much of anything, but you know what let's just take a look, so moving this, let me make sure that we have the right file, let me just close this out. Okay, so we actually need to call lerp. Sorry about that, so whenever this happens, I'm gonna call lerp, not lert but lerp, okay. So now it's not moving halfway yet, we still have to do that. And so that's something that we could do in an animation frame. So, this is going to recursively call itself because again, when we're moving somewhere, we want it to move halfway. And then we want it to do the same thing again, so move halfway and halfway and halfway and so on until it reaches that point. So, we're going to request the animation frame, and we're gonna lerp again.
And so, let's kick it off by actually lerping and then that's going to recursively call lerp every single animation frame. Okay, so by doing that, hopefully this works. All right, you can see that now is smoothly animating to my mouse. And we did pick 0.5. And so that's going to make it go really quickly to our mouse, so it doesn't really look like it's being super smooth because it looks like it's just almost attached to our mouse. So to make this more apparent, I'm gonna change this to 0.1. And so now, you see it's taking its sweet time getting to the mouse [MUSIC]
Related talks
-
Behind the Illusions: Impossibly High-Performance Layout Animations
CSSConf Australia, 2018. 23:51, 3.8K views -
Getting Sassy with Node.js
Node.js official channel, 2015. 22:29 -
How to Create Smooth, Lightweight Website Animations
Prismic, 2020. 12:45 -
Animations: Use CSS or CSS-in-JS?
Prismic, 2021. 9:22