High performance web user interfaces - Google I/O 2016

Chrome for Developers · Intermediate ·📰 AI News & Updates ·10y ago

Key Takeaways

Discusses building high-performance web user interfaces for Progressive Web Apps, including responsive and intuitive UI components

Full Transcript

[Music] Hello. H how you all doing? Good afternoon. Um so the slides have disappeared. The slides should come back. I would like Hello. Um, so, uh, well, this is the first of the web content at this year's IO, and I I couldn't get a straight answer from anyone whether it was like a flying start for the web or if it was like ripping a band-aid off to get off, you know, like get him over and done with so the fun can start. I don't know. But all the same, here we are. I'm Paul. I work on the web developer relations team, and I typically talk about performance. And today, I thought I'd take a break and talk about performance. Um, which is to say actually there is a slight difference. What I'd normally do is I'd normally explain how pixels get to the screen, pixel pipelines, how you know styles work and layout and stuff. But today I want to talk about building stuff because that's what we do. We build stuff. But before I get into talking about building stuff, I wanted to explain how it is that I think this talk fits the overall story, the scheme into which it fits. If you've heard us talk about progressive web apps, um you'll know that we've mentioned uh a bunch of things along the way. And if you haven't heard, you will do over the coming few days. And you'll hear about progressive web apps and you'll hear things about how you need HTTPS for a bunch of features. It's good for users. It's good for you. Um it's just generally a good thing. And HTTPS unlocks a bunch of stuff. Uh not least of which is push messaging, which is super exciting. great to get your users engaged back into your app and all that kind of stuff. Well, push comes through a service worker which itself requires HTTPS and a service worker is going to help you with the offline story. Um, which is cool, but I actually there's a bit about the offline story that I'm, you know, I don't mind the offline bit, but the bit that really gets to me, the bit I love is actually the poor connectivity bit. I on my way to work passed through Europe's busiest train station according to Wikipedia anyway. It's called Clappam Junction in the United Kingdom. And you would have thought that Clappam Junction being so busy would have amazing connectivity. Uh you'd be wrong. Um because every time I pass through it, my phone says, "Paul, I've got 3G." And I say, "No, you don't. You're putting up a spinner. This is not good." Service workers help here. They're going to help us smooth over uh some of these cracks in poor connectivity. So, progressive web apps, uh, bunch of stuff. Very exciting. And if all goes well, you're going to arrive here. The thing that you built is going to be on somebody's home screen. Now, that's cool. That's a position of privilege. That's a fun place for us to be. It's exciting. We've never been here before. But a closer look at that home screen, I think, reveals an interesting challenge for us. When I look at that and I say, "Which of these is the progressive web app or which of these are the native apps?" Well, okay, the Google Maps one is probably pretty obvious, but the other ones, I don't know. It could be one or the other. Now, a user is never going to say this to you, but there's an implied message here. That app looks like native. I hope it behaves like it. And when I say behaves, I think that falls into two parts. I think it's about the performance and I think it's about the interaction models, the way this actually feels, the things that it allows you to do, the kind of is it intuitive I suppose. So let's just quickly deal with the performance bit. If you've heard me, Paul Irish, Ilia, Gregoric or anybody from my team talk about performance in the last year, we've talked in terms of a model called rail, uh, which is kind of a way to put the user back in the middle of the performance story. And uh it boils down to these things. Um a way to kind of think about uh how the user is going to interact with your app and what they expect. So for example, if they tap on the screen, we want to respond to them in under a tenth of a second for it to feel instant. If we have an animation, whether that's scrolling or a transition from one state to another, we want that at 60 frames a second, and that's 16 milliseconds. Idle is an interesting one. It's about doing uh non-essential computation work um at a time that is convenient uh for the user as in when they're not interacting and they won't notice it. And you do it in 50 millisecond chunks so that you can uh get back to uh handling interactions if they occur. And load is sort of you know getting stuff on screen. I think it's what we'd all expect from the network or from a cache or what have you. And for the gold standard there we want to get something up on screen and interactive in under one second. Now, when we mention rail, uh, often people feel like we're saying everything's important, everything is like top priority, you must do all of these things. But I think reality tells us something different. I think when we look at the advice that we get and the the sort of the uh the way that things pan out in reality, it looks more like this. I think for most of us, we, you know, if the user taps on the screen, of course, we want we want to respond well. And we've heard that scrolling performance um you know that's a thing and idle. Yeah. Okay. Uh but load load. Yes, I've got that. Yes. When somebody talks performance, they talk load. And that's great. Now, what I'm going to say is that if we expect to be on a home screen and if we're going to build a progressive web app, I think the priorities start to look more like this, which is a different way of thinking about what's important. The reason I say that is kind of a bit back to front. So, let me work backwards from there. Let's assume that your app has has been added to somebody's home screen. If it was added to the home screen, the user was probably prompted. Chrome probably said, "Hey, you're using this a lot. Would you like to add it to your home screen?" If that happened, it's because you've met certain criteria. One of which will be that you've got a service worker. And other bits like a manifest. Well, if you've got a service worker, I think you're probably going to be handling things like the offline case or the poor connectivity case. So, I'm going to be passing through Clapam Junction and quite happy. So, I'm saying if you're here or wanting to be here, it looks more like this. Because while load remains important, you do have to load quickly. You do have to get the app on screen quickly. If you're hoping to run 10, 20, 30 times and you've got a service worker, you're loading from a cache. And if you're loading from a cache, you're not networkbound anymore. Correspondingly, think about the apps that you use every day from your home screen. If they scroll well and they're responsive and they have the features you want, well, that's the way you differentiate those apps and the things that you get. So, if you're thinking home screen, well, now we've got a whole new competition on our hands, things that we actually have to care about. And maybe you're sitting there going, I'm more of a site person, less of about the apps, but I still think uh this is going to be useful to you. I hope it is because uh we still all make user interfaces all the same and ultimately I think we're heading to a fairly web appy world. So with all that said, what I wanted to do is I wanted to step through the building of three components and they are they range from the kind of fully deterministic we know where we start and where we end with the the animations and the transition all the way through something that's a little bit more dynamic all the way to the far end where we have no idea up front exactly what the animation is going to behave like. Those three components are a sidenav, a dismissible card system, and an expanding and collapsing view. So, let's talk about the sidenav. Sidenav then is this one. Obviously, we're all used to them, I think. Now, what we're going to do is we're going to talk about a little bit of theory for each of these just to kind of set up how it is I would actually consider approaching them from a at least a performance point of view. So, we got our page here and let's chuck on a containing element and this is going to be the home for our sidenav into which we're going to place two other elements. a semi-transparent black background to obscure the page content. And of course, we'll have the sidenav contents themselves, which we're going to want to slide into place and in and out as we go. When it comes to that container, what I'd normally do um is I'd make it position fixed and uh left top zero, width 100%, 100%. Some people are like right zero, bottom zero. That's fine. Um, I know I don't feel strongly about it. Um, overflow hidden because when we've got something translated out the side, we don't want a scroll bar. But there's an interesting design decision that I'm taking here with my sidenavs, which is I've got pointer events none. The reason is this. A sidenav is the kind of element that you want primed and ready to go. If a user taps on the button, we need it to come in quickly. We don't want to have it out of the render tree because then when we bring it into the render tree, we have to trigger layout and styles and we have to paint the thing and then we can animate it in. So, we want it there. We always want it in the render tree, not hidden. Um, but then it's going to sit on top of everything else and block clicks. That's not cool. So, we can add pointer events none and clicks will pass through to the underlying content. When we bring the sidenav out, we can switch that to pointer events auto. You don't always want like this primed ready element, but if you have one like a sidenav, consider that you might want to just have it ready and set something like portrait and vents to none. Other things, this sidenav contenty bit, we want to promote this to its own compositor layer. Compositor layers are our way of separating a part of the page from other parts of the page. Bit like you would in an art package where you create a layer and then you can mess around with it and it's not going to affect the other layers that you've got. It's not just one flat bit map. It's sort of separated out. Browsers will let you do that and the way the easiest way is to use will change transform. Uh it's relatively new. in the last couple of years before that you would have used something like translatez0 which I think many folks have done. So what it kind of does, if you imagine there's this page here, simplest possible page I could think of with a photo of a bald guy and a nice guy and we put will change transform on that then it gets separated out. Yes, 3D. Love it. And when it's separated from the page, we can use a transform and move it around and it's separate. We don't have to repaint the page content behind it. It's an extremely useful thing that we can do. Now, maybe you're sitting there going, "That sounds cool. I feel like I should promote every element. Star will change transform." Burn that from your mind. If I'm not clear enough, don't do it. Don't do it. The reason you don't want to do it is twofold. Firstly, um we want to keep memory usage down. when you create a layer, the layer itself has memory uh associated with it, but you also have to load upload the textures to the GPU. And so that's memory you're going to use. And on a mobile device, you don't want to do that. The other thing you want to do is bear in mind that your time putting those layers back together is compositing. And you'll want to keep that time down. So the more layers you have, the more time you'll spend in compositing. So, it's a balancing act, but all the same, this is a primed and ready element, and we're going to promote it to its own layer. So, we've got will change transform, and we're going to transform this sidenav off to the side, just out of view, uh, with a curiously specific minus 102%. You might be thinking, why not a minus 100? And that is because I've got a shadow. And the easiest thing is just move it a little bit further. Uh, somebody's like, "Why don't you turn the opacity down?" You could do that, but why not just do 102%. What's 2% between friends? Nothing. Just do it. Just do it. Now, at some point, the user is going to tap on the button, and we're going to show the sidenav, which in this case is just going to be adding a class to the sidenav, which is going to remove that minus 102% and just transform none. And that will basically cause it to slide in from the side. With the semi-transparent black background, it's a similar kind of story. We just have will change opacity this time, which will create another compositor layer. Uh, and it will also create a stacking context. And then we can transition from opacity of zero through to opacity of one. Dismissing the sidenav is a fairly similar process, but it's the same, but in reverse really. Uh, but the way I choose to do it is I will say if you click anywhere, there we go. If you click anywhere in the sidenav, I'd like you to hide the sidenav, which is great because if you tap or click or whatever in the semi-transparent background, that's going to go. Uh, but the problem with that is if you actually click on the contents of the sidenav, uh, you're going to dismiss the sidenav, which might not be what you want. So, the easiest way to solve that is just to cancel it. If you click inside the sidenav, it is cancelling. Um, so you got to be careful with this, but I think it's a good use of this and that just involves stopping the propagation of the event. I think it's reasonable. The other thing is uh this is a behavioral thing that I think users expect from a sign. They expect to be able to gesture and sort of swipe it and move it around with their finger. Get rid of it. So in this case, my personal preference is to delegate that out to the document with a touch start, touch move, and touch end. Uh, since I've delegated that out to the document, uh, I need an early exit case. If you touch start, you know, on the document and it's not the sidenav, that's not so clever. So, we just have this that just says if the sidenav is not out, cuz it's a kind of modal element, you basically can just rely on this simple check. If the sidenav isn't out, don't worry about it. If it is, cool. Let's start figuring out what we need to do. And in this case, we're going to start visually updating every frame with request animation frame. Oh, where did this where did the slides go? Let's bring them back. Hello. It's twice. Terrific. So, we start this uh update uh loop with request animation frame. And the request animation frame, what we're doing here actually is decoupling a little bit. And I'll talk about this more in a moment. But I've got the request animation frame which is going to update every frame of the animation irrespective of whether I get touch input. As I say, we'll talk about that more in a moment. It's a useful thing. In the touch move, uh all we want to do is just find out where the finger has moved to. Uh because we're going to need that in a moment to actually slide the sidenav into position. A slight note here is that we would want to use prevent default uh because by default by default Chrome is going to throttle back the number of touch move events we get and we want them every frame if we want something that we can have stick to finger. So the way to get that every frame is to call prevent default. So with that said our update is fairly straightforward. We can just figure out where we've moved from and to. Make sure we never go past zero cuz we want to always go negative. And then apply a translation to the container. Works out just fine. And then when we're done, we need to remove that transform that we added dynamically because it takes precedent. It's got greater specificity than the class-based animation that we had. That's right. I said specificity twice and I didn't get it wrong. And that's with jetlag. Yes. Um, and then if you uh translate it off slightly to the left, we'll hide the sidenav. Works out just great. This is what it looks like in reality. This is a sidenav. The code for this is on GitHub. And I'll send you I'll give you a link to this in a little bit. And you here, see it's coming out from the side. It's going in. We can drag it around. It works out really well. In fact, from a performance point of view, this is the dev tools timeline. And you can see here I've taken a recording with the sidenav sliding in and the sidenav going out. And if we zoom in a little bit on the sidenav coming in, the top bit, the green bit is the frames per second, which is a steady 60 frames a second on a Nexus 5X. And you can see that below it there's the work per frame, and it's basically uh very cheap. We're doing really well here. So, this approach works well. If you want to recap on that because we're about to move on, um there's a show that I do called Supercharged and there's a live stream of me building uh the sidenav which is about an hour long and then there's the TLDDW which is this which is about five or six minutes long where I basically recap what I just told you uh bitly/sidenav. So let's move on to the swipeable cards because the sidenav was fun and it was pretty much a deterministic minus 102% to nothing and back again. Swipeable cards. Well, they're not primed. We don't know which card you're going to interact with. So, we don't necessarily want to be like will change transform on all these cards because there might be lots of them. So, let's see what's involved here. So, it's this, you know, it's that with the swipe and the move and the cool. So, our theory is that we definitely do want to promote this to a layer, but we want to do it at the last minute. We don't want to do it up front. So, we'll have to do that with JavaScript. When you move it to the side, we're going to use a transform because we did, you know, in the same way as we did with that photo. We kind of moved it back and forth. We want to do that. And we can use opacity as well. Transform and opacity are our two best friends when it comes to animating performantly. So, we'll use that as well. Now, I mentioned before about this decoupling and um of the touch input from the visual update. And this is pretty much what game developers do as well because whether or not you move your character or whatever on screen, they want to make an update. They want to draw the screen. And it's pretty much the same here. We always want to be updating the screen. We want to draw the stuff irrespective of whether you've actually interacted. So the way we do that is if you imagine every frame that we want to draw of the the interaction or animation, we just call request animation frame with the update function for every frame. And if we get a touch move event, great. We'll incorporate it into that frame. If we get one slightly after, that's okay. We'll deal with it in the next one. And if by some weird co-inky dink we got two of them, well, it doesn't matter. We were all we were going to do is store the touch value the the position and we'll deal with it in the next request animation frame. It's relatively cheap way. Now it shouldn't be the case that you get more than one but it could happen and so we want to decouple. We want to separate out what might happen here and as it happens um it means that you've got an update function that you can call independently if you ever need to for some other reason. Kind of works out well. Now when I show my code often people go um what gives with the bind thing uh it's just this is a total aside I just wanted to talk about it so that I don't know might be useful um it's in a bit of an acquired taste like earlier tea anybody like earlier tea no a few gra okay um basically what I'm doing here is I'm copying from the prototype into the instance um and binding it in the process the reason I do This is it's got two benefits and one cost. The two benefits are because I'm binding to this it means that when I'm in these functions if I say this do whatever it refers to the instance and not the event target. The other thing is they're named onstar on move on end. And that means that I can do uh add event listener and name call them by name and I can remove event listeners for tidiness sake. If you just use an arrow function it can be a lot more difficult to do that. Not impossible, but it just makes life a bit more difficult. So, our cards, they start here, and that's fine. We can do that. We can get the page x or the first touch events page x. I think when the pointer event stuff lands, that will be a lot easier. Um, it's not too bad. It's a line of code. And here, this is what I was talking about. We were going to use JavaScript to manually promote uh the car that we're interacting with to its own layer as and when we need it, not before. We don't want to basically promote everything just in case we cause oursel memory issues. So, this is where we started and now we're going to move off to the side here. Well, our on move is fairly straightforward. It's pretty much the same kind of deal. We can just track. That's all we're going to do. We're going to track in the on move and the update will take care of actually moving the card. like so because we know where we started, we know where we are, and that's just a translation at this point. So that's cool. If you're dragging the card, the translate is the current X minus the start X. And then we can use a transform to just move it around. Very similar to the sidenav, right? But there's a bit where you dismiss the card, right? So if this is like zero and off to the side is position one like normalized position one out to the side or in the other direction this is one. What I do is I throw up these thresholds at like I call I put it at 0.35 but you could put it wherever you like. If you go past this 0.35 threshold and release then we want to dismiss the card. So that would be in here in the on end. The threshold is the card width. There you go. And if you've gone past the threshold, then you set this target X, which we haven't seen to this point, but target X, and it's either going to be the card width or minus the card width, depending on where you were going. And that's in use here. Now, it takes this form translate X plus equals target X minus translate X all over four. Now, if you've been doing this kind of stuff for a while, uh, as I have, you'll recognize this pattern. If you've not seen this pattern before, it's incredibly useful. Uh there are variants of it. Um it's kind of like uh lurping uh and it's very very useful. It's kind of like the easiest easing that I know how to do. So you get this nice smooth motion and it takes this generalized form value whatever it is. And in this case it's the translation in X plus equals target minus value all over strength. Let's see what it means in a kind of for reals way. Um let's say we're taking this box from zero to 100. Well, it'll be 100 minus 0, which is 100 all over strength. That's four. Well, we moved it 25 pixels in that first go. So, it's now here. In the next frame, it's going to be 100 minus 25, which is 75 all over 4, which is 18.75 pixels and on and on. And it basically slows down because we get closer and closer and closer to our target every time, which gives us this kind of nice slowdown, which is cool because that's the feeling we want. We only want the car to kind of slide gently back to the middle or we want to dismiss it off. So there you go. So see it's a oneliner, but it's a really useful oneliner. I use it quite a lot. So now we got to detect the dness. Like how do we know when this card's done? I don't know. Well, there's one version which is where you kind of slide out to the middle a little bit. You don't go over the threshold and then you let go and we go back to the middle. Well, that one we can just ask if the translation is small. And if the translation is small enough, then we'll just reset it. It'll be fine. That would work. But the other one is basically, well, we've got to I'm going to dismiss it off to the side and it's going to disappear because that's something else that the user would expect. They'd expect this to disappear. They'd expect it to go to an opacity zero. It's part of that behavioral thing. In that case, there's a nice and easy cheap way of checking that it's basically gone, which is that it's invisible. And in that case, we can basically remove it from the DOM, but that will cause the other cards to just jump up immediately. And what we'd like to do is we'd like to slide them into position. Well, that would be like that. Okay. So, we've removed a card and that's going to cause the other cards to jump up. So, what we can do again with a translation is we can start at the the car that we've removed. We can immediately transform them all down by a card's worth of height plus in my case a little bit of a margin. And then we'll wait a frame for that translation to take hold. We're using request animation frame to do that. And now what we'll do is we'll switch on a transition on transform and we'll just remove that transform that we added. That again is another transform uh transition on transforms. Nice and easy. And it will cause that to slide up. When the animation's finished, we can basically say, okay, we're done. This card's gone. Pick another card. So, that's a slightly more dynamic version um of the first one really. And this is what it looks like in reality. You can uh Oh, go back, Paul. You going to do it? You going to do it? You going to do it? Yes. There you go. So, you know, smooth out. Let go. Fine. Dismissed that one. Dismissed that one. Great. Dev tools. Uh this is what it looks like again. Very green. That's all good news. Now, this bit of the the timeline is the card being dismissed. Uh, which as you can see is a fairly steady 60 frames a second. And then this is where the other cards slide up into position. And you'll notice at the start, cuz this is reality, there's a little dip in the frames per second. And that's because we're doing that setup of all the other cards to get them ready to animate them up. So, there is a little dip um just as that works going on, but it tends to not be too much of a problem because there's a break in the animation. and the first one disappeared. There's a break and then the other ones slide up and you don't tend to notice it. Again, if you want to uh see this one being made, there's another live stream uh and a TLDDW that could help. So, let's move on to the final one, the expand and collapse. Now, the expand and collapse is probably uh it's the most uh challenging of the three. And the reason is we don't know really where we're starting and where we're finishing ahead of time. And it could change with responsive break points. So, in this case, we're going to expand this one card out like that. But we could be doing any number of things. We could be sliding something down, bringing something in from the side. This is probably the the one you'd most likely to do in an app context because this is the kind of thing that people expect from an app, right? The theory here um would be well certainly what I do when I get something like this from a designer where I do it myself is I'll eyeball the animation over and over and over again. And okay, there's the pink thing that's fading in the header bar at the top, but mostly this thing is just changing size, right? It's getting bigger and it's moving on screen. its width is changing, its height is changing, its left is changing, and its top's changing. And those would be the ones that I would want to animate. Unfortunately, that wouldn't be the performant path forward. If you go to css triggers.com and you look up any of the four of left, width, height, or top, you'll see that for blink, gecko, webkit, and edge. Uh triggering changing any of those, mutating any of those will cause you to trigger layout, which is changing the geometry of the page. So that's the positioning or the dimensions of an element. And layout is normally proportional to the DOM size. the more elements you've got in the page, uh, the more time you're going to spend in layout. That's typically the case. So, you're going to do that if you, uh, change left width, height, or top. And, you'll do that every single frame of the animation. You'll also trigger paint. If you trigger layout, you're guaranteed to trigger paint. Uh, painting is going to be expensive because you're filling in pixels. And then you're going to have to composite any layers that you've got together on the page. Not a good story if you do that every frame of an animation. Certainly not on a mobile device. Now, from the previous two examples, you may have noticed that I'm a big fan of transforms. And the reason is this. With a transform, if you if you got something that's got its own layer, which I showed before with the will change, then you don't trigger layout, you don't trigger paint, you only trigger compositing if you transform it around. It's our new best friend, I think, for this kind of work. So, the question becomes, can we do an effect like that with transforms? The answer is yeah, we do just slow it down. That looks to me like a transform or it could be if we used a scale transform and we used a translate. Cool. But we we can't just hardcode it because we don't know what we've got. We don't know our values. The approach I take, I call it flip, and it stands for first, last, invert, and play. And I'll step you through what it actually means. first is where the thing starts on screen. So in this case, it's starting here. This is the card that we're going to tap on to trigger our animation. And what we can do is we can call get bounding clientrect. Way to go naming of functions, but it's been around forever. It's been around since like IE4. And it's amazing. It tells you like the width, the height, the left, the top, the bottom, the right for an element relative to the viewport. So you know where this thing is on screen and how big it is. Then what we can do is we can actually immediately snap uh our animation right to the final frame. Sounds a bit odd. Bear with me. In this case, I'm going to use an expanded class, but you could manipulate the styles any way that makes sense to you. So we've gone from our first, we've gone to our last position. That's cool. And then what we do is we call get bounding clientrect again. Now we know where we started and we know where we finished. Interesting. Now, admittedly, in this process, going from the first position to the last position forces styles and layout, which I'm sure you're sitting there going, pretty sure you said that was a bad idea. What are you doing? Hold on. There's two reasons why it's not as bad. Firstly, because I said it was here. Yeah, there's two reasons why it's not so bad. Firstly, we're only going to do it once. We're going to do it as part of the setup of the animation. We're not going to do it on every frame. We're doing it once. And I mentioned rail back at the start. Rail is going to help us out here. Bear in mind, the user tapped on the card to get to that finalized, you know, version. And they're tapping. And so, in rail terms, we actually have a tenth of a second to respond to the user. So, we've got a tenth of a second, and that normally gives us enough time to do some work. And in this case, you can typically afford to do a single styles and layout pass. Just the one, but you can afford to do it, but it'll still need to complete in less than 100 mills if we're going to stick to the rail stuff. But actually, in my experience, 100 millonds is actually plenty of time to get one of these styles and layout passes done. Okay, so we know where we started and we know where we finished. Now finally we are ready to introduce the transform to this situation because what we want to do is we want to return our card or our view back down to where it started just using a transform. Well we can do that because we know where we started where we finished and we can figure out the scaling that we need and then we can apply a transform to take care of it. So our net effect is this. Here we are before and we're about to tap. Ready, steady, go. That's it. At this point, we're actually done with the first, last, and invert. But actually, what happened was this. We went first, last, and then we didn't animate this bit. We inverted, which is cool because what we can now do is we can switch on a transform transition because we've managed to just basically apply a transform to this element and it will cause and then we remove the transform that we applied that invert transform and it will cause the card to do that. We just managed to remap that animation from width, height, left, and top through to using a transform. And that makes it much more likely that we'll get 60 frames a second. Yay. Flip does come with a couple of caveats though, and it would be remiss of me to miss those out. So, I shall tell you what they are. Firstly, if you scale something, you're going to scale the children elements with it. You might need to use sibling elements for content because if you've got something that's scaling and skewing and not quite, you know, linearly doing so, then the children will also get skewed and squashed and stretched, which might not look very nice. So what you want to do is you want to probably move that content out to a sibling element which isn't being squashed and stretched. Uh so it does require a little bit of gymnastics. Uh but it works out typically just fine. It's a bit of slight of hand uh smoke and mirrors to make that work. Like I said that first to last change involves forcing styles and layouts. So you need to be careful with it. Um you need to check your dev tools and just make sure that when that happens you're not spending a long long time. But when you do, this is the kind of the thing you get. This is on an Nexus 5X as well. Uh, and you can see it's the kind of, you know, it's a fun little animation. You can have lots of them on the screen. Tap one and it expands to take up the full screen. But like I say, flip is it's responsive design friendly because of the fact that we don't know ahead of time. We just ask what are you what are the positions on screen before we begin this animation. Um, in this case it was like this, but it could have been like this, which is the desktop version. Different size, different location on screen. Uh, but it works just as well. Works out really well for us. From a dev tools point of view, uh, this is what you'll see. Uh, this is the card expanding. Again, we're going to see a fairly uh, green uh, run across the board. Now, there are a few dips. What is it? 1 2 3 four dips. Uh, and that is just reality. Uh in this case, Chrome has decided partway through this animation to do some painting and that just happens sometimes. Uh but mostly it doesn't happen. And in fact, when you look at the collapsing animation, you actually get a much cleaner picture of what it's normally like. Uh which is like this, mostly green except for that bit at the start. Uh which is the first, last, and invert part. It's the setup of the animation. That's why it's running at a low frames a second because we take up to 100 millonds to do the setup. In this case, it's like 1410 to like 1440. So, 30 40 milliseconds, something like that on a 5x. Cool. So, we're nearly done. We've gone from a fully deterministic sidenav uh which we know ahead of time all the way through to something where we don't know ahead of time. We have to basically bake it into our code. The consistent things across those three, which tends to apply to all the kinds of animations that you should do if you want something that's performant is that you'll want to use a promote elements that uh that you intend to animate. Use things like will change or translate Z if it makes sense. It normally does. Uh but you'll want to use it sparingly. As I said, you don't want to overdo it and overuse memory. Transform and opacity changes are uh your friend because of the fact that they don't trigger layout or paint and they can uh typically involve GPU layers and that makes it uh pretty fast. GPU layers, compositor layers which have the GPU helping. There you go. Uh flip. I mean I'd love to find another way, but this is the only way I can think of at the moment to remap expensive properties to transforms. It's more work than just going transition width, height, left, top. There's a lot more code, but it works and it works really well and we have used it in production uh in the stuff that we've built um at Google. So, that's cool. If you're new to um rendering performance and you're sort of thinking why uh transform and opacity, what's layout, what styles, what's paint, I've never really spent much time. We have a section on Google web fundamentals that could help you. Uh it's the rendering performance section. There's also um a course that you can do with Udacity as well which runs you through uh exactly what's involved in every stage of the pipeline and that can be extremely useful to kind of figure out when you're looking at a dev tools timeline like why why did that trigger layout and it should hopefully help you there. If you want to see the source code and play around with the elements, the three elements that I showed, uh, you can do that with the supercharged UI. That'll take you to the GitHub repo where you can clone and play with the code. And if you want to watch the supercharged episodes where well, I I tend to do the coding and Surma interrupts me, but that's fine. Uh, it's just like real life in the office, so that's helpful. Um, you can do that. Ultimately though, when I think about this, um, I think it's a tremendously exciting position for us to be in as web developers. This is, uh, it's just so exciting. Like, somebody could add you to the home screen and you're incredibly useful to them and that's awesome. But with that comes some expectations. I think our users deserve uh, user interfaces that they they love using. I think the web is ready to give it to them. We sometimes have to do a little bit of uh of a dance to make it happen like you saw with Flip, but it can be done and it's completely worth doing. Well, I'm going to be out over in the mobile web area for the next few days just kicking around. So, come and say hi. Come and show me what you've been building and have a wonderful IO and thank you very much for coming to see me. Thank you, [Music] Lou. Heat. Hey, Heat. [Music] [Music]

Original Description

Users expect Progressive Web Apps interfaces to be responsive and intuitive. In this session we dissect some UI components, and see how we can build them in a performant way that delights our users. Watch more Chrome talks at I/O 2016 here: https://goo.gl/JoMLpB See all the talks from Google I/O 2016 here: https://goo.gl/olw6kV #io16 #GoogleIO #GoogleIO2016
Watch on YouTube ↗ (saves to browser)
Sign in to unlock AI tutor explanation · ⚡30

Playlist

Uploads from Chrome for Developers · Chrome for Developers · 0 of 60

← Previous Next →
1 Polymer Performance Patterns (The Polymer Summit 2015)
Polymer Performance Patterns (The Polymer Summit 2015)
Chrome for Developers
2 Polymer Power Tools (The Polymer Summit 2015)
Polymer Power Tools (The Polymer Summit 2015)
Chrome for Developers
3 Chrome Dev Summit 2014 – Chrome Case Studies
Chrome Dev Summit 2014 – Chrome Case Studies
Chrome for Developers
4 Web Directions Code 2015 round up
Web Directions Code 2015 round up
Chrome for Developers
5 Maintainable Code - HTTP203
Maintainable Code - HTTP203
Chrome for Developers
6 iron-ajax… wat?! -- Polycasts #26
iron-ajax… wat?! -- Polycasts #26
Chrome for Developers
7 The Guardian - Supercharged
The Guardian - Supercharged
Chrome for Developers
8 ES2015 (next version of JavaScript), Totally Tooling Tips (S2 Ep1)
ES2015 (next version of JavaScript), Totally Tooling Tips (S2 Ep1)
Chrome for Developers
9 #AskPolymer: Rob answers all the questions ever -- Polycasts #27
#AskPolymer: Rob answers all the questions ever -- Polycasts #27
Chrome for Developers
10 The Future of JavaScript - HTTP203
The Future of JavaScript - HTTP203
Chrome for Developers
11 Data Binding 101 -- Polycasts #28
Data Binding 101 -- Polycasts #28
Chrome for Developers
12 The Guardian part 2 - Supercharged
The Guardian part 2 - Supercharged
Chrome for Developers
13 The Future of Web Audio: with Chris Wilson and Chris Lowis
The Future of Web Audio: with Chris Wilson and Chris Lowis
Chrome for Developers
14 Chrome 46: New motion-path animations, client hints and service worker improvements
Chrome 46: New motion-path animations, client hints and service worker improvements
Chrome for Developers
15 Sublime Snippets, Totally Tooling Tips (S2 Ep2)
Sublime Snippets, Totally Tooling Tips (S2 Ep2)
Chrome for Developers
16 #AskPolymer: How do you make the show? -- Polycasts #29
#AskPolymer: How do you make the show? -- Polycasts #29
Chrome for Developers
17 Critical Path CSS, Totally Tooling Tips (S2 Mini Tip #1)
Critical Path CSS, Totally Tooling Tips (S2 Mini Tip #1)
Chrome for Developers
18 Binding to Objects -- Polycasts #30
Binding to Objects -- Polycasts #30
Chrome for Developers
19 Player FM - Supercharged
Player FM - Supercharged
Chrome for Developers
20 Where’s the Designer? #AskPolymer -- Polycasts #31
Where’s the Designer? #AskPolymer -- Polycasts #31
Chrome for Developers
21 Jake Beats Wikipedia - HTTP203
Jake Beats Wikipedia - HTTP203
Chrome for Developers
22 Supercharged Observers! -- Polycasts #32
Supercharged Observers! -- Polycasts #32
Chrome for Developers
23 Jai's Web blog - Supercharged
Jai's Web blog - Supercharged
Chrome for Developers
24 Windows Command-line Tooling, Totally Tooling Tips (S2, Ep4)
Windows Command-line Tooling, Totally Tooling Tips (S2, Ep4)
Chrome for Developers
25 What about internationalization? #AskPolymer -- Polycasts #33
What about internationalization? #AskPolymer -- Polycasts #33
Chrome for Developers
26 Developing for Billions (Chrome Dev Summit 2015)
Developing for Billions (Chrome Dev Summit 2015)
Chrome for Developers
27 Google+ Performance Improvement Comparison
Google+ Performance Improvement Comparison
Chrome for Developers
28 Deploying HTTPS: The Green Lock and Beyond (Chrome Dev Summit 2015)
Deploying HTTPS: The Green Lock and Beyond (Chrome Dev Summit 2015)
Chrome for Developers
29 Progressive Web Apps (Chrome Dev Summit 2015)
Progressive Web Apps (Chrome Dev Summit 2015)
Chrome for Developers
30 Instant Loading with Service Workers (Chrome Dev Summit 2015)
Instant Loading with Service Workers (Chrome Dev Summit 2015)
Chrome for Developers
31 Increase Engagement with Web Push Notifications (Chrome Dev Summit 2015)
Increase Engagement with Web Push Notifications (Chrome Dev Summit 2015)
Chrome for Developers
32 Engaging with the Real World: Web Bluetooth and Physical Web (Chrome Dev Summit 2015)
Engaging with the Real World: Web Bluetooth and Physical Web (Chrome Dev Summit 2015)
Chrome for Developers
33 Asking for Permission: respectful, opinionated UI (Chrome Dev Summit 2015)
Asking for Permission: respectful, opinionated UI (Chrome Dev Summit 2015)
Chrome for Developers
34 Polymer - State of the Union (Chrome Dev Summit 2015)
Polymer - State of the Union (Chrome Dev Summit 2015)
Chrome for Developers
35 Building Progressive Web Apps with Polymer (Chrome Dev Summit 2015)
Building Progressive Web Apps with Polymer (Chrome Dev Summit 2015)
Chrome for Developers
36 Introduction to RAIL (Chrome Dev Summit 2015)
Introduction to RAIL (Chrome Dev Summit 2015)
Chrome for Developers
37 DevTools in 2015: Authoring to the max (Chrome Dev Summit 2015)
DevTools in 2015: Authoring to the max (Chrome Dev Summit 2015)
Chrome for Developers
38 RAIL in the real world (Chrome Dev Summit 2015)
RAIL in the real world (Chrome Dev Summit 2015)
Chrome for Developers
39 #ChromeDevSummit talks are up - W00T! -- Polycast #34
#ChromeDevSummit talks are up - W00T! -- Polycast #34
Chrome for Developers
40 V8 Performance from the Driver's Seat (Chrome Dev Summit 2015)
V8 Performance from the Driver's Seat (Chrome Dev Summit 2015)
Chrome for Developers
41 Quantify and improve real-world RAIL (Chrome Dev Summit 2015)
Quantify and improve real-world RAIL (Chrome Dev Summit 2015)
Chrome for Developers
42 Owning your performance: RAIL (Chrome Dev Summit 2015)
Owning your performance: RAIL (Chrome Dev Summit 2015)
Chrome for Developers
43 HTTP/2 101 (Chrome Dev Summit 2015)
HTTP/2 101 (Chrome Dev Summit 2015)
Chrome for Developers
44 Leadership Panel (Chrome Dev Summit 2015)
Leadership Panel (Chrome Dev Summit 2015)
Chrome for Developers
45 Build Processes, Totally Tooling Tips (S2, Ep 5)
Build Processes, Totally Tooling Tips (S2, Ep 5)
Chrome for Developers
46 Accessibility (Chrome Dev Summit 2015)
Accessibility (Chrome Dev Summit 2015)
Chrome for Developers
47 Binding to Arrays -- Polycasts #35
Binding to Arrays -- Polycasts #35
Chrome for Developers
48 HTTP2 - HTTP203
HTTP2 - HTTP203
Chrome for Developers
49 Chrome 47: Splash Screens, requestIdleCallback and better desktop notifications (New in Chrome)
Chrome 47: Splash Screens, requestIdleCallback and better desktop notifications (New in Chrome)
Chrome for Developers
50 Call For Submissions - Supercharged
Call For Submissions - Supercharged
Chrome for Developers
51 Cross Device Testing, Totally Tooling Tips (S2 Ep6)
Cross Device Testing, Totally Tooling Tips (S2 Ep6)
Chrome for Developers
52 Testing AJAX with Web Component Tester -- Polycasts #37
Testing AJAX with Web Component Tester -- Polycasts #37
Chrome for Developers
53 Slack: Extended Xmas Special - Supercharged
Slack: Extended Xmas Special - Supercharged
Chrome for Developers
54 Browser testing with Travis & Sauce Labs -- Polycasts #38
Browser testing with Travis & Sauce Labs -- Polycasts #38
Chrome for Developers
55 Optimize for production with Vulcanize -- Polycasts #39
Optimize for production with Vulcanize -- Polycasts #39
Chrome for Developers
56 Highlights from Chrome Dev Summit 2015
Highlights from Chrome Dev Summit 2015
Chrome for Developers
57 Chrome 48: Custom buttons in notifications, DevTools Security panel, and Presentation mode
Chrome 48: Custom buttons in notifications, DevTools Security panel, and Presentation mode
Chrome for Developers
58 Crisper: Protecting your Polymer app with CSP -- Polycasts #40
Crisper: Protecting your Polymer app with CSP -- Polycasts #40
Chrome for Developers
59 How do I use Sass with Polymer? #AskPolymer -- Polycasts #41
How do I use Sass with Polymer? #AskPolymer -- Polycasts #41
Chrome for Developers
60 Colors – DevTools Tonight #0 (Pilot)
Colors – DevTools Tonight #0 (Pilot)
Chrome for Developers

Related Reads

📰
Your Manager Is More Dangerous Than AI (And You Don't See It Coming)
Your manager poses a greater threat to your career than AI, and being aware of this can help you take proactive steps to protect yourself
Medium · AI
📰
The AI Skills Nobody Is Talking About. But Every Professional Will Need Before 2030.
Discover the essential AI skills that every professional will need by 2030, beyond the usual hype
Medium · AI
📰
The picking scorecard still has no row for MCP and the GitHub trending list is dominated by MCP servers
GitHub trending list is dominated by MCP servers, but picking scorecards lack MCP row, indicating a mismatch between community trends and evaluation metrics
Dev.to AI
📰
The Architecture of Insight: How the Brain Downloads Ideas, and Why Stealing Concepts Resets Your…
Discover how the brain processes ideas and why copying concepts without understanding can be detrimental to innovation
Medium · AI
Up next
How to Handle the AI Shift
Matt Tutorials
Watch →