 Hi, everyone, and welcome back to the CSS podcast, where we cover all things CSS from accessibility to ZIndex. And this season, we're answering your CSS questions and helping resolve some of those CSS frustrations. Like a nice massage to work out the kinks of your code base. And one of those frustrations that you might run into is glitchy animations. And this is especially common for 3D animations, but it might happen in other contexts, too. So we'll start by covering issues in 3D animations, and we'll talk about 2D animations and other animation glitches that you might encounter. Excellent intro, glitchy resolutions. Here we come. So if you are doing any sort of 3D transforms or even transforming a card flip, where you've got content on the front and the back, can you believe there's a back? I don't think a lot of people even know that there's a back to everything you put on the page. I mean, anyway, whatever. You might run into some glitchiness when you're kind of switching between these things. This could happen when you're doing the transform and the browser's interplating between the states, which could be like something on hover or focus. And the browser's transform style property is flat by default. And when you apply transforms, you tend to do it on a 2D plane. So if you're creating 3D animations and they're not what you want, it's probably because you have to change the transform style. The fix is transform style colon preserve dash 3D, preserve 3D, which kind of sounds like a style I'd place on a dinosaur egg or something going extinct. You know, preserve this thing in 3D forever. Thank you. It's like cryogenically frozen. That's what we should transform style cryogenically frozen. No, that doesn't have the same ring. Anyway. Submit an issue to the working group. See if it lands. Actually, April Fools, maybe I should just go put a whole bunch of bad ones in there just to, no, I don't think that land good. If you wrote a post, yes, this plugin, it could work. Touche. I'll just make an ancient syntax for styling based on dyno language. Anyway, whatever, this is getting off track. If you use preserve 3D, it tells the browser to keep the 3D transformed elements in 3D space. I just kind of what it sounds like, but also it's kind of weird. You even have to ask for that. You're like, I'm putting them in 3D. So hey, be in 3D. And this is just so they don't get flattened out into the plane of their parent element. And so this is useful if you're running into issues with transformations in a 3D space, you're gonna want preserve 3D. And also it's like there's a video game concept in this where like a child node is trying to escape the 2D nature of its parent. You know, like I'm a 3D kid. I'm a 3D teenager, dad. You're 2D. Let me escape your 2D plane of existence. I'm ripe with these bad ones today. I'm so sorry. I'll just let you keep going. So another 3D CSS Gotcha is when you're creating something like a card where you have content on the front back and you want to flip it or a cube with content on multiple sides. So once you have set up your 3D space, sometimes you either don't get the expected side visible or it glitches during the transition if you're going from flat to something that is 3D on the transition. So if you could imagine an example of that is just that card parent with two divs, one is on the front, one is on the back and then you're flipping between them. But by default, you only see the div, the second div in reverse. And the browser is keeping it on top of the other div. And this is because of back face visibility. An element's back face, so it's back, is a mirror image of its front face. So by default, you see the back face of that when you flip it. And since it's second element, it goes second. So it has, it's on top of the one before it. So that's what you're seeing kind of flipping back and forth. And you're just going to see it in reverse. So you want to turn this off when you're working in this 3D space. And the fix for that is back face visibility hidden. You want to hide the back face of that element. If you hide the back face and once you flip it, you'll see the other element. So if you had a card with like a back and front, then you'll see the back face once you turn back face visibility to hidden. That's the key here. One gotcha with this is that back face visibility is ignored when you're applying overflow or opacity to the parent. And this is because overflow and opacity are grouping properties. They require the user agent to create a flattened representation of its child elements before they can be applied. And because of that, it forces the elements to have a flat style for Preserve 3D. So just like Adam talked about with Preserve 3D, it'll convert it to a flat style instead of the 3D style, which I just learned about all of this when preparing for this episode, but there are other grouping properties in addition to opacity and overflow. And those include clip path, filter, clips, isolation, mask image, mixed blend mode and containment. So if you're using container queries within kind of 3D transform, watch out for that too. There's also still some cross browser bugs with back face visibility, especially on mobile, but this space is a candidate for Introp 2024. So hopefully this gets accepted and finally ironed out soon. Excellent explanation. Reminded me of two things that I should have put in our notes here. One of them is, if you have two divs that are stacked on top of each other that you intend to hover and do the rotate, think about some of the glitches are because it's as if two pieces of paper are trying to exist on the same slice of paper. And so you see this tearing that can happen, right? We're like, it's seeping through because they're technically like, are they in each other or on each other? I don't know, they're like one, but not. And the browsers has a struggle, like deciding which one to show you. And so you'll see this like glitchy effect. And the other thing you reminded me too when you explained Preserve 3D is an interop issue I think it was last year it was decently recent, decently recent. Sorry, that was fun to say all out. I said you have to put Preserve 3D on stuff over and over and over again. So this is like another gotcha you're gonna have is you might just be like, all right, the viewport to my 3D world, Preserve 3D. And then you throw something in there and rotate its X to like have it look like it's in perspective in 3D and it doesn't do it. It's cause that also needs it. So I'm just remembering all my demos where I have like star selectors that put Preserve 3D on all the children so that when I rotate them they stay in 3D. Another weird thing with that example, like if you're hovering over the card you might lose your space once you start to rotate. So you might stop that animation. You need to give it a parent that you're hovering on or you're focusing, the focus doesn't give you this problem cause you're focusing on the element but if it's hover once you get to like here see how there's like a very thin space. You kind of have to make sure that you're always going to stay on that element to continue that transition. So that's just like another little gotcha that might glitch like you might see like a little flashback if you're not hovering over the right spot. Totally. Specifically for hover effects. Yeah, this is classic where you hover on something and slide it away and then when you're unhovered it slides it back and then it does it forever. Yeah, cause it's moving in that 3D space. So it's a very, very, very, yeah. Excellent call. All right, we also have one here. Overflow issues could also break your 3D illusions if your transformation exits the bounding box and you've hidden overflow, multiple viewport panes. It's like the browser has to look through the scroll port and the viewport and then your perspective port and all these different things. And so overflow can impact the way that this is all being rendered. Sometimes 3D animations can have very different across browser performance. And that's because of how browsers render the 3D buffer and 3D surfaces. Browsers aren't designed to be game engines even though Eric calls them 60 frames per second text scrollers or whatever, right? And it's awesome. It just sounds like a first person shooter but it's just a text scroller. Yeah. And so they're not designed to be game engines even though they can do a lot of the work. They're designed to be laid out as one thing in front of the others. So like layers, it's magic paper. I love thinking about the web, it's like magic paper. And that's why transform style is flat by default. I got magic paper, just layers of paper. And historically it wasn't very reliable, aka it was unreliable, especially on mobile to do like 3D animations. Just wasn't a lot of GPU power, but it kind of, it's gotten a lot better. Do you remember FAMO.US, about 10 years old now? Yeah, yeah. I've had one demo. And they made the coolest as all the elements from the periodic table that was swished around into a helix back into a table. And it was all in the iPad one and it was 60 frames per second, it was amazing. But the way they did it was by hacking the CSS 3D transform matrix. And you're like, no one's gonna write that by hand. That's not easy. Anyway, good news, it's gotten a lot better. There's a lot less jank. Things are, and if you find something that doesn't work, plug a bug. But I don't think you will, but I think the final tip here is just test it on mobile. That'll really help you, so. Yeah, that reminded me, just fun fact. One of the things that got me really into fine development was 3D CSS. Like it was just this really interesting mix of logic and design and just figuring out how to make those work. And at the time when these capabilities first came out, they were breaking a lot of browsers. I thought that was funny. So definitely a topic that I thought was fun. Yep, me too. So let's talk about slow animations too. You might be running into glitchy or slow animations because you're overloading your CPU and you have a lot of animations running that aren't being hard or accelerated. You might be dropping frames because of this and your user experience will suffer. So background, we talk about web page and rendering performance. In order to render a web page or re-render it upon some visual style change, the browser needs to go through four classic steps. There's style where it would calculate the styles that apply the elements that needs to be calculated first. Then there's layout step or layout stage where you generate the geometry and the position for each of those elements. Then there's paint where you fill out the pixels for each element onto layers. And then there's composite where you draw the layers onto the screen. Why do I wanna do this skit on stage at some point? I know, there should be like a little, there's many cartoons. I feel like there's a lot of articles about how to do this. There's lots of doodles, but I wanna see a person do it. You have the power and you have the equipment. Touche, I suppose I shall then expect that maybe, I don't know, I have somebody weird bad ideas. I can't go execute them all. But anyway, great explanation of those four steps. I think those are really crucial for people to know as they're like digging deeper and deeper into the front end space, as Paul said. And so like you were saying, some CSS changes, they affect all the steps. So like if you're also calculating styles and then you might just affect one though. So like that's the thing is knowing what you're changing can help you know if you're affecting all four of the steps which is gonna be extra slow or if you're popping in right there at the last step, the composite step. So animating something like width requires layout changes which then affect paint and then composite. And there you go. You got three little dings against your performance there. But if you use transforms like scale or opacity, those only affect the composite steps. So that's at the very end. It shows up, it goes, I'm happy to do this. I'm just gonna nudge this a little bit like this. And it's able to do it very efficiently. So try to use hardware accelerated properties, generally as best practice for all CSS animations and these include opacity and transforms. And if you can't use these optimized properties and you're seeing jank, you can use well change on your element. And this lets the browser know like ahead of time that I'm gonna change this property and you list out the properties and it will change. So also avoid saying all in there where you're like, I'm gonna change everything. The browser is like, I'm ready for all of it to change that and it'll like spoon up and ramp up and probably be overly excited for the tasks that you're doing for it. But this can allow you to sort of manually create a layer. They're called like GPU layers, that composited layer where all those steps are squashed into one and that can be moved around and scaled nice and easily. Telling something will change, it can do that work ahead of time too. So you're basically telling it to promote this layer, do as much of this work in the GPU as you can and be ready for me to change things. But the tip here is use it sparingly. You can totally overdo it. So if you've got a hundred items and you want them all to animate, don't give them all will change because then it's gonna take all of those, put them in the GPU and maybe run out of memory while I did that and then it's gonna be really bad. You can also remove the property or put it on just in time. So you can put it on to 30 of them, have them animate doing something funky that's not scale or transform or opacity and then take it off when they're done so that we can free up the memory and tell the browser, I'm all done changing those. Yeah, those are some good pro tips and some good advice, especially if they don't overdo it. I like that sort of adding it just as you need it, just in time. Jit. Jit. So another sort of along the same vein little hack is sometimes you could just hack something to force hardware acceleration like adding transform, translate 3D000. This won't actually make any transform difference but it can fix some glitchy bugs so recently with scroll driven animations there was still what it was being a work in progress in Canary. This transform, translate 3D000 thing fixed a lot of the inconsistencies and bugs while they were getting started out. It just sort of can be a kill switch sometimes if you're running into weird glitches with animations. You could do that force hardware acceleration little hack, it's a hack. It's a hack. It's a hack when CSS3 just came out, which is funny, that's a long time ago. We called that the silver bullet and then it got reduced. It was, so we would do, yeah, translate 3D000. But then we were like, if all we're trying to do is trick it in and make it a layer, why don't we just do translate Z0 and then that became the new silver bullet, slightly less to write I guess and was more pinpointed. Anyway, it was dumb. That was a lame thing for us to have to deal with but it didn't have a cool name. The silver bullet, like, oh yeah, just put this on there and watch the animation get better and you're like, hey, it worked. Kind of is the silver bullet, that's annoying. But yeah, we got better ways to promote things to the GPU now. Oh man, the jokes. I just like want a night layer, like give me a sword, but like, I'll now promote you to a layer. And it's like, yeah, I've always wanted to be one. Okay, so another thing to make note here is like sometimes a really intense easing function can cause some frame rate loss or some jank. I've got easings that are like really striking. I'm talking like they just shoot out the gate and then they slow down right at the very end. And sometimes the browser struggle with those. Like using the built-in keywords is very reliable but if you make a really intense easing on over a short amount of time, you might find you get some jank there. And also sometimes with 3D work, Z and X or translate Z can be weird and we were talking about seams and intersections with other elements on the same plane of existence. It can be really nice. I think there's even a tip in a hot tip when they were refactoring transform 3D and something like how you have to write preserve 3D and all the layers is that if you don't put something on zero, it's better. Like putting something at least on Z index one or translate Z one will help you be in the scene as opposed to like on the screen of the scene. So just things to think about that depth starts to have meaning. And then you can use that to your advantage and it might be a cause of a bug or a way to get out. Interesting, nice. So another issue you might be running into is if you're trying to animate properties that don't interpolate. And we talked about interpolation in the last episode ad nauseam. So this would be an example of if you're animating discrete properties. These are properties that don't move slowly from one value to another or interpolate from one value to another. And so they switch on and off. So example, those are blend modes, display animations, various properties that you can't have values that would solely shift. And currently in most browsers, these will switch on at the beginning of your animation. So might appear glitchy and unexpected but there are a bunch of changes that are coming to discrete property animations in Chrome 116 and 117 where you're able to now add discrete animations to be switching at the 50% point of your easing function during your animation duration. So instead of right at the beginning, they'll sort of try to switch at 50% or ease in line with the rest of your animations. This can kind of help alleviate a little bit of that. And that's for transitions. And then with animations, they're gonna be within the key frame that you're calling them for. When you are applying transitions for discrete animations, you sort of have to turn this mode on with transition behavior. So you have to set transition behavior to allow discrete. So that can be a standalone property or you can use it in the transition shorthand. So you can do something like transform opacity, half a second, display half a second and then allow discrete. You have to have that keyword. If you're thinking about just turning this mode on for transition behavior, you're gonna have to do this after the transition shorthand. Just keep that in mind because it's a specificity issue since the transition shorthand, you could override it if you don't have that little keyword. So just be mindful of this. There are behavior changes coming to discrete properties if you turn them on and you might have like these word glitches if you're not expecting it, if you're applying properties that don't interpolate. So they don't have this ability to smoothly animate from one value to another. Just worth exploring what those values are too. Yeah, so it's like deferred, discrete. I have a question. So by default, discrete values flip immediately regardless of, this is for a transition, not keyframes because keyframes you could delay it but for transitions you can't. And so when you say allow discrete, does it just automatically go to the end? Or it goes to the 50% point of that easing function during the animation duration. So it'll put it on the animation transition timeline instead of at the beginning. Gotcha, thank you. I feel clarity after that. The shorthand thing. Sorry, that was confusing. No, it's cool. Well, you were explaining it. I kind of knew what it was and then that just popped up in my head as like, oh, can I delay it to the middle or is it only gonna delay it to the end? Anyway, so you answered that very nice. And if you are doing this for things like display or for things like visibility, that acts really smoothly, especially when you combine it with other things like opacity or a transform so that you could kind of ease it in and out. You want to combine it with other properties if you are animating display, for example, is in either a transition or an animation. You want to combine those things. Well, that's a really good way to mess with other developers that don't know what this property is. You could animate display but delay it. So they'd click a delete button and be like, hey, it's not gone. And then it goes away and they're like, what? Why is this not, by the way? But it's still in the DOM. Yeah, still in the DOM. It's still in the DOM, hold the DOM. All right, so let's talk about something like debugging. Although wait, I had like a small side thought which is this shorthand thing is getting really annoying in CSS. You know, we're like, this happened with scroll driven animations where you have to list a property after the shorthand or just not use the shorthand at all. And people have been warning against shorthands for years and it's only getting worse. It's like a festering blister inside of CSS. That's gross, sorry. I like shorthands, but we are running into these things where you wanna have global behavior and you wanna expect it to act like other global behaviors. So if you have like a star selector, you might do like box sizing, border box and you put that at the beginning of your whole code base. If you wanted to do like the global selector like star transition behavior allowed to screed or apply global behaviors for retransitions, you don't have to put that at the end of your code base instead of at the beginning so that it overrides all of the shorthands. So that I think we're starting to enter some new territory with global CSS that might not just be at the beginning of your style sheet. It might be at the end of your style sheet. Well, cool. Just some weirdness that we're running into now. It's good. I need to talk about this with someone and you're the person, you're the only nerd I get to chat about this stuff with. So thanks for being there for me. I'm always here for you. I love it. Let's talk about some debugging scenarios. So you got some animation glitches, things aren't going right. And you're like, how do I get out of this? Well, one of the cool things you can turn on is the DevTools FPS meter. It's in the rendering tab. You can also hit Command Shift P on Mac and just type FPS and it'll pop up. And this is a little frame that pops up over your page live and it monitors the frames per second of your animations that are running and the scrolling performance. Like you can scroll your huge page and see the FPS. It's a high performance animation. It will have a high percentage. So the closer to 100% the better. You can also see the actual frame rates on there and see if you're dropping below 60 or dropping below 30 or getting into the 10s of the fives. At which point you should be going, what am I doing wrong? Yeah. You can also do an audit in the performance panel and this can help you identify big layout recalculation which can then tell you to look at the DevTools FPS meter also. But if you are in the performance panel and you see a big purple bar, that means that you have style and layout recalculation or a big green bar might be a re-rasterization if it's not hardware accelerated. So those are just a couple of things to look out for with the performance panel if you're deep bugging buggy animations. Yep, excellent. This next one has saved my bacon numerous times. This is paint flashing. So you open up the rendering tab, you turn on paint flashing and it will show with a red little box that fades out what just got painted. And this is really handy because when your site's at a resting state where you're not scrolling and you're not interacting with it, there should be no paint flashing unless you have an active animation and that's kind of what you can see. So the first off you could be like, hey, what's that red thing flashing up there? And it turns out you had an infinite animation that was set to opacity zero and it's still running, it's still rotating. And you're like, well, that is wasteful and paint flashing can help you discover these things that might be mysteriously running even though you thought you stopped them or something like that. So paint flashing, check that one out, that has saved me a few times. Good call on that one. Another good one that is kind of obscure is show layer borders and the layers panel. So you can find this, I think the easiest way is just Command-Shift-P and search for layer in the little pop-up for DevTools. It's also in the rendering tab, but this lets you see your layer borders. So if you apply will change, you'll see that a new layer is created and that can be why this is helpful for debugging animations or especially 3D animations where you might have multiple layers created that might break your 3D effects. So check that out if you're still not sure why some things are kind of funky, it might be a layer. Might be a layer, yeah, that's how you don't guess it. You can go see layers and that one's also super duper nice. Last debugging tip here is isolation. So just remove all the other crud on your page, reduce the amount of work the browser has to do, isolate your little animation and your effect and see if it's still reproducing the issue. If it is, you've at least eliminated a whole bunch of potential things that can help you understand what you did or just reducing complexity in the page, but the whole app that's there can often add up to a bunch of like combined oddities and reducing it can help you. Or maybe you didn't turn on paint flashing, didn't realize you had multiple animations running infinitely while you're trying to debug this little one that's being crappy. Turns out all your memory's been consumed by invisible animations so it's a good thing to reduce. We need an isolation mode and dev tools. We do, yeah. That's all we have today. So thank you for joining us as we de-glitch your glitchy web animations. Yeah, yeah. And if you have any questions, don't tweet us because we don't love to answer them and if we don't have a hashtag, so send us no questions. If we didn't have a hashtag, what wouldn't it be? Not CSS podcast. So you can find me at the UNA or not at UNA. Yeah, don't find me, Argyle, Inc., ARG, YLE, INK. And your question, no, we do, we love them. It could help a lot of people. Send it over. Yeah, send it over because we are actively recording these so it could get answered on the show. And if you like the show, give us a review on whatever podcast app you're using or share this podcast with a friend or a coworker. Those reviews are how you can give us a high five and help other people find our show, which means that more people will get to learn about this kind of stuff and improve the quality of CSS on the platform. Thanks, y'all. Looking forward to your questions. Yeah, this is the goal. We're here for that. We'll see you. We'll see you next time.