skip to content

Modern CSS: Grid, Aspect Ratio, Container Queries, and More!

CSS has come a *long* way in recent years. In this episode, Stephanie Eckles will show us some of the modern features that have been added & why "centering a div" isn't hard anymore!

Full Transcript

Click to toggle the visibility of the transcript

Captions provided by White Coat Captioning ( Communication Access Realtime Translation (CART) is provided in order to facilitate communication accessibility and may not be a totally verbatim record of the proceedings.

JASON: Hello, everyone, and welcome to another episode of learn with Jason! Today on the show, we have Stephanie Eckles, Stephanie, thank you so much for joining us today, how you doing

STEPHANIE: Doing pretty swell.

JASON: I'm super-excited to have you here today. All right, coming straight out of the gate with a sub. Thank you, Luke, for the sub. Yeah, so, Stephanie, we're going some really exciting stuff today. But before we talk about that, I want to talk about how exciting it is to have you on the show. So, for folks who are not familiar with you and your work, do you want to give us a little bit of a background?

STEPHANIE: Yeah, absolutely. So, CSS is sort of something I seem to have made my umbrella over the past about year and a half. I'm the author of Modern I'm also a full-time software engineer at Microsoft. But CSS is something I found myself enjoying, educating about, articles or videos, egghead, workshops. That's what I'm talking about these days. My other thing is Eleventy, if you're interested in either of those topics, I would love to chat.

JASON: All right. I'm throwing some links in the chat to and Eleventy. Today we are focusing on CSS. Not just CSS, but the new things in CSS. You know what I just realized? Something is missing -- what is it? It's that I forgot to turn on my background lights. Watch, you're gonna see how the magic happens.

STEPHANIE: Got to get the vibe right. Come on, Jason.

JASON: Look at it. Oh, there we go. See? Doesn't this feel better, everyone?


JASON: Okay. So, now that we got the vibe right. So, we're talking about some new features in CSS. And so, here's something that I have learned about myself. I just really prefer writing CSS to any of the other approaches that I have seen. I have -- I picked up -- what were they? It was like glamorous, I picked up Sass and less, emotion, I've tried tailwind. And none of them to me feel as good as just writing straight up CSS. Because it always feels like -- like when I use those other solutions, I always kind of feel like I'm one step away from the thing I'm trying to do. And that makes me feel disconnected from it, right? So, I'm a huge CSS proponent. I think one of the biggest superpowers we can pick up as web Devs is to actually learn and embrace CSS as a language and not try to find ways to engineer around it. Sounds like you are also a kindred spirit in that regard.

STEPHANIE: Yeah, absolutely. It's super-refreshing to hear you say that. And I mean, I came in knowing, you know, very well that you certainly have CSS chops yourself, which is awesome. And I'm looking forward to definitely revealing some of the new stuff that hopefully will get the rest of the folks that are watching this now or later excited.

JASON: Absolutely.

STEPHANIE: And sort of feeling kind of the same way. Because we are getting stuff? Regular CSS, vanilla CSS, whatever you want to call. That will ease some pains and the reasons why this other tooling had been developed.

JASON: Absolutely. And because we're going into something that can be a contentious topic of CSS, chat, I want to remind you all very clearly. We do not trash other libraries here. All right? We can have preferences, we can have opinions. But our opinion cannot be X is trash. Okay? Every tool is good for its use case. And every tool has a set of users that vastly benefit from it. So, we're talking about preferences. These are not objective facts. Do not trash things in the chat. I will kick you out. Thank you.


JASON: So, with that out of the way, I am super-excited to hear what's new in CSS. Because as somebody who likes CSS, I am also very -- okay. This is -- these are two very separate statements. I am someone who likes CSS. Unrelated to that, I am someone who is scared of change. [Laughs] And so, I absolutely never try the bleeding edge stuff. I always wait until somebody else has done the work to test it and work the kinks out and bring it. I don't know what's coming. I would love hear a quick overview what have you've got in mind for today.

STEPHANIE: Yeah, absolutely. So, and I can sympathize with what you were just saying. And I know certainly that your usual audience is used to JavaScript. And definitely a stand out difference for me. And kind of the root of a lot of the frustration people have with CSS is that part. They can't use the new stuff right away. We have to wait for browsers to catch up. Sometimes we can polyfill it, and there's a fall back. And I encourage using progressive enhancements and we will talk about that today. There's not something like Babel that transpiles it like JavaScript. Totally understand the frustration and hear everyone who shares that experience. But I'm hoping, yeah, we can kind of work through that and, you know, everything we do today is gonna be available in your evergreen browsers. And the slight differences we can accomplish patches for in a few extra lines of code. Not much. Nothing is going to be painful, I promise.

JASON: I am -- I am excited. So, let's talk little bit about kind of what some of the benefits of some of these things are. One of the ones that you called out by name are container queries.


JASON: Can we talk a little bit about what those are?

STEPHANIE: Yeah, absolutely. That's definitely the one that's getting kind of the most hype lately. And the reason is that of the upcoming things, that one is actually supported in -- or beginning to get support, I should say. It is behind a flag in Chrome canary. Which means that it's one of the furthest ahead on the standards track as it were. So, the idea of container queries is that instead of our traditional media queries which watch the viewport, container queries allow you to watch a individual element. In effect, its children.

JASON: oooo...

STEPHANIE: As the context changes, you can do the same thing as with media queries, but with the element. Instead of orchestrating the whole page, you're only worried about your single scoped component. Things like font size, changing orientation, grid areas, background colors. Literally any property that you have access to CSS you -- you can do it in a container query. You're just changing that scope from viewport down to the element level. We'll do one example. It's gonna be kind of towards the end of our demo today because we got to build up to that point.

JASON: Sure, sure.


JASON: I'm excited. I have a million questions. But it might be easier to talk about these when we can move things around the screen. Why don't we just -- enough talking! Let's build some stuff. Here we go. Let's go over to pair programming mode. And I'm gonna start first and foremost by giving a shout out to our captioner. We've got Amanda today from White Coat Captioning. Thank you so much, Amanda, for being here. That is right on the home page of Learn with Jason. You can find the live transcript. So, just go over there if you want to follow along. That is made possible through the support of our sponsors, we've got Netlify, Fauna, Hasura, and Auth0 kicking in to make this show more accessible to more people. Which means a lot to me. And while clicking things on the Internet, follow Steph on Twitter with that great leet username. That's a wonderful one. And we talked a little bit about I'll drop a link. And Eleventy, are we using 11ty today?

STEPHANIE: We are. Not much, but we are using it.

JASON: All right. Okay. So, all that being said, what is the first thing that I should do now that I'm ready to start writing some modern CSS?

STEPHANIE: Yeah, absolutely. So, we have a starter repo. It's currently private. It will be available after stream today. Yep. And see if you want to go ahead and clone that down.

JASON: Okay. I did that ahead of time just in case we needed it.


JASON: Let's poke this thing open here.

STEPHANIE: So, this is just an extremely lightweight starting point using Eleventy. The reason we're using Eleventy is because it already includes some nice creature comforts like browser sync and because we are just building a static site today. So --

JASON: So, we don't need to care about anything but this, right?

STEPHANIE: Yep. So, this is a clone of my Eleventy SaaS skeleton. We have SaaS processing available. We're not going to do anything extremely fancy with SaaS. I am going to ask you to create individual files and that will help us keep organized as we build out our styles today.

JASON: Wait. What happened?

STEPHANIE: And here come the boops!

JASON: Eleventy -- oh, I actually need to install all of the dependencies.

STEPHANIE: Yep, normal install.

JASON: What do you mean it's missing? I've seen you, Eleventy! You exist!


JASON: Okay. There we go. Here we go. Let's pop this thing open. And, yep. You want to open things up. And important point here, we are using Chrome Canary today because we had to enable that container for queries flag. So, for folks who have never seen this before, do you want to talk us through kind of like what's happening here? Because this is actually the first time I've ever enabled the flag.

STEPHANIE: Absolutely. Strictly for the portion on container queries, we are using Chrome Canary. Again, that's the only place it's available at current. And so, you'll go to that Chrome//flags. Search for container and you can see at the top, the lists there, we have enabled. The reason we did that is that it required a relaunch to make sure it's working for us. So, that will be all ready when we get to that point.

JASON: Okay. So, you they have --

STEPHANIE: We have that.

JASON: This very straightforward locally running site that has, I believe, all the things we need. Let's...

STEPHANIE: Yes. I was gonna ask you that.

JASON: Hot reload. There it goes.

STEPHANIE: Yes, and that LWJ is throwing it. Yeah, it was doing that to me too.

JASON: Can I tell it not to do this?

STEPHANIE: You can change the text. Change the actual text.

JASON: Page is not in Arabic.

STEPHANIE: It shouldn't do that the rest of the demo.

JASON: Stop it. Never translate this site. Go away. There we go. Okay.

STEPHANIE: Perfect. Cool. Okay. So, we're gonna start out, take some baby steps to get us going and kind of understand how this project is working and then we're gonna go all-in. Anybody that caught my Tweets this morning, I sent out a sneak peek of where we're headed. We're going to build up a dashboard page. It's going to give us an opportunity to cover a lot of modern CSS features and be ready for you to hook in some sort of real database in JavaScript stuff to actually make the data part work. So, that's our plan today.

JASON: I see the chat has discovered the beard.

STEPHANIE: Yes. Perfect. So, the first thing I'm gonna have you do, you're already in your HTML. That's perfect. For folks wondering why we're only seeing an H1 in the chat. This is because I have the Eleventy starter set up where Eleventy used the -- yep. That's where we've tucked away the boilerplate stuff. Yep. That's where it's outputting our content. Just helps us focus in on what we're worried about for today. All right. So, what I would like you to do as a starting point is we want to add a little bit of semantics here to get us going. So, if you wouldn't mind wrapping that H1 in a main tag. And going ahead and giving that a class of container. So, we're gonna kick this off with one of my absolute favorite like introductory modern CSS features.

JASON: Okay.

STEPHANIE: Something that you can use right now and you'll love it. So, in our -- yep, go ahead and go to our style file. If you would go ahead and create our first additional file. Within the SaaS directory, if you would create underscore layout. For those not familiar with SaaS, underscore tells SaaS processer not to compile that as a separate style sheet.

JASON: Oh, okay.

STEPHANIE: And we're just going to use this as organization today. Don't overwhelmed with SaaS. Nothing we're writing with CSS is proprietary SaaS stuff.

JASON: How do I do this?

STEPHANIE: Yep, at the top of the file.

JASON: Top of the file.

STEPHANIE: It has to be at the top just due to the rules of SaaS. @use, and then parentheses layout -- excuse me. I don't know why I said parentheses. I'm in JavaScript land. Within quotes.

JASON: Like this?

STEPHANIE: Yes. Perfect.

JASON: Now, if I go back into this one, we created that container class, and I do a border 1px solid red which is my favorite way to debug anything. That should be working. Do I need to restart Eleventy to pick up the change.

STEPHANIE: Yes -- yes. It should quote, unquote just work. Did you get an error when we did the install? All that's installing is Eleventy and then SaaS. The main SaaS library.

JASON: File changed. Did the thing. File changed. Maybe I need to --

STEPHANIE: Of course we're gonna hit a bug at the first step.

JASON: What's a comment in SaaS?

STEPHANIE: Let's do a rerun of Eleventy just with the npm start. Just to make sure.

JASON: Okay. It's also possible they typo'd this. Let me just really quickly double check. Container and then I go out here. Container. Okay. I did that part. So, let's stop and restart it.

STEPHANIE: Yeah. Because I'm also not seeing the other -- the base stylesheet applied since that's a serif font.

JASON: Oh, interesting. I wonder if something is going more wrong here. CSS style.css.

STEPHANIE: Let's make sure that exists in your public directory.

JASON: Oh, you know what it is? I'm running Netlify Dev and I bet that it's -- oh. Okay. Hold on.

STEPHANIE: Just start.

JASON: We can figure this out.

STEPHANIE: Just use the start command.

JASON: That's why. I was running a shortcut and it didn't know to use your -- your command. So, that's -- that's on me.

STEPHANIE: So, it should be 8080 instead of -- yeah.

JASON: Okay. Here we go.

STEPHANIE: I have done that as well.

JASON: Ta-da!

STEPHANIE: Perfect. Isn't it beautiful?

JASON: Lovely.

STEPHANIE: Yeah. You know what? I'll have you actually leave on the outline, or the border. I was going to have you add an outline so we can see what's happening.

JASON: Oh, an outline. That's also a good call. Because an outline -- outlines don't occupy any space, right? It doesn't change the layout at all.

STEPHANIE: Right. It doesn't add to the dimensions of our element, similar to block shadows. Cool. So, all right. So, let's actually make this do something more exciting than have a border. We're probably losing people. Classic debugging. You know? Had to happen there. All right. So, if you would go ahead and add a width property to our container.

JASON: Okay.

STEPHANIE: And now normally you would probably set this up to something sort of precise or percentages or something like that. Instead, so, here's our first little nugget, we are going to use the min function. You're going to type min and this type you're really going to type, yes, parentheses. The min function. There's also max. You can give it an array of values. You can actually give it more than two. We're gonna give it two.

JASON: Interesting, okay.

STEPHANIE: And based on the computed size of the width of the element, it's going to select the minimum value. So, it will change as the component changes size in this case.

JASON: And so, like in a -- in a silly comparison here, if we do this as 100 pixels, 300 pixels, the computed size is going to be 100, right?

STEPHANIE: That's correct.

JASON: We can go in and you can see that it's 100. This is not particularly useful because we can immediately determine that. But when is a case when this is useful? Or I should let you continue with the example instead of jumping ahead of you.

STEPHANIE: Yeah. So, our goal is to -- so, it's a little bit confusing is that we typically use the min function to actually set a maximum allowed value. And so, we'll see what that means. So, the first value we're going to pass it is 100ch. Ch is the character unit. It's going to be roughly equivalent to the width of the zero character in your computed font size at that point.

JASON: Okay.

STEPHANIE: Since this is, you know, at the root of our element, it's going to compute back up to the unit, 1 rem as a default or 16 pixels. So, the second value we're gonna pass. That's gonna essentially make it a max width of 100ch. And then as our component shrinks down, we don't want to have overflow. So, we are going to do 100% minus 2rem.

JASON: Do I need to wrap that in a calc or anything?

STEPHANIE: No, we can do math directly within min, max and clamp.

JASON: No way!

STEPHANIE: With the CSS function. Yes.

JASON: Okay. So, here's the 100 characters. But as I make it smaller, it won't go over 100% minus 2rem.


JASON: That is awesome.

STEPHANIE: So, to finish off our container class typically, typical behavior we want for this is for it to be centered. So, I'm gonna introduce one other modern CSS thing for you here. We're gonna use logical properties. So, instead of setting margin left and right, I'm gonna have you set margin/inline. And --

JASON: What?

STEPHANIE: And I know a few weeks ago this was brought up in the discussion of the right to left languages.

JASON: I'll tell you what, I was so overwhelmed by the right to left episode, this part didn't try to stick in my brain. Fell out the other ear.

STEPHANIE: Completely fair. So, the idea of logical properties, the super 5-second overview is that they will intelligently, based on the browser heuristics and whether right to left or left to right languages are set, they will essentially flip orientation, for example. So, we've got inline, inline start, block, block start, et cetera. So, block is going to be your traditional top and bottom and inline is going to be your traditional left and right.

JASON: And, what this is doing is instead of using like a highly specific language of left and right and top and bottom, we're saying, like, inline are whatever would be considered the, like, space between characters in the flow. And block would be, like, the spacing between blocks of text which we think of as like the top and bottom.


JASON: But if we -- so, does that mean that if we change like the -- if we use play flex and change the top and bottom, would that did --

STEPHANIE: If you change the language orientation.

JASON: Serve subscribing. Oh, wow, we got a gift. Okay. Okay. Thank you all -- Todd, thank you for the sub. Happy B, Peruvianidol, thank you for gifting all those subs. Y'all should now have a huge amount of boop potential. Did I see the boops aren't working? Do I need to reload? I saw a question from Red Hat Ranger, am I the front end masters guy? I am one -- I have taught front end masters. Ben, here we go. We are all over the place. We just hit level 3 -- oh, Todd. Todd, what is happening? Oh, my gosh. Everybody, thank you so much for all of these sub GIFs. You are all the best. Make sure you Spam the heck out of that boop now that you have one. It looks like the boops did break. So, let's reload -- let's reload the overlay so that everybody can do those boops.

STEPHANIE: Wouldn't want to miss the boops.

JASON: They are. Try some boops, y'all. Try some boops. There we go.

STEPHANIE: Excellent.

JASON: Oh, my goodness, so many subs all at once. I appreciate you all. Thank you all very much. Okay. Now, everybody settle down, we're trying to learn CSS.

STEPHANIE: Yes, and if you joined more recently, we're going to do something way cooler than outline a box and size it. Stick with us. We're just getting our feet wet here.

JASON: I think this is the closest I have been to completing a hype train. The only time I completed a hype train is when we did it on Cassidy's chat. Thank you for the sub, appreciate it. What does that mean? 17% for B1 mine subbing. That means we need four or five more subs to hit the level 5. I think that's it. Who wants to be the one? Finish the hype train. Dingleweenie, what a name.

STEPHANIE: Beggars can't be choosers, Jason.

JASON: Oh, I love it. All right, all right, all right. Let's -- let's keep going here. So, we're at margin-inline.

STEPHANIE: Let's go, yes. We got a lot to get through in an hour.

JASON: Thank you Todd! Oh, boy. What a great -- what a great show. This is a great show. Oh, and then Taylor's out here gifting. Thank you all so much. Todd, I think you just set the record for most-gifted subs in a show. So, thank you very much for that. And we are now at 173% of the hype train. And I think we'll never be free of this noise ever again.


JASON: Thank you all so, so much. Oh, my goodness. We're still going. Holy crap.

STEPHANIE: Y'all are amazing. But I would like to show you some CSS.

JASON: I know, jeez. Okay. I'm actually -- I'm gonna -- I'm gonna turn off the stream lapse thing because it's so noisy. Thank you all so, so much for the subs. I appreciate you. You are the best. Let's get back to some CSS.

STEPHANIE: Okay. Okay. So, I wanted to real quick mention, oh, I guess we need to finish this rule. Margin-inline. You're going to say auto. That's going to set both our left and right. Excellent.

JASON: My life just got so much easier.

STEPHANIE: Yeah. So, okay. So, one thing about logical properties is there's a little discrepancy right at this very moment between their support.

JASON: Okay.

STEPHANIE: The good news is that two things. There's a post-CSS plugin which I actually have as part of this package. Once we do like the final build, what it's going to do, it's going to find margin-inline. It's going to know based on our browsers list that we would like to back fill that.

JASON: Okay.

STEPHANIE: The holdout is Safari. Once Safari 15 drops, I'm fairly certain, I looked this up, this should be across our evergreen browsers. That will take time.


STEPHANIE: But this will change to margin right and left a auto. You can write this now and have it do the processing after. It's just going to add two more properties. And so, you know, this is another thing where we can use it as a progressive enhancement. Makes our writing a little bit easier and it's a good habit to get into. This is a small thing we can do to future-proof what we're building.

JASON: Yeah. Okay.

STEPHANIE: So, yeah! All right. So, let's do something more exciting. Oh, one other thing I wanted to mention terms of support. I would highly recommend the VSCode extension webhint. It's going to look at your browsers list and give you a little extra squiggly line and let you know when it identifies stuff that may not be supported based on your -- what you've said you would like to support through your browsers list.

JASON: Nice. Got it.

STEPHANIE: Might not restart, but it will throw a yellow squiggly on that margin line.

JASON: Okay. Let's do it. I'm reopening... what the heck is code meter? I don't know -- I've now installed so much crap that I have literally no idea what's going on. See, that one goes away. And we'll keep this one. And extensions have been modified? Yeah, I know. Let's not do copilot today. Oh, my goodness. We got the level 5 hype train emote and it's a corgi doodle! Did y'all get this one? Because that is a good one. Oh, that's a -- that is a really good one. I'm very happy about that.

STEPHANIE: We can ignore it for now. I wanted to mention it's really helpful with CSS properties. I think it works with some non-vanilla. But I have not personally tested that. It's made by folks from the Edge team and other collaborators. I believe it's open source and actually used in Edge browser. You'll see a newer pane that was added recently. It will tell you similar things.

JASON: Nice.

STEPHANIE: I want to cover our support basis since that's a big question that comes up with this topic.

JASON: Yeah.

STEPHANIE: Let's do something a little bit more exciting. While we're on our container, we want to make this more flexible. We're going to start to introduce some custom properties. At the top of our container rule, we're going to do three of them. The first container-width. So, dash, dash to start indicating our custom property.

JASON: Cool. I forget that's the official name. I always call them CSS variables because that's -- that's the world I live in now, I guess.

STEPHANIE: Yes, I try to say both. I've trained myself to do the other. My apologies, yes. Same thing. We're going to set that as our default of 100ch. And you can go ahead and swap that out in our width rule. So, you'll do var, the var function and then the full name. Yep. VSCode is very helpful there.

JASON: Very helpful.

STEPHANIE: And the second one, second custom property we're gonna call container-gutter. Yep. And we're gonna set that to our 2rem. I'm calling it gutter, it's not margin, it's not padding. It's that little kiss of extra space in there.

JASON: Just like -- [Kissing noise]

STEPHANIE: Rather than having to create a whole bunch of utility styles we can do it on the fly. You could still end up creating utility classes. For example so, I come from advertising, marketing background. And design systems as well. So, I'm very used to the idea of being handed, you know, very precise measurements, right? We're gonna talk about a few ways we want to get away from that today or try to encourage folks to get away from it. This is one of the ways where, you know, falling back on rem, falling back on ch, these different kinds of again, future-friendly units that are going to allow our interfaces to be responsive. And we're still gonna get a really nice, pleasant result at the end. But we're just trying to identify those opportunities. So, yep, you got that there. The last thing we're gonna do, just one extra little thing to make sour container more flexible is add first a custom property of container-padding.

JASON: Container-padding?


JASON: Okay.

STEPHANIE: And we're gonna default this to 1rem. We need to add this as a new property. Just like our margin inline, now we're going to set padding-block.

JASON: Padding-block.

STEPHANIE: We're going to set top and bottom. The reason we're not doing all four sides, the gutter is doing the work of essentially acting like padding because of the way it's being subtracted from the 100% value.

JASON: Okay.


JASON: Oh, I see. Should I get rid of the border, then?

STEPHANIE: What's that? Oh, yes. That would be fine to do now, yep. And if you want, you can flip over and kind of resize.

JASON: Look how nice that looks. Ta-da!

STEPHANIE: So, there it gets to 100ch.

JASON: Yeah, looking good.

STEPHANIE: Perfect. Okay. So, the next thing we want to do, if you would please go out to the base repo and over to the final branch we're going to copy in at this point. So, we have nothing -- we are truly from scratch, folks in the chat. We are truly from scratch. There is no theme happening here that's special or unique beyond what we have already shown you on screen. What we want to do is go into the SaaS file actually.

JASON: SaaS file, SaaS.

STEPHANIE: Or directory. And we want to copy the reset. And we can really, really briefly discuss what's in there.

JASON: Okay. So, let me make a reset.

STEPHANIE: Yes, sorry. Important first step. So, the concept of a reset is to add our own defaults to reset the inherited browser ones. And these have super-evolved over the years as browsers have evolved. This is a derivative of Andy Bell's CSS reset, I have it linked at the top there. I've taken out a bunch of stuff that we're not going to use in this particular demo. But that's the one I like to point folks to. I have a few extra things in here. So, we'll just briefly will say, you know, we're resetting our box sizing, border box. That means that padding and border will not be part of the element's computed size. We're resetting a handful of things to margin zero so we can manage the spacing our own custom way. And then we are setting our body min-height to heights, and some things I like to personally reset. Go ahead and reset the base font family here. So, not too much going on. But it's going to already give us a little bit, you know, some nicer things going on.

JASON: Great. Okay. So, I've got it.

STEPHANIE: And then we will... let's see...

JASON: And I can see now the default margin from this H1 is now gone.

STEPHANIE: Yeah. And the other thing we can do with that said is if you go to the main style file, we just had that one rule in there, we can now remove it.

JASON: Good-bye!

STEPHANIE: Yep. Since we have done that in the reset now. Cool. So, the next thing we're going to do before we get into the main meat of the business is we're going to add -- I call it a theme file, brand file, whatever you want. We're going to define some colors.

JASON: Okay.

STEPHANIE: So, if you go ahead and create a theme file. And so, I am not a designer. I have learned tricks to make my stuff not look terrible. But I'm not a designer. So, I'm gonna share one of my favorite ones to create our theme file here. So, we're going to, if you want to go ahead and open up a rule for the root property. So, the root is essentially also means the HTML element. And the reason we're assigning some properties here, we're gonna assign a whole bunch of custom properties, is that we intend to use them globally. So, we want them to be defined at the highest level of our application. And so, we are going to build ourselves out a little color system.

JASON: Let's do it!

STEPHANIE: Our color system on HSL. Which is hue, saturation, lightness. And I'm calling it theme for a particular reason which is that the first value we're going to define is our color-primary-hue. And we're gonna give it a starting hue of 260. What's gonna happen is the way we develop the rest of our colors is we can come in here, change the hue and re-theme our app and just like that. With a different color.

JASON: Sneaky! This is a good idea.

STEPHANIE: The caveat here, and we'll talk about it more, that's my other thing, I definitely try to advocate for accessibility as much as possible and throughout my teaching is that that's a really cool feature to have. That it re-themes it. You will then have to make sure that you course correct for any contrast that gets lost in that process.

JASON: Yeah, when you start messing with colors, you've got to check your contrast and all that stuff.

STEPHANIE: I'm not using it today, but I should mention, CSS is also getting a color contrast function. Which means we will be able to upgrade the solution we're implementing today maybe by next year sometime to -- it will take an array of values and it will choose the one, like if you pass it white and black just as a starting point, it will pick the appropriate one that has the contrast.

JASON: Excellent. Excellent. I love it.

STEPHANIE: Okay. So, let's actually do our colors. I'll probably have you -- we'll talk about the first one and then I might have you go copy/paste to save us some time.

JASON: Sure, sure.

STEPHANIE: We've got the hue. Now we're going to define the initial color for this. So, color-primary. And then hsl. So, we can actually pass in that hue as our variable. Yep. And then we just have to define saturation and lightness. You can go all out on this and you can have separate properties for the saturation and lightness as well. I've just essentially locked down this particular example. We didn't need that complexity here.

JASON: Sure.

STEPHANIE: So, our saturation is going to be 85%. And our lightness is gonna be 60%. I'm not sure if you can -- can you get away with no commas? I think it's a little bit iffy.

JASON: I think you can because if we wanted to do opacity, we could do like that whole thing, right? It's --

STEPHANIE: Yeah, I'm not sure it's quite cross-browser --

JASON: I think with CSS it should work, right?

STEPHANIE: Potentially. I didn't test it, that's why I'm hesitant.

JASON: If you tested it this way, let's do it this way.

STEPHANIE: Yes, I'm hesitant. If you wanted to really quickly test that, you could go back -- you could go right below since we're just testing. And assign our color primary to change the color of our H1 if you just wanted to test that out super-quick. Yep. So, the var of color-primary.

JASON: Ah! Oh, I have to actually include it.

STEPHANIE: Oh, yes. Let's do it. Yep. Exactly.

JASON: Ta-da! And then if we change this to a different... and you can immediately see the contrast problem.

STEPHANIE: Yes, exactly. So, our 220 to 320 is a really safe range for what we're doing today. Our blues, purply, dark magenta, essentially. 260 just happens to be my favorite spot.

JASON: Yeah, this is a good -- that's great.

STEPHANIE: I will go ahead and have you jump over to our final because we definitely need to --

JASON: Keep on trucking. Yeah, let's do it.

STEPHANIE: We won't do the whole file. Just get the top part. Just get the rest of those values.

JASON: Okay.

STEPHANIE: So, we've just filled this out with a color light. And then we've defined our text, a couple shades of gray and our body background. You can see those are all operating off of our primary hue. It's nice for the grays to give a hint of color to make it feel cohesive. It is not super-perceptible unless it's not done that way. Then you feel that coldness in your gray. That's my non-designer designer trick. Okay. That's all the colors we need for this particular app, at least as a starting point. Let's do something. Let's -- the last thing that sort of is theme-related is if you go to -- back in our Eleventy files, if you go to our base. Includes base. I've just added a Google font in there. So, that's already been done. So, we want to create our typography SaaS file.

JASON: Okay.

STEPHANIE: And we'll just get that assigned out.

STEPHANIE: So, we are keeping our SaaS organization for anybody that may be a little picky for anything happening today. We're keeping it super-light. I don't want to get bogged down in details. Definitely in a more expansive project, I would have sub directories and so forth for some of these things. Yep, go ahead and copy it. That's fine.

JASON: Do you want to talk a little bit about this is is.

STEPHANIE: We will. Is one of our newer selectors. I forgot to grab the link, but I have a Smashing article covering some of the newer selectors. We have IS and we have -- I can't remember what it's called. I can find it a little later too. Yeah, we have is, we have where. And this allows you to pass an array of -- I think it's something about selectors. So, yeah.

JASON: Here?

STEPHANIE: Yeah, that one.

JASON: Okay.

STEPHANIE: We get to pass an array. I picked it out for typography. Not because it's super-useful for exactly what I'm showing it, but just to make sure to mention it because it is incredibly useful. Where it becomes more -- so, yep. So, it's not offering us any more benefit in this exact example other than, you know, listing them out separately. Where it's more official is when you have more complex selector and nested selectors. And one important thing to note for is, is that it has the specificity of the highest specific item in the list. So, if we had an ID in here, it would have the specificity of the ID.

JASON: For the whole set.

STEPHANIE: Yes. There's a complementary selector of where. And where means zero specificity no matter what until you start combining it with other selectors. It's here not because it's super-useful in this example, but because I definitely wanted to mention it because it has a lot of use cases I'm excited about.

JASON: Gotcha. We can see here --

STEPHANIE: Yep. It's applying it. Nothing -- you can see our block end which we'll use. We haven't actually had that on the page yet. That's coming. In fact, we are finally ready to make our example much more exciting. We're going to have to really rip through the rest of this stuff. So, if you go back to our base project, you can copy the whole index at this point.

JASON: Okay. So, we're going back to here. We're going to the index.HTML.


JASON: And this is markup. So, let's see. This is gonna be statistics. And we've got article cards that are going to have our like various scores. Here are some details. Okay. This all makes sense. So, we're basically --s in a reporting dashboard.


JASON: Okay. That all makes sense to me.


JASON: So, let's pop on in here and look at this.

STEPHANIE: It's inspired by like the screen time idea that for an iOS user that you get.

JASON: Yeah.

STEPHANIE: Okay. So, we have just got some -- yep. I see HTML there. Let's start to give it some of our colors that we've defined. If you go back to our theme. We are... because we forgot to do this part. Let's go ahead and copy-paste to save some time. We go to our theme file. What we're gonna do is we're gonna use those custom properties -- yep. And then the theme. And don't get the middle bit there. Get the class -- the body in the classes at the bottom. Yep.

JASON: Okay.

STEPHANIE: So, we're using our custom properties just to create a few utility tiles. I'm a fan of utility styles when it makes sense. This is literally repeatable stuff. You want these backgrounds available. There we have an improvement on our app already. Okay. So, the -- I'm scrolling down my notes. I got a little out of order there. Let's go ahead and we'll really quickly -- let's see. Did we create a -- yes. We have a layout file. It's just got our container in it right now.

JASON: Yeah. And I'm just pointing out here that like these classes, background, gray light. And up here, we've got background-primary. There's no magic here. What we're doing is really straightforward stuff. Utility classes. Just like you would expect if you were using something like tailwind, this would be like bg colon something, something. So, there's no real difference in what's happening, right? We're just using a theme of our own device.

STEPHANIE: Yep. We're being, you know, we're being selective ahead of time. The old fashioned way. Yep. So, now in our layout file, we are going to kind of go top down a little bit here. We're gonna style our header. So, specifically the header container since we -- that, like, avatar and H1 is nested in a container element.

JASON: yes. So, the header container. Right? Am I just doing like header container like this?


JASON: Okay.

STEPHANIE: Again, more to just not go down the rabbit trail of talking about naming methodologies. So, we're just gonna use good old selectors today.

JASON: Right.

STEPHANIE: Just all we're doing is a display flex, center align, and a gap of 1rem. That's all. Caps and flex --

JASON: Align-items: Center. And a gap of how much?

STEPHANIE: Just 1rem. Lovely.

JASON: Okay. So, this I think here is maybe one of my -- like the most powerful things that I've learned in CSS recently. This has been in for years. The flex properties are not new. But the ability to just do this without having to do a bunch of floats and things like -- I haven't used a float in CSS in years at this point. Because of how powerful these are.

STEPHANIE: Yes. So, the next thing we're going to do, if you notice, our little footer there is not at the bottom because we don't have enough content. So, it just so happens that this problem is what prompted me to start in the first place.

JASON: Okay.

STEPHANIE: Because I had used a technique for absolutely years and it involved just hacks on hacks, right? To make happen. And now we can do it so much easier. So, on our body --

JASON: On our body.

STEPHANIE: Yep. Let's -- we're gonna set the whole darn body as display: Grid.

JASON: Display: Grid, all right.

STEPHANIE: And then we're gonna set up grid-template-rows.

JASON: Okay.

STEPHANIE: Of auto -- oh, no commas for template rows. Just spaces.

JASON: That's right. That's right.

STEPHANIE: 1fr and auto. So, let's inspect that and see what's happening over in the browser.

JASON: Okay. Let me -- let me make this a little bit bigger so we can see.

STEPHANIE: All browsers -- while you're doing that -- all browsers have pretty nice grid tools at this point. If you go to your body and click the little grid pill, whatever you want to call it --

JASON: Look at it!

STEPHANIE: It reveals your grid. What's happening is we know we have three elements at the body, the header, the footer. We have made columns to correspond. And 1fr is a fractional unit, one of the special grid units and it basically says, if we used it more than one time, it would divide any remaining space that doesn't have a more exact value between those frs. Since we only have one, it's basically saying take up absolutely all the extra space besides what's already used by our header and footer. Which we set to auto. We set to auto because that means that those can still grow and we're not putting a limit on them.

JASON: Right.

STEPHANIE: But it also means to shrink to their boundaries.

JASON: This is -- I actually hadn't seen this grid button before. This alone, holy crap, y'all. How useful is that?

STEPHANIE: I am not a fan of counting grid items. And in fact, it kept me away from grid for several years. So, everything I teach for grid, we almost -- I can think of one time that I teach something that we have to like really care about numbers on grid.

JASON: Yeah.

STEPHANIE: If that has been your experience as well, anybody, I'm here to give you some other techniques that will still work for you that are awesome with grid. Cool.

JASON: Yeah.

STEPHANIE: Okay. So, we've got a good -- pretty good starting point. And this is readable. We've already got a readable little thing. It can be improved, absolutely. But it's readable. You know, it's branded. We've got a good start. Okay. We've pushed our footer to the bottom. The next thing we want to do is -- so, this is essentially kind of our mobile view.

JASON: Right.

STEPHANIE: This is great for mobile. So, the next thing we want to do is actually define -- so, we've already set body to grid. We want to use grid then to rearrange our screen for our larger viewports. And so, if you -- this is like the one time we're gonna use a real media query.

JASON: Okay.

STEPHANIE: And again, I might switch this in the future when we have better support. So, @media, min-width of 100ch. We can actually use that handy ch feature for our media queries. And then on the body --

JASON: Oh, so --

STEPHANIE: We're going to set grid template areas. And we're going to use -- I mentioned we're not gonna count any numbers here. So, we're gonna use named grid-template-areas.

JASON: Okay.

STEPHANIE: So, we're going end up with two rows and two columns. Now, for every grouping of row values, we put them in quoted strings. And so, our first quoted --

JASON: Okay.

STEPHANIE: Array is gonna be header for the first column and main for the second column. So, it's just a space between. And then after that ending quote, just a space, and open up another quoted array. So, no commas anywhere here. And then repeat header. And for the first column. And then footer for the second column.

JASON: Oh... interesting. Okay.


JASON: I thought I needed to do these differently. I was getting ready to do some -- I was getting ready to do some ASCII art over here.

STEPHANIE: Not this time. Sometimes. But not this time. So, the next thing we want to do is we want to actually set up what type of space should those take up? Now, what I'm showing you is what I believe is the more clear way to understand what's happening. There are other ways that we could be assigning the same thing. And again, that's something that kept me from grid. So, I'm trying to introduce the way that I think makes a little more sense and is a little more approachable if you're just trying to use grid and some of these features. So, we want to -- we've got our named areas. And now we want to assign their spacing rules. So, go to grid-template-columns as our next property. And the first column --

JASON: Oh! Okay.

STEPHANIE: The first column, which is going to end up containing our header because it's gonna be a sidebar, basically. We're gonna use the grid function. Sometimes this is used a different way, but within grid, it's a function --

JASON: What?

STEPHANIE: For fit-content.

JASON: Like that?

STEPHANIE: The function is called fit-content. Sorry.

JASON: So, fit-content, like that?

STEPHANIE: Yes and we're going give that a value of 25cl.

JASON: 25ch.

STEPHANIE: As a function within grid with this is magical because 25ch basically says this is the maximum that you can grow to. But if our content happens to be smaller than that, it will only grow to the space it needs. Which is really nice. And then 1fr for our second column which is gonna be like our main dashboard area.

JASON: Okay.

STEPHANIE: And then need to assign our rows, so, new template grid, rows. We just have two of those in this larger view. We have 1fr which will again represent the main dashboard area. And then auto which will become the footer area.

JASON: Okay.

STEPHANIE: So, if you save, something interesting is going to happen. You will have to expand out your window to meet our media query. So, these are getting assigned just auto placement according to DOM order. So, it's got us almost there, right?

JASON: Right. Almost. You hackers, you -- you dirty hackers.

STEPHANIE: But we want to be more specific about it. What we want to do, so, for our header as a new rule within our media query. So, header, we're going give that a grid-area of header. This time there's no quotes, which is a little confusing. Yep. And same idea for our footer. And the DOM order takes care of our main element.

JASON: Look at it go!

STEPHANIE: So, if you resize it down to mobile, you know, like I said, mobile we're just like DOM order is fine. No big deal.

JASON: Da, da, da! Look at this. This is amazing. We wrote very little code.


JASON: To completely rearrange this -- these boxes. And like I remember trying to do this stuff with other approaches. And like I know why a lot of people have this bad taste in their mouth about CSS. And it's because they -- they learned CSS before these options were there. Right? And now that we have grid and Flexbox and things like this, like a lot of those things that people complain about in CSS, they just don't exist anymore.


JASON: This is --s in so pleasant to work with.

STEPHANIE: Yes, and if you expand, we have container on the main. If you do wide screen on it.

JASON: Oh, yeah, that's right.

STEPHANIE: You'll eventually hit the point where it -- maybe hit zoom out.

JASON: Yeah, I got to zoom out a little bit -- I'm on a very small browser.

STEPHANIE: But you see the container taking hold then.

JASON: Yeah. It starts to center. We get the -- this is the maximum size. This is about here-ish.


JASON: These are our margins. It's doing really powerful stuff. This is really, really powerful stuff.

STEPHANIE: Yes. I come from bootstrap, almost the beginning of bootstrap. It's being replaced. Think of the utility classes you would do and pull your hair out because I have been there to make this happen. And maybe not even quite get to do it without also adjusting your DOM, right? So, anyway. I love -- I love that very much. Grid-template-areas are the bomb. Okay. So, I definitely like want to get to the cooler, more dramatically visual stuff. So, let's -- let's go ahead -- we need to add one little rule. You see how our summary is kind of bumping up in there. Let's add -- I'm trying to remember where that is. So, above our media query, we're going to have -- so, after the first body rule and above the media query. We're gonna add a new rule for main. And we're gonna -- yep. We're gonna go ahead and nest it because we technically have SaaS available and we're going to add something in a bit. If you do the direct child selector. Yes, it's going to be the carety thing. And universal selector, an asterisk.

JASON: This always looks like somebody giving you the eye, like...

STEPHANIE: Yep. And before we open our rule, plus another asterisk. This is saying what it's gonna attach a rule to is direct children that follow another child.

JASON: This is what I lovingly have heard referred to as the lobotomized owl selector.


JASON: This is I think a Heydon Pickering special

STEPHANIE: Yes. It is. And use the logical properties again. Practice those. Margin-block Start. AKA, margin-top. We used min earlier, we're gonna use max this time. Max function.

JASON: Okay. To the max!

STEPHANIE: To the max! We're gonna give it the options of 4rem. Comma.

JASON: I always forget which is which.

STEPHANIE: And 8vh, which stands for view eight. We're going to tell it to do a little bit of dynamic business depending how much space we have available.

JASON: Do that -- do that business, CSS!


JASON: No, this is great. This is great.

STEPHANIE: Yes. And just as a complement because on our wide screen it's a little snuggly.

JASON: Behold! My bucket!

STEPHANIE: It's a little snuggly at the top there for our first headline in there. So, just in our -- within our media query that we had down there, we're just gonna bump up the top of main. We don't have a rule for it yet. So, just create a rule for main and we're going to give it a margin-block-start of 3vh. So, I sympathize with anybody, I don't see anybody talking about it today. But usually I get asked, how do you talk to designers about this? And my answer is, show them a demo. That's how we get buy off and I strongly recommend going ahead and experimenting with that. Like I have said it a few times. If you have joined us more recently. We're trying to create rules that are future-friendly and don't care what kind of device you have and what size it is. So, that's why we're trying to move towards view heights and CH. Take advantage of grid and so forth.

JASON: Right, right, right. No pixel perfection here. We're going for something that actually fits the modern use case which is where I'm dragging my window all over hell and it needs to look good in all of these sizes.

STEPHANIE: Yes. So, we are super running short on time. Let's go to -- so, we're gonna create our -- the main content here is gonna end up being like a card-type of layout. So, let's go ahead and create our card file. We're ready to move on to that. And -- or, excuse me. I forgot. We need to -- that's okay. We'll obviously leave it there. But the first thing is, if you would mind going in your browser. Because I want to make sure folks have a reference for this next trick because it's my absolute favorite of all the tricks I know.

JASON: Ooo... okay.

STEPHANIE: Go to my site, We're gonna copy the first demo that's gonna come up there.

JASON: Here?

STEPHANIE: So, that small responsive grid, we're gonna copy the code for that one. Just the guts of it.

JASON: Just the guts.


JASON: Got it.

STEPHANIE: Okay. So, in our layout file, we're gonna create a class for layout-grid. And that can go after our container. The like main container rule.

JASON: After the main --

STEPHANIE: Just to keep our utilities together.

JASON: Layout-grid?

STEPHANIE: Yes. You can pop that rule in there.

JASON: Okay.

STEPHANIE: And we'll actually let it -- we won't make any changes. If you want to go back to our demo, though.

JASON: Ooo! Look at it go! So, now if I make this smaller -- da, da, da! There it goes! It's going! It's doing it! You're doing it, Peter! Okay. This is great.

STEPHANIE: Awesome. Favorite trick of all time.

JASON: That is really useful.

STEPHANIE: When we talk about, you know, we obviously already showed, there's still a place for media queries, but it is less. Less of an -- so, the only change I want to make here is bump up the min to 25ch. So, the default value for our minimum. We are short on time. Go out to smolcss if you want more explanation on what is happening here. Because we want to get some styles applied to these cards.

JASON: Let's do it.

STEPHANIE: Okay. So, now we're actually ready for our cards. We're gonna style the summary cards first.

JASON: Okay.

STEPHANIE: And so, let's go out to our final. Let's copy and paste a little bit of this. Since we're only down to like 20, 25 minutes or so.

JASON: We sure are. Okay. I'm gonna go into cards.

STEPHANIE: So, copy that -- like the opening for card throughs it own styles. So, just our essential styles -- not quite that far.

JASON: Oh, like here?

STEPHANIE: Yeah. Just until it opens that second rule. And you can close that off. Yep. So, that's just gonna give us our essential -- they look like cards now, right?

JASON: Just some basics. We have some border radius year, a little bit of drop shadow, nothing ground breaking here. Looks good.

STEPHANIE: Nope, nope, nope. So, now -- so, that's our generic card class. You can see it's been applied to every element on the page, everything's a card. Jason, up to you if you want to nest down. If I'm in SaaS, I like to do the ampersand nesting trick. You can open a new rule if you would like, but we want to do card dash, dash stats.

JASON: Let's do it like this to make it able to be copied out to a non-SaaS setup.

STEPHANIE: Okay. Here's our first bit of magic. We are going to set aspect-ratio to 1. And sorry chat, normally I would be paying attention. But you want I want you to see the cool stuff.

JASON: Look at it go. Okay. Hold up! Hold up. So, we just made that square.

STEPHANIE: Sure did.

JASON: Now, wait if I -- what if I want it look like movie? Shut up, get out. Get out. Ah! Behold! My bucket! That's so good. Magic, magic.

STEPHANIE: So, slight dampener.


STEPHANIE: Safari 15 is behind. It's coming. The good thing is we can put a progressive enhancement on this. I would like a square. Do a sensible fallback. It's not going to hurt, I promise. Under that, well, you could again, nesting or not. So, if you don't want to do under, we can create a new rule. But we're gonna do an @support query on this. And we're gonna actually do @supports not. So, we're gonna do like a reverse on this.

JASON: We're gonna neg CSS.

STEPHANIE: Yeah, I don't describe that well. It's actually @supports and then the additional keyword of "Not." So, before your parentheses.

JASON: What?

STEPHANIE: Yeah. And just -- just the word. So, not like a selector.

JASON: Just the word -- just the word?


JASON: I have never seen this before. That's magic. Okay.

STEPHANIE: We also need to define aspect ratio and the value because it's checking --

JASON: Oh, I understand. So, we're basically saying, like if you can't compute this --


JASON: I got it. Okay.

STEPHANIE: So, in this case, just for other folks' reference, for this particular one, it doesn't matter what the value is, but exactly what you said, can you do anything with this at all? And we're just gonna set a height here, the width is taken care of because of the grid. We're going to set a sensible default on our height. We're gonna use our max function. Yeah, we can do 25ch. That's a little small. This takes a little trial and error testing. Sorry, 25vh.

JASON: Oh, vh, got it.

STEPHANIE: Just from my own testing of this, 15rem was decent for what we're trying to do here.

JASON: This will make it like mostly work.

STEPHANIE: Yes. Firefox, Chrome, Edge. Where this is gonna kick in and have the most impact currently is iOS since they all use Safari. We won't get into that. Okay. So, cool. We've got cards, we've got our aspect ratio taken care of. Now I think I'm gonna have you -- well, okay, never mind. So, on our primary rule there for card stats, let's keep going.

JASON: Let's go!

STEPHANIE: Continue on here. We want to set grid-template-rows, sorry, display: Grid. Pro tip: Define the display first. And then grid-template-rows of 1fr and auto.

JASON: Okay. Look at it go immediately!

STEPHANIE: Okay. So, one thing I found when I was browser testing this, and I'm gonna be filing a bug for this, is in Edge, this combination where we have an aspect ratio and specifically these kind of relative units for our rows. So, versus like being more explicit and defining something like 65%. It unfortunately overflows the aspect ratio area. So, our fix for right you, because I'm pretty sure that's a bug, that should not be happening, is to also define both width and height of 100%. That's just for Edge to make sure it like behaves. It applies the aspect ratio just fine. But for some reason, even though it should match Chrome, it must be a little behind on something there.

JASON: So, if I go into -- oops. If I go in here. Still working.

STEPHANIE: Still working. Yep.

JASON: Good, good. We're happy. Everybody's happy.

STEPHANIE: We are happy.

JASON: Chat, you happy? Chat's happy.

STEPHANIE: Now I'm going to have you go into the file. Let's definitely copy and paste some stuff.

JASON: Chat's happy. Look at them. Chat, you're at happy as me. That's how I'm feeling right now. Let's do this. So, I have the --

STEPHANIE: Okay. Scroll down to the part where it's defining the DT. So, you can skip all that.


STEPHANIE: We've set up our card as a definition list.

JASON: Oh, stampede!

STEPHANIE: Is -- still in the chat, you can drop your link for that. Oh, man. And so, if you copy though -- actually, just copy down to the font size because we're not ready for the last two properties under the DT. So, font size, yep.

JASON: Okay. And I put this under card stats, right?

STEPHANIE: Yes. So, within our DT we have a span. And I unfortunately had to like break my ideal semantics here. Because what we're gonna populate into that span, we're gonna populate a chart using CSS Houdini and the polyfill was not working when I had it as a CSS element. We have made space for. The 1fr is making space, and the auto is applying to time on apps or whatever the title is. So, let's really quickly, if you go back to the final copy, the -- the rule for the DD and the strong. We'll just make sure those styles are in there. They're not mission critical. But... I'm sorry about the nesting.

JASON: No, no worries.


JASON: This in there.

STEPHANIE: If you wouldn't mind commenting out the clamp. Let's just do it that way. Because it will have an impact here before we want it to.

JASON: Okay.

STEPHANIE: Okay. So, it's just -- we're setting the strong in the DD to display block. We're just -- rather than forcing a line break there. Okay. So, let's get to the like one of the more exciting parts of this whole thing. Is that span that's in that part has a class of chart. So, let's open a rule for the chart. And that's gonna be unique. So, yeah, it can just sit wherever. And we're using something called CSS Houdini. CSS Houdini, I can put a link in chat. But it lets you write your own -- there's a few different flavors of it -- but the one we're using today is the paint API. So, it let's you write your own canvas-based functionality to paint extra things within -- or via CSS. And so, I've created one. I went -- I used this as an excuse for me to explore Houdini a little bit more. So, I created one that's gonna generate dynamic bar charts.

JASON: Okay.

STEPHANIE: Now, these aren't going to be accessible. They're intended only to be a place holder. They're perfect for what we're doing today. If you were to develop this app, of course, please use a real charting library popped in here so that you have accessibility features and labors and so forth. So, the first step in getting this to be applied is to set the background image. And we use the paint function. So, this is unique to like Houdini.

JASON: Okay, okay. I've never used this before. I'm very excited.

STEPHANIE: In a -- what is it called? I can't remember the casing. Lower case Houdini, but then capped bar charts.

JASON: Like that?


JASON: Okay.

STEPHANIE: Go ahead and save that little buddy.

JASON: Ah! Okay, we --

STEPHANIE: Go to our --

JASON: We don't have time to talk about how to works, do we? Moving ahead. We have to do a whole episode on Houdini.

STEPHANIE: Yes. I'm not the right person to do it. If you're familiar with George Francis, that would be one of the people I would definitely tap for that.

JASON: Okay.

STEPHANIE: So, it's a little bit big. We're just going kind of a hacker/cheater way to reduce it. We're just gonna say margin 8%. And that's gonna give it our typical margins around that chart space.

JASON: Cool. Works for me.

STEPHANIE: So, what we want to do is we can actually -- we want these to actually have some dynamic flavor to them. And so, if you -- go to the file and copy and paste these.

JASON: Okay.

STEPHANIE: So, find the rule for chart which I think is above that one. Because it's nested in there. So, grab those -- grab those -- yeah. Custom properties out. We were gonna progressively build this up but we don't have time for that unfortunately.

JASON: We are out of time, y'all.

STEPHANIE: Okay. So, this gets us part of the way there. You can see the variance in the number of bars there. And this is partly working together we have set up in our DOM an inline style where we're passing a unique -- we created a separate -- if you look on, I don't know what line it is for you, like 36 or something. That chart ID. We're defining that as an inline style in the DOM so that we're forcing a variance of these bar charts which is cool. So, in other words, Houdini can read custom properties so that you can modify their behavior. Which is held together with CSS.

JASON: Cool. Very cool.

STEPHANIE: Okay. So, the other awesome thing we want to add is we want to have a little color variance. And we should be able to do this pretty quickly.

JASON: Okay.

STEPHANIE: We want to in our main stats rule, we would like to -- again, we're gonna build this up. But we don't have time. We're just gonna go for the final. We're gonna add that chart color property.

JASON: Okay.

STEPHANIE: Yeah. We might have to do one other step. I can't remember. Oh, yes. We do.

JASON: Look like we do.

STEPHANIE: Go into the final and we need the Nth child rules. And they're Nth child rules based on the card stats.

JASON: Here.


JASON: Okay. So, these ones I don't have time to port over so we're just gonna copy-paste them in. And I broke everything.

STEPHANIE: One extra curly. I think. There we go.

JASON: Yep. That was it, that was it.

STEPHANIE: So, you can flip over to your view and check out -- what's happening here is it's a repeating pattern using Nth child. And we have used our main primary color. And on one end, we've added 60 to our hue and on the other end, we've subtracted 60 to our hue. That's given us nice really simple variance in our palette without having to create new colors. And it feels nice, they kind of go together automatically. 60 is enough to give us enough of a turn on the color wheel if you will to hit another color.

JASON: That's really nice.

STEPHANIE: The other nice detail that goes along with that is up on the main stats rule to grab out the -- if you want to go to the final one, you can grab this out.

JASON: Okay.

STEPHANIE: We want to add a little tiny bit of a gradient that also picks out that chart color.

JASON: Here.


JASON: Ooooo... snazzy!

STEPHANIE: Yes. Now, do we have --

JASON: I like that you added all of this like, oh, I'm not a designer. I just have these hacks. I feel like that's what every designer says. This looks great.

STEPHANIE: But it is hacks. We're just using the primary hue and we're turning it. That's a hack.

JASON: Call it hack. Some way call that skill, Stephanie, I don't know.

STEPHANIE: Good times, good times. Okay. So, let's just -- just to finish it out, let's copy-paste in. So, that weekly score. That's one we called the cart highlight. Let's just go grab those styles just so that's looking finished.

JASON: Weekly score, that's down here somewhere -- here it is.


JASON: This one. Probably. Let's drop it in here and find out.

STEPHANIE: If you visit this repo later and check it out, it's just using our friend grid again to --

JASON: Nope. Where did I put this?

STEPHANIE: Outside of the card stats.

JASON: Outside of the card. Whoops. Oh, boy. Outside of the card stats.

STEPHANIE: So, it's nested within just the main card rule. But not the card stats rule.

JASON: Oh, within the card rule. Okay.

STEPHANIE: There we go. So, just making it look a little nice.

JASON: Yeah.

STEPHANIE: And we used a -- the unique thing in there, probably the only thing to point out, is that we used clamp on the font size of that percentage. So, you can see when it hits down below, it shrinks a little bit. There you go. We went ahead and used a regular clamp and viewport unit went on that because it is actually viewport-relative. With that said, we didn't get to our container queries. Let's spend the last 3 minutes doing that part.

JASON: Let's do it.

STEPHANIE: That was something we really wanted to hit.

JASON: Yeah, let's do it.

STEPHANIE: So, on our card stats, this is where we're going to have these apply.

STEPHANIE: Within the main stats rule.

JASON: Card stats! There we go.

STEPHANIE: So, you can put this wherever you would like as long as it's in the main one.

JASON: Okay.

STEPHANIE: So, with container queries, we have to define which elements we would like to query. which containers we would like to query. I have an article on Smashing Mag, I need to update a little bit because the syntax changed since I wrote it. The current, this is in flux because it's only on Chrome and they're in the process of writing the spec. It's out there for people to experiment and give feedback on it. And you can provide feedback on GitHub. I will get the link in the chat. To define, the current syntax, the property name is container-type. That's few different values. But the one we're going to use is inline-size. So, you can think of this as watch the width.

JASON: Got it.

STEPHANIE: The width is what we care about. This is going to be specifically about the width of that card stats. So, now based on the size of that container, we can effect -- we can make adjustments to the children. And instead of @media, we can use @container. After that with the syntax is similar to media query. They're working on enhancements where you can query is the container currently blue.

JASON: Oh, interesting. Okay. Okay.

STEPHANIE: What we're gonna use it for, though, is not to affect layout stuff. We're gonna affect the font size of each of these elements. And coincidently, it was just added as support in Canary. There are now container units. And I'm gonna put a link in chat. But Ahmad who is also terrific as a CSS educator wrote all about them. Similar to our view width, we would have in this case QI. Query inliner. Not sure what the what that is. But I think it's query. And so, if you go down to our -- so, like the font sizes we have right now, like our time on apps and those things, that's the data we're looking at, is reasonable. Right? But it would be cool if it adjusted based on the card size. That's what we're after.

JASON: Okay.

STEPHANIE: So, yep. If you go ahead and uncomment the clamps that we pasted in earlier. For those unfamiliar with clamp, we're giving it basically a minimum value, an ideal value -- and that's where we're using our QI. If you're used to fluid typography, that's where we would pop in a view width and then setting a max allowed size on it. And you'll need one more to copy-paste in there on the dt. We didn't put that one in earlier.

JASON: So, we clamp. Our min is --

STEPHANIE: In this case, 1rem.

JASON: 1rem.

STEPHANIE: Our ideal is 8qi for query inline units. And our max is 1.25rem. And then you want to go over to browser and play with resizing it.

JASON: And this is cool because --

STEPHANIE: We want it to -- yep.

JASON: You can kind of see these --

STEPHANIE: It's hard to tell.

JASON: Does everybody see these kind of adjusting in and out as we go here? It's actually probably gonna be most visible whether we do it this way. So, look at these sizes --

STEPHANIE: It's very smooth.

JASON: And then everything gets bigger, smaller. Bigger. Smaller. And it's subtle, but that is -- I mean, this is powerful stuff because --


JASON: It gives it a sense of space, right? Like you don't get that sparseness where it's big here, but then it feels kind of small when you get to like this size --


JASON: When it blows up, right? If it was the same size here as it is for the three across, it would feel weird.


JASON: But they have a sense of weight here that is proportional to the size of the container.


JASON: And that would be really hard to do if this was being done --

STEPHANIE: Oh, yeah.

JASON: With a traditional media query because there would be so many dependent factors that would cause this to get weird.

STEPHANIE: Absolutely. So much smoother than trying to orchestrate the page level. We picked the ones that work for page queries. This is a progressive enhancement. It just makes it that much better.

JASON: Yeah.

STEPHANIE: If you want to copy in one more rule that will pretty much finish up the demo so at least we can show the full demo real quick.

JASON: Let's do it.

STEPHANIE: So, if you go back to the layout file.

JASON: Layout.

STEPHANIE: And then within the layout grid rule, there's that scroll snap cards. Again, I don't have time to go in-depth on what this is. But we're going to look at it quick.

JASON: Layout grid. Let he go back to layout and we'll put this down here. Okay. So, let's look at it. What have I done?

STEPHANIE: Okay. Open up Dev tools and open up the device inspector.

JASON: Device inspector.

STEPHANIE: Okay. We have one -- you're good. We have one little rule that we need to add to fix this issue. So, we've set up this scroll snap ID. It's an inherent function in CSS now. It gives us like a cover flow if you will idea. Or it would be similar to doing JavaScript hacks for Parallax. Or not Parallax -- but go to the main rule where we did the direct child stuff.

JASON: Here?

STEPHANIE: Yes. And within -- just add overflow hidden. I don't have time to explain why that's gonna resolve it. But -- okay. Now you can play with it. No JavaScript happening. This is native CSS.

JASON: Okay. So, if I try to pull it to a period spot, it pulls us to the right card.


JASON: Oh, that's very cool. And this feels way less janky than what I've done with JavaScript.


JASON: Because we're not scroll jacking. Like it's taking my scroll and then when I let go, that's when it moves. Instead of trying to do like on the fly evaluation of what's going on. That is -- ooo... that's slick.

STEPHANIE: And there's a lot of caveats here especially with accessibility. This is not a production-ready solution. But it's one of the cool native CSS that replaces a ton of JavaScript.

JASON: Where is this that I was looking at and I lost it?

STEPHANIE: In our layout. It's the scroll snap.

JASON: Let's spend exactly 1 minute talking about this. So, what we've effectively said is we want to scroll the X axis and mandatory meaning it --

STEPHANIE: Grab it and take it.

JASON: And the width of the card. Oh, that's cool. And it snaps to the center. So, I mean, like I don't know how this works. But it's intuitive --

STEPHANIE: It's working.

JASON: You can see the snap align is center.


JASON: It should always stop. We have the width set to be the right kind of feel for that. This is slick. This is really nice.

STEPHANIE: I apologize. One final thing, 10 seconds. We need to copy out the dark mode to really polish it.

JASON: We can't not ship dark mode. This is a developer app.

STEPHANIE: We're using the CSS-only version. Again, this is not a complete solution. Ideally you also offer the user a choice on if they actually to want flip your site over to dark mode. Important caveat to this. Go to the theme file.

JASON: Go, and drop it in here.

STEPHANIE: We're essentially we defining our custom properties. We're essentially flipping them to a dark mode version and that's all we had to do. This took me when I was actually developing this demo, it took me about 8 minutes and a couple more minutes just to refine a tiny bit because we have been so careful in selecting our initial values.

JASON: So, if I go to light, it auto changes with us now.


JASON: That is -- oh, that's slick. This is very, very cool stuff. I love it. This is amazing. Okay. So, welcome, New Relic, I see you just raided right no time for us to head over and raid someone else. This has been amazing. Steph, where should someone go if they want to learn more about this? I've got a handful of links that we're already gonna share. I have this modern pseudo class selectors, we've got the CSS container query units. Anywhere else you want to make sure people check out?

STEPHANIE: Yeah. So, I'll pop in the GitHub where if you do play with container queries, that's where you can see the current issues and give feedback. That's really important right now. If you want to go more in-depth than today, if you don't mind me doing a slight promo.

JASON: Please do.

STEPHANIE: I'm doing a workshop in partnership with Smashing Conferences. We will go into the stuff today, but actually have time to go deep on it. Hope to see some of you there, starting October 5th. And then if you are feeling like you want to learn more about these different topics and you have an interest in CSS but haven't keep up, that's who I have written for. Check that out. And popped my name in chat, and this coming Monday, second round of CSS office hours. You can bring questions you have about the demo today if you would like. I'm doing that on my Twitch. I would love to see more of you there. 5t3phDev is who I am in the chat.

JASON: That is awesome. This was so amazing. Chat, let's do a quick run through of what's been going on today. We've had Amanda with us doing the live captioning. That's from White Coat Captioning. Thank you so much, Amanda, for hanging out. And that's made possible through the support of our sponsors, Netlify, Fauna, Hasura, Auth0, all putting a little bit of money toward making that live captioning possible because you got to pay to get that stuff done well. Really appreciate that -- that support. That is very, very, very helpful. I'm going to find somebody for us to raid. Stephanie, thank you so much for hanging out today. I learned a ton. This was an absolute blast. Chat, stay tuned for a raid. We will see you all very soon. Later!


Closed captioning and more are made possible by our sponsors: