Animation and Vue.js


There's a lot to gain from adding animations to your site or app. Beyond their visual appeal, you can guide the user's attention, cover up slow to load components and elements, and reveal sections of a page without the user wondering where it came from. This talk will cover the built-in ways Vue.js helps you animate your site, and how for more complicated animations you can hook into third party libraries. It'll also cover the basics of animation itself – what to animate, what not to animate – and how you can use animations to enhance your website without harming the experience of people with disabilities.


Today I'm going to be talking about animation in your vue.js app. How you can use animation to improve your app, why you should do it, and when you maybe shouldn't be animating your app. My name is Callum, I'm a creator developer based in London. I've written a book called vue.js Up and Running, published by O'Reilly Media. And if you're on Twitter, that's my handle, feel free to give me a follow. So I figured we'd jump straight in with the why, why would you want to add animations to your site? So beyond the obvious visual appeal, like animations look good, that's a valid reason to add animations. There are a few functional reasons that you might want to add animations to your site. So animations are a really good way of leading users around your app. So for example, you might have a call to action you want them to look at, or you might want them to go to the next page, they might have made a mistake on a form and you want to alert them to it. animations would all help in these scenarios by guiding the user's attention towards this part of the page. So as I just mentioned, animations are a good way of guiding attention or distracting users. So another case would be, you've got a page which is loading quite slowly. If you display a loading sign or some sort of animation, the user will perceive the page to have maybe loaded a bit quicker. But of course, too much distraction is very much a bad thing. If you add too much animations to your site, they will be totally unusable, no one will be able to make it through your text. And this is especially bad for people with some disabilities, such as people with ADHD, or people with some vestibular disorders, who would be really badly affected by too much animation. So you've got to keep an eye out for that. So I figured we could make most of this talk just a big demo. I'm not so big on slides, even though they look like slides. So here is our first thing. It's just on this page. It's this menu here. So I'm sure if you've been on the internet before, which I figure you have, especially if you're watching this streamed, you'll have seen this kind of menu before. You click on a button, a menu comes in from the side. And this is a thing, this is probably one of the animations I've implemented most commonly in vue.js apps. So let's have a look at the code which powers this. So here, I'll just talk you through it briefly. We've got our menu open state, which is either true or false. Then here, this is our menu, which we're using the vshow directive so that when the ref is true, then the menu is open. Otherwise, it's not added to the DOM. And you'll see we've got this transition component wrapped around it. So what this does is this is a built in component in vue. This means that when the state changes, when the menu become, when menu open changes from false to true, it isn't just added to the DOM. It is added to the DOM, but it's got a bunch of classes added to it, which you can use to, in this case, add a css transform, css transition even. So here, what we can see is this class is, so when this element is added to the DOM, it's added with this enter from class. So it's got a css transform, which translates it to the right by 100%, which in this case would be the width of the menu. So effectively, when it's just added to the screen, the menu is just off screen here. So you can imagine it's sat slightly off screen. You press the button, it comes in on screen. That's what this translate means. Translate X 100%, translate it in the X direction 100%, which in this case is 100% of the width of this. So the next thing vue does once it's added this class and added this element into the DOM is it adds this class called enter active, which we use to add a transition, which we used to use a css transition, and then it removes this class. So the new transform will be unset. So effectively, it'll be translated nowhere. So it'll be its natural position in the DOM, which is here. So what the css transition property does is, in this case, we're saying transition the transform property, take 0.3 seconds to do it, and use this easing. I'll get back to easing in a second. But effectively, what this does is you can give it quite a few css properties, and it means that when it changes, don't change it immediately. Transition it from the old value to the new value in this time. So in this case, we're saying we want our css transform, which is going from a translation to the right to nothing because the class is being removed and taking 0.3 seconds to do it. So the explanation is a little convoluted, but hopefully, in the context of seeing what the menu does, that makes sense. That's the enter class. We've got a slightly different class for leave. So you can just combine these into one, depending on what you want to do. So you'll see on some of my later examples, I'll have enter active and leave active in the same rule. And then I'll just have this, the transform on 0.3 seconds. In this case, though, we have some easings. So we've got ease out on the way in and ease in on the way out. And that won't make sense if you don't know what it means. So I will show you. So if you watch this menu come in and out, you'll see when it goes out, it starts off moving slowly, and then it speeds up. You can sort of see it. And then on the way in, it does the opposite. It starts moving quickly, and then it slows down towards the end. You see that? So that's what this ease out and ease in means. Ease out means we're using an easing, which it doesn't just translate from this position to this position linearly, like that, and then stopping straight. It means it slows down. So it starts off fast, and then it slows down. There's a bunch of different easings available. MDN has a page that explains them all and some charts. The Gsat website, which we'll talk about later, has a bunch of animated charts, which are also really useful for understanding easings. Cool. So that's css transitions. The next thing we'll look at is css animations, which allow us to do slightly more complicated things. So here's our css animation. So again, for this, we're using a transition component. It's fairly similar to how the last one works. Instead of a menu button, we've got a separate button in the DOM, which we're using to animate it instead of the menu button. But it's still the same idea. We've got something that just drew a false, and we're using vshow here. The main difference here is that we're using a css animation instead of a transition. So you'll see here we've got the animation property instead of the transition property, although we're using the same class as mostly. What this does is a css animation, instead of just saying you've got one transition which goes from one place to another, it lets you set up keyframes. So you're saying what you want to happen at each stage of the animation. So you're saying you want the animation with 0%, you're saying the animation to start here, 50% of the time the animation has completed, you want this. And then 100% is where you want it to end up. So here we've got, so if we start by looking at the opacity, so the animation takes 0.7 seconds. What we've got here is at 0 seconds, so just after you've clicked the button, it's opacity zero. So you won't be able to see the text, it will be completely transparent. And then because it's 0.7 seconds, at 50% of that, 0.35 seconds, the opacity is set to one. So it's fully visible halfway through the animation, which we wouldn't be able to do that with a css transition. Because you can only have, effectively, you can only set 0% and 100%, you can't set the middle bits. Further to that, we've got a more complicated transform. So on the last slide, on the last demo, we had a translate transform. But this one, we're also adding scaling and rotation, which are two other properties supported by transform. So in this one, at 0%, we're starting translated up and left a bit, and then very small, scaled right down. So scaled means you're taking an object like that, and you're making it smaller. And rotate is rotation. So we're rotating it minus 3 degrees to the left. Then halfway through the animation, we've got a separate transform. It's going down to the right of where it'll end up. It's going slightly bigger, and it's being rotated in the opposite direction. And then at the end, we're just setting it back to what it should be normally. So when this animation is removed, it'll look as it should. There'll be no jumps. So that's what that looks like. We can see it's starting about here. It's jumping down here, then come back to here. And it's fading out in the first half of the animation. But when it's halfway through the animation, it's fully visible. In addition to translate, scale, and rotate, there's also a further property called skew, which if you can imagine a rectangle, so like that, skew slightly makes it moves one of the sides. So it's like one of the top of the bottom. So it's like that. It makes it skewed. I don't know. I've actually never used that. Yeah, so I figured now we've got this open, this would be a good time to talk about performance. So maybe you haven't seen this before, and you're thinking, wow, I can now animate everything. I can animate height. I can animate color. So in theory, yes, you can animate height. You can animate color. Some of the demos later on, I will be animating color. But they aren't performance to animate. You can only, the only things you can performantly animate are transforms and opacity. So the reason for this is they're the only things that don't trigger a repaint. So if we take the menu we looked at on the last example, so it's coming in from the right of the screen, you might think we can absolutely position the menu, and then we can animate the right property. I mean, you can do that, but it won't animate at 60 frames per second. It'll look jerky. It won't look great. Because every time, every frame, once the right property changes a bit, the browser has to look at everything else on the page or everything nearby to figure out if that has moved as a result. Whereas with transform with opacity, it doesn't have to look at any other elements. So these can be hardware accelerated. They're a lot more performant than anything else. I mean, you can use other things. Try to use these where you can, but sometimes you want to animate some stuff which these just can't animate. But be aware that it might hurt performance. Also I've been using v-show mostly. I figured now's a good time to talk about v-if versus v-show. So both are directives that show and hide an element. I could change it to v-if and it would look exactly the same. The difference between v-show and v-if is that for v-show, the text is still in the DOM. It's just hidden with display none versus with v-if, it'd be removed from the DOM entirely. So if something's being removed and added again multiple times, you generally want to use v-show. Well, if something's just coming in once and then it's never going to be seen again, that's where v-if is beneficial. I mean, in this context, because it's not being added and removed that often, it probably doesn't matter that much. But if you can imagine some, say you've got a large component with a YouTube iframe nested inside it, you don't want to be adding and removing that from the DOM repeatedly. Cool. So that's css animations. Next let's move on to javascript animations. So all the examples we've looked at so far have been powered by css, but a lot of animations on the web are powered by javascript. This could be because we want more complicated animations. For example, you might want... So that hint... Well, this is... I guess this is an example. So in this animation, you can see when it comes in, the background comes in first, then the text comes, then this text comes in, then the subtitle comes in afterwards. And same on the way out. They all come in at different times. Now, you could do this with a css animation. It wouldn't be very fun working out all the timings, and especially as these have their own easings, you could do it with a css animation. It just wouldn't be very fun to do. It'd be a bit complicated. So generally, you'd want to... I mean, this is a simple example as well. You can get a lot more complicated than this, and then you absolutely wouldn't want to be using css animations. So this is where javascript animations come in handy. So if we look at the code for this one, you can see there's a bit more code. Bear with me. So for this one, we're importing a library called GSAP, which stands for the GreenSock Animation Platform. It's a very heavily used library. Lots of websites use it. I use it a lot as part of my job. It's a good library. It's good fun. And it works well with vue. There are other libraries like AnimeJS available. There's loads of animation libraries. You don't have to use this one. So you can see here, we're still using our transition component. We've used this for the first three examples. But in this case, we're listening to two events. We're listening to the enter event, and we're listening to the leave event. And they both call different handlers. So if we take the enter event, it calls the handleEnter function, which is up here. So it's passing two arguments. The first one is the element. So it's this element. I will come back to the other argument in a minute. What we're doing here is we're setting up a GSAP timeline. A GSAP timeline is a way of chaining multiple animations together. So in this case, we've got our background element. We've got a separate element for the background because it moves independently of the actual element. So you'll notice, if I show and hide it, it goes outside of the actual element. So that's why we've got a separate background element. And we've got our heading and our text. And they're all coming in one after the other, which is what GSAP timelines are really good for. So this is a little outside the scope of this talk. So I won't go into it too much. But I'll just explain briefly what this is doing. So this is animating. It's taking this element. It's animating it from y equals 50, opacity 0. So down slightly and transparent. And it's animating it to y equals 0, its original position, and opacity 1. And taking 0.9 seconds to do it. You might have noticed in the previous page, in the previous example, I said to always animate translation, not any other form of moving an element. And this has got this y property. GSAP automatically resolves that to transforms. It's a nice way of working. Instead of having to have a transform here and calculate it as a string, that wouldn't be very fun. And then we've got this syntax here. So this is all fairly similar stuff. Then we've got this, which says we want this animation to start 0.2 seconds after the previous one. And we want this one to start 0.1 seconds after this one. And we've got something kind of similar on the way out. But I won't talk it through. So the second argument that's given to the function is a done argument. So this is how vue knows that the animation is complete. So we pass that straight into GSAP as the onComplete handler. And it calls vue when it's finished and lets vue know that it can clean up, it can remove its classes. On the leave, if it's using a VF, it can remove the element entirely. And the last thing we've got to know here is, if you're using only javascript animations, pass css equals false. And it won't add the classes we looked at in the previous two slides, which slightly improves the performance. Cool. So the next thing we'll look at is, it's very similar to this example. You'll notice, as I've loaded the page, it wasn't here. And I had to press the button to get it to come in. If this were set to true already, it wouldn't have animated in. It would have just been there already. It wouldn't have animated in. So we've also got another property called appear. So let's look at that. So we can add appear attribute here. And if we set this to true, what that'll do is, when we navigate to the page, when we reload the page, it'll animate in. So I'll just refresh the page. And you can see it's animated in. It's pretty simple attribute. But it's a good way of getting animations when you first load the page. So next, so everything so far has been looking at single elements. Or, I mean, this isn't a single element. This is three elements. But it's one child of the transition component. Next let's look at list animations. So in this case, we've got multiple elements. I'll just type in, so I'll show you what this code does. So what's going on here is, when I type in here, it displays it as, it splits it up into separate letters and displays it as span elements. So you can see, here's our text that we're typing into from the input. And then we've got a computed property, which splits it across, it splits it apart by letters and returns it as an array, which we're then iterating through to, yeah, we're iterating through it and putting it in the DOM one letter at a time. So in our transition group, while it might not be obvious from looking at it, because it's only one element written here, but it does work out as multiple elements in the DOM, one for each letter. So for this, we can't use our old transition component, it'll complain at us, it won't work. But instead, we've got a transition group component, also built into vue, which is really good for handling groups of elements. So here we're using css animations, we're back to using css animations. And what this example here does, it's fairly similar to the animation example. You can see when it enters and when it leaves, we add a transition. Here we're saying we're using the all property, which instead of saying transform 0.4 seconds, comma opacity 0.4 seconds, we're saying we want to animate everything, we want to transition everything that changes. And here you can see that we're animating it from and to opacity 0, and then we're translating it down 30 pixels. So let's look at the example again. If I remove one, it fades out and moves down. And if I add one, the opposite. Now this is all right, but you can see, you might have noticed that when we delete a letter, it moves down. And then when it's removed from the DOM, the other letters jump or in the opposite direction when we add one, it jumps. The other letters jump when we add a new one to the DOM. Luckily, vue has a way of working with this, which I'll show you in the next demo. So here you can see when I add the new letter, the other letters slide to the new position instead of jumping. And to do that, it's pretty simple. I'll talk about the rest in a second. We're just adding a move class and vue automatically sees that you're doing something with that and handles the position or change automatically. I also had to add this. I don't know why. It was buggy without it. I couldn't find it in the documentation. Maybe it's a bug. I don't know. So yeah, this is moving, but it supports other kinds of movements. So for example, this is some sort of anagram generator, I guess. So if I press Enter, it shuffles all the letters to a different position. And because we're using the move class, vue is automatically moving it around for us. It's really nice. So one thing to note, so you might have noticed there's quite a lot of code when I showed this before. And this is because it's two states. I've got this text in the right order, and I've got it in the wrong order. So the complication here is the keys. If I just used the order here, so if I used 0, 1, 2, 3, 4 as the keys, then this wouldn't animate because vue wouldn't be able to tell that I've shuffled them. It would just think I've changed what letter is in them. So most of the code here is handling that. So the split text is adding the index, and then we've got a new shuffle text, which sets shuffle text to this, but in a different order. So the I is still linked with our original characters. So this should be 0. This should be 1. Whatever, I don't know how to use a mouse. One of these would be 2. One of these would be 3. I don't know which way around. 4, 5. And that's how vue can tell that we've reordered it instead of just replacing them with new letters in a different order. So the final kind of animation that we are going to look at is state transitions. So here, this isn't really specific to vue, but it works well with vue. So here we've got some state. I'll just show you this here. It's a number. And then we want to change it to a new number. So if I click the button, the state is automatically animated to the new value. And the way this is working, we're using GSAP again. So GSAP, in addition to being able to animate css values and stuff like that, it can also animate properties on any object. So here we've got our number ref, and it's animating number.value to the new value and taking one second to do it. So that comes in really handy sometimes, and I will show you on the next demo. So that was kind of all the different kinds of animations you can do with vue.js. And now I figured, as I'm a massive fan of SVGs, and I haven't showed any SVGs yet in this talk, I would show this demo, which brings them all together. So here we've got this boat. If I press this button, it swims off screen. And then if I press the button again, it comes back into shot. So this is using the transition component again. I'll just show you the code for that. So here you can see this block here. This is our... So this here is our block. And we use the G. So the G element is kind of like the div element in html, because now we're in an svg component. I'll just show you that. Here we go. Here it is. So everything in here is inside an svg component. So it looks like html, but it's not. It's still XML, so it's pretty readable. But it's slightly different. So here we've got our G element, which it stands for group, and inside we have our boat. And when the G class becomes visible, so we've got our boat visible variable, which is set to true or false by the button. And here we've got... It's wrapped in our transition component, which you'll recognize these by now. It adds and removes the transform. So when you click it, it goes out using a transform, and then it comes back in again using a different transform. Here for these clouds, we're using transition group. So I'll just spam that a bit. It's adding more to an array. And then if I spam remove, it's removing them from the array. And it's animating them in and out. So let's have a look at that. So on the left, you can see right at the top, we've got our clouds array. It's our array of clouds, their positions and sizes. And then we've got two functions, add cloud and remove cloud, which is pushing you... It generates a new cloud or removes a cloud. And then here on the right, we've got our transition group, which contains our clouds, again using a V4. And then in our style at the bottom, we've got our css, which handles entering and removing. So it comes in from the left with opacity zero, and it leaves to the right again with opacity zero. So our clouds aren't changing direction or anything. It's using different from and to positions. And finally, we've got our state transitions. So here, everything I'll show you in the code. So we've got a time value, which it's a ref, which defaults to 18, so 6 p.m. And then this is being passed into a bunch of different components. So for example, this is the moon component. Our moon component on the right here, it's being given a time prop. And then we're changing the moon opacity depending on what time it is. So for example, there is no moon now because it's during the day. So we've got this number, and when we change it, lots of different elements will change state. So for example, some of them are changing color, some of them are changing opacity, some of them are changing position, such as the sun and opacity, like the moon. So that is an animation because I just dragged a handle slowly, but that isn't actually an animation. So the animation here is we're using GSAP again so that when we click a button, it smoothly animates that number. So right now, the number is 18. If I click this button, it's going to animate it to 12. And we can see the effect of that on our animation. So that's the summary of all the animation types in one svg. So we've looked at transitions without a group, so the boat going in and out. And we've looked at transition groups, the clouds. And then we've looked at state transitions. And that's it for my talk. Thank you for listening.
32 min
20 Oct, 2021

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

Workshops on related topic