591: Cascade Layers, CSS Functions, and more CSS with Miriam Suzanne

Download MP3

Miriam Suzanne stops by to talk about CSS updates and news on container queries, rolling out cascade layers, !important things to remember, custom properties, exit animations, CSS functions, state queries, and more.



Miriam Suzanne

Miriam Suzanne

Web · Social

Co-Founder of Oddbird, core contributor to Sass, author for Sitepoint and CSS Tricks, invited expert to the w3c CSS Working Group.

Time Jump Links

  • 00:19 Preferred Sick Days
  • 01:53 Container queries
  • 09:41 Rolling out cascade layers
  • 12:11 Working with prefixes
  • 14:40 Why does cascade layers exist?
  • 24:16 !important to remember
  • 26:08 Sponsor: Miro
  • 27:59 Shipping WordPress themes and layers
  • 33:27 Nesting rules
  • 36:28 Scoped value works in the dom
  • 40:53 CSS Custom properties
  • 41:30 Using not
  • 47:43 Exit animations
  • 52:27 What's happening with CSS Functions?
  • 58:12 Container style queries
  • 02:16 State queries are being worked on

Episode Sponsors 🧡


[Banjo music]

MANTRA: Just Build Websites!

Dave Rupert: Hey there, Shop-o-maniacs. You're listening to another episode of the ShopTalk Show. I'm Dave--extra baritone--Rupert, and with me is Chris Coyier.

Chris Coyier: You sound good, though. It's helping you, I think.

Dave: Really?

Chris: Yeah.

Dave: Maybe I should get sick all the time.

Chris: Yeah, all the time.

Dave: Hey, kids. Dad sounds real good, real - I don't know - throaty on the podcast. [Laughter] You should always... Yeah. Just keep bringing home the germs.

Chris: But see, you're sitting in your desk, which is the worst kind of sick. I feel like the best kind of sick is a good 24 hours, you're totally laid out. You can get into the new season of Gilded Age. It's out. Amazing. Watch that. Then you're fine the next day. It can't drag out. You just get 24 hours of TV.

Dave: I wish I had that kind of sickness, but I have not had that in a very long time, and it's very weird to me.

Chris: Oh, me neither.

Dave: Anyway. Hey, Chris, who is in the studio today, and are they sick?


Chris: Miriam is! Hey, Miriam!

Miriam Suzanne: Hey!

Chris: [Laughter] Hey! Sorry to force you through our--

Miriam: How are you?

Chris: We're just great at awkward intro banter. People say that about podcasts. They're like, "If you could go five, six minutes without saying anything of substance, that's what I'm looking for in a podcast."

Miriam: [Laughter] I love it.

Dave: That's great.

Chris: Yeah. Oh... thanks. Well, we brought you on just because we like you and you're a friend of the show, let's call it, and personally, and know a shunk load about CSS--that's a real word--and are at the forefront of new CSS a lot of times, which is wonderful. Thanks.

Let's talk about CSS a bunch. Are you ready?

Miriam: Great. Let's do it.

Chris: Let's do it. So, I saw you on Jason Lengstrof's show. That was probably a couple of months ago now, wasn't it?

Miriam: Oh, yeah.

Chris: Because Jason likes to learn. You like to learn with Jason.

Miriam: That was great.

Chris: And you did the container queries thing. Yeah, that's nice. It was a great walkthrough of container queries. This is weird to say, but it's always like, "Container queries... pfft. That's old now."

Miriam: [Laughter]

Dave: Old!

Chris: Old!


Dave: Yeah.

Chris: Which of course, it's very much not. It's just weird that CSS is moving so fast that we're like, "Got it! Next! Let's go!"

Miriam: [Laughter]

Chris: You know? But that one has rolled out across all browsers. In fact, I just used it yesterday in a way where I'm not even thinking about it anymore. You should think about it. I'm not advocating that people don't think about browser support. But because it's in all the main browsers. If you have a pretty hip audience or whatever and the numbers support it, that's a pretty safe one to just use it. Wouldn't you say?

Miriam: Yeah, and a lot of us have sort of that background of having gone through that with media queries and knowing how to use them as a progressive enhancement. You've got a fallback of some kind. What does it look like without the container query?

Chris: Sure.

Miriam: It does feel like one that's really safe to pick up whenever if you can provide an okay fallback.

Chris: Yeah. Okay. Right on. And so, if you just happen to be totally under a rock or whatever -- which I shouldn't say that because it's not everybody's job to keep up with CSS. But whatever. You're listening to a podcast where we've talked about CSS hundreds of times, so you probably can say that.


Dave: Sorry. Why are you 591 episodes in?


Chris: Without anything.

Dave: I mean at least up to the 2021 specifications. [Laughter]


Chris: Yeah, a little weird. But it's like a media query. Only you can style an individual container instead. I often think of it as just width. It's width. That's the 90% use case. What's the other 10%, though? Could you do container height? Is that even a thing? It probably is.

Miriam: Yeah. The tricky thing with container height is you can't contain only the height of a container. You have to contain both the width and the height.

Chris: Oh...

Miriam: That's because it's a bunch of the loopy things that we're making container queries hard. But it's really only useful if you've got a container that you know is going to have a set height from somewhere outside.

Chris: Oh, I see. From somewhere outside, which is usually an inside thing.

Miriam: Right, exactly.

Chris: Right.

Miriam: There are sometimes, like if you're doing a full height scrolling main area or something.

Chris: Right.

Miriam: You know the height is coming from the browser, so it's coming from somewhere. Now that's not particularly useful because you can measure the browser, too. But say there's a footer and there's a header, and you don't know the size of those.

Chris: Oh...

Miriam: There might still be ways that you're--

Chris: Occasional. Sure.

Miriam: Yeah. But you're right. It's mostly width.

Chris: It's a width thing.

Miriam: It's a width thing.

Chris: Yeah, right on, which is obviously just incredibly, extremely useful. I like that every demo about it ... was like, "All right. Let's see. How about a card?"


Chris: It's going to be a card. But I'll tell you what. Cards are a thing, baby. Little websites, like Dave calls them.

Dave: Little baby webpages on your webpage.

Chris: They need container queries. I'll tell you what.

Miriam: Yeah, they're just a real quick example. Easy to do.


Dave: What's been your favorite container query-ization that you've seen? Do you have a vision board, a little mood board of all your favorites?


Miriam: I wish. Somebody asked that at conference, and the truth is people don't tell me when they use container queries.


Miriam: There's no, like, "Fill out this form."

Chris: No hotline? 1-800-container.


Miriam: I usually don't know. I've seen a lot of cool demos, but I actually haven't... I don't know how people are using them in production.

Dave: Mm-hmm.

Miriam: That's when it will get exciting for me is to see how people are doing real things with it. All over CodePen, there's really cool--

Chris: Yeah, for sure.

Miriam: --theoretical tricks.

Chris: The most common one to me is it's two columns. But at this point, it's one column.

I don't know. That's still amazing to me. I know that's not as sexy as this calendar that swaps between four different layouts or something. But that's not as day-to-day as grid template columns 2FR, 1FR.

Miriam: Yeah.

Chris: Then container query 500 pixels, grid template columns 1FR. [Laughter] That's great.

Miriam: Also, I've seen some great examples of people using the container query units to do responsive typography that's responsive to the container. That can be very cool.

Dave: Yeah, that's the way to do it.

Chris: Totally cool. I almost think if you're going to dip your toes into padding and stuff, too, that a container query unit is maybe more appropriate than the document is - or whatever you'd call it - the viewport units. Yeah, pretty cool.

I feel like a border-radius here and there is nice to use container queries for. If it's really big, you can get away with a more rounder thing.

Miriam: Sure. Right.

Dave: Big, fat borders. Okay.


Chris: You know one thing that always gets me, though, is like, "Oh, cripes! Yeah, I've got to put another div around it."

Miriam: Yeah.

Chris: Got to put another div around it. Rock the wrapper. Yep.

Miriam: Yeah. That's the downside of a lot of them.

Dave: But you say that like we don't already have 500 divs named container in our webpages--


Chris: Yeah, fair enough.

Dave: --already, right? I feel like--

Chris: You know what I've been--? Not that anybody cares, but I like the idea of putting the wrap... Forgetting about it and then adding a wrap around what you've already got is nicer than being like, "I'm going to put a card-inside inside it." I always feel like you're probably trying to style the thing you already got, so just wrap it.

Dave: Hmm...

Miriam: Right.

Chris: Then put the container on the wrap.

Miriam: Yeah, that makes sense.

Dave: Ooh... So, you're coming out against no inner wrappers.

Chris: Inner wrap.

Dave: Yeah.

Chris: Yeah, I'm anti-inner wrapper.

Dave: Okay. All right.

Chris: Not that I really care.

Dave: No. No.

Chris: But I feel like it tends to make more sense. And I've thought, just in retrospect, that I thought it would be the majority. That was kind of the speculation before they existed was like, "If we had these, we would mostly use them," was kind of the guess.

Dave: Mm-hmm.

Chris: And I feel like I'm not quite even 50/50 yet. But at the same time, if I was working on a design system all day, I think that number would be a lot higher.

Miriam: Right.

Chris: Because you're just working on digital components, which just randomly I'm not at the moment.


Miriam: Yeah. I think, over time, also, we just have to see if there's something you reach for more.

Chris: Yeah.

Miriam: Once they're more integrated into the toolkit. But also, these days I feel like we use a lot of media queries for other things. Right? Like querying the dark mode or light mode or reduce motion. There are all sorts of media queries that there isn't an overlap.

Chris: That aren't width.

Miriam: Yeah, and those aren't going anywhere.

Chris: Yeah. Yeah, yeah, yeah. There's no such thing as a container query of dark mode, right?

Miriam: Right.

Chris: I don't think so. That would be weird. Okay. Yeah, yeah, yeah. There are just more media queries.

But speaking of, I am interested in that rollout thing because you were perhaps even more involved. I don't know what your day-to-day is, but cascade layers was a little bit straight-up credited to you, your early proposals, and stuff, and is also all the way out in all the browsers, which has got to feel good. That's some legacy stuff.

Miriam: Yeah, that's wild. It was my first proposal. Then they invited me to join the group to work on it.

Chris: Mm-hmm.

Miriam: Then it shipped absurdly fast. The problem is, it's all downhill from here. Right? Nothing else is going to ship that fast. [Laughter]

Chris: Yeah, you're done, I'm afraid.

Miriam: I'm done.

Chris: That's it.

Dave: Sorry. Yeah.


Miriam: But yeah, that was wild. It was wild to see a proposal that I made roll out in the browsers. I mean it's sort of the opposite in some ways. It's invasive, and it's hard to progressively enhance.

Chris: Mm-hmm.

Miriam: So, it's one of those that rolled out, and it's going to take five years for it to become common because it's not as easy to add piecemeal here and there.

Chris: It's just like contain queries is. You can just plunk one of those in. But if a huge codebase is like, "You know what? This cascade layers stuff is sweet. We're going to layer all of our styles." I would think you might have a bad time, maybe. That's going to be rough at first. Greenfield, though, for sure it's cool.

Miriam: Yeah, and I think they work best when you use them over your whole product, your whole site - whatever.

Chris: I see. Yeah.

Miriam: That's where they really shine. So, yeah, it's going to take a little bit before people are comfortable doing that. So, I'm glad it rolled out fast so that now the five-year timeline is shorter. [Laughter]

Chris: Mm-hmm. Mm-hmm.

Miriam: Or it's already rolling.


Chris: Yeah. You're right. It would be way too... I have no idea what the polyfilling scene is on that. But even if it were possible, it'd be probably pretty heavy, wouldn't it?

Miriam: Yeah.

Chris: Because you'd use specificity as the proxy, which would mean affecting every selector.

Miriam: Yeah, some of the team at OddBird worked with the auto-prefixer folks.

Chris: Mm-hmm.

Miriam: There is a polyfill. You can use it. You can use a little bit of JavaScript to decide which CSS to load, and it works.

Chris: Hmm... Right on.

Miriam: You can do that. But up to you whether it's worth it.

Chris: I was thinking about auto-prefixer the other day because, as it should, perhaps, has died off in neccessaryness and probably usage, I would think.

Miriam: Yeah.

Chris: People are like, "Okay, Mask is still weird. You still need WebKit Mask," and what else? Can't even think of one. There are pretty few. But if you are using it to polyfill... But if new stuff comes down the pipe that could use it, then - I don't know - maybe its relevance will peak again. It's not dead forever. It depends on what CSS does.

Miriam: Yeah, and this is technically separate. It's a separate polyfill but same post-CSS approach.

Chris: Oh, I see. You don't just turn on PostCSS--

Miriam: Right.

Chris: --and it starts polyfilling your cascade layers. I see. Interesting.


Chris: I also looked at Lightening CSS. There used to be some contenders. In fact, you can see the history of this kind of embedded in the CodePen UI. We had two options for dealing with prefixes. You could just click a radio button that says, "I'd like to use auto-prefixer," and then we'd just roll it through auto-prefixer.

Then Lea had an old--I hesitate to say weird, but it's a little weird--project called Prefix Free that did it all client-side only. That it would look at the CSS OM. I don't know what the right words are. It would apply the prefixes that way. It was zero-build process, which is appealing to some people, but probably had that kind of flash of, you know, JavaScript has to execute and that probably happens after first layout.

Anyway, I guess you can change that now. Isn't that relatively new on a script? You can say, "Stop render," or something. There's just some new attribute that you can tell the page to not even do that first render until this JavaScript has executed. I think that's a thing.

Miriam: You've veered off my expertise.

Chris: Yeah. Well, it exists. I'm telling you.

Dave: No, it is. It's weird. It's like rendering is the name of it.

Chris: Yeah. Rendering no. [Laughter]

Dave: Rendering block or blocking, or something.

Chris: Block, blocking. Anyway, it's a thing. But then all of a sudden, this Lightening CSS kind of comes out of nowhere, if you ask me, which also does auto-prefixing. So, kind of neat. If you haven't seen it yet, it's a contender in that world. I don't know how it does it, but it seems to make the right choices the last time I used it.

Okay, so we did it. Container queries, green checkmark emoji.

Miriam: Done.

Dave: Done. Next.

Chris: Cascade layers, we didn't... I don't know if we did it justice, but it is a very cool thing that you can do. Should we explain a little bit more about what it is? What's the top use case (in your mind a little bit) for why that would exist?


Miriam: A lot of people solve specificity. I'm putting heavy air quotes around that.

Chris: Solve? [Laughter] Yeah.

Miriam: Solve specificity by--

Dave: [Laughter] We solved it.

Chris: Yeah.


Miriam: --by pretending it's not there and then shoving everything into classes and always one class and using these complex naming conventions. And a lot of people--

Chris: Ah, so we're yelling at BEM. We're yelling at Tailwind.

Miriam: Sure.

Chris: Okay. Go on.

Miriam: Sure. Find as a hack, but it's a hack, and people will often be doing those things and then say, "Well, why would I need layers?" I'm like, "Well, you're doing those things and you shouldn't have to."

Selectors are pretty cool. There's a lot you can do with the attribute selectors and all sorts of other things that are useful. So, let's let you use selectors again by giving you another way to manage specificity and state what should override what in your system.

Chris: Right.

Miriam: I think that's especially useful sort of the bigger you get and the more of your project is using it. It's like I can bring in my design system in a layer, and then I can bring in my component library at a layer. I can say whether the component library wins over the design system or whatever. Right?

Chris: Mm-hmm.

Miriam: I can set up these layers of my application and know that, within each one, the specificity is contained. Then I can say which layers override which layers.

Chris: Right. Would you say that it--? It almost feels like it contains decision-making, in a way.

Miriam: Yeah.

Chris: Then if you were going to give yourself away, like a library, like Bootstrap or something. I'm hesitant. I wonder if a best practice will be you layer yourself before it even... Like the NPM version of it is already layered. But that weirds me out a little bit. It almost seems like you'd want to make that choice as a consumer.


Miriam: Yeah. I think we're going to want both. So, you can layer things that are already layered. Then you end up with nested layers, and that's fine.

Chris: Oh, yeah.

Miriam: I think Bootstrap should ship layers. Then you should pull Bootstrap into your project and put their layers in your layers.

Chris: Oh, okay.

Miriam: And say where it goes.

Chris: That makes sense, except for that you can't un-layer it. But maybe that's okay. If you wanted it to be the top layer, then layer your project and make it the top layer.

Miriam: Exactly. Right.

Chris: Yeah, all right. Oh, wild.

Dave: I guess I'm picturing Bootstrap at some point orders their layers, right? Like base, element, modifier - whatever. I don't know. We're just picking words. [Laughter]

Miriam: Yep.

Dave: Let's say Bootstrap adds that and it ships in their CSS file that goes to my client. Then I can come through and write a little inline script that say, "No, actually, at layer the order is modifier, element, base," and mess up Bootstrap real good.

Miriam: You could. More likely, you're going to say, "Pull their three layers into a Bootstrap layer," and now we have Bootstrap base, Bootstrap elements, Bootstrap modifiers.

Dave: Okay.

Miriam: We get those nested layers, and you can move them around where you want. But you do have the ability to go in and move their layers around if you really want to.

Dave: Yeah. Okay. Yeah. Best practice might be Bootstrap name spacing their layers like Bootstrap base, Bootstrap--

Miriam: Mm-hmm.

Dave: Yeah.

Chris: Nobody will ever be mad again--

Miriam: Ever.

Chris: --that some third-party library has shipped with stuff that's hard to override because this literally does solve that. If you put their crap on a layer lower than yours, anything you write will win.

Miriam: Exactly.

Chris: Regardless of their specificity, which is really almost like I could imagine the madness totally reversing and saying, "My CSS is too powerful." [Laughter]

Miriam: Yeah.

Chris: I need to notch myself down a little bit.

Miriam: And the great thing is you can put stuff below Bootstrap and stuff above Bootstrap. You can set up the layers however you want.

Chris: Mm-hmm. That's wild.

Miriam: But additionally, you don't need to wait for Bootstrap to do it. You can already, right now, go pull in Bootstrap into a layer in your styles and now you have Bootstrap layered.

Chris: Yeah.

Miriam: And you can work with it from there.

Chris: It's not theoretical. You could do that right now if you want to. Pretty cool. Except for if it's a link tag, and then you can't. But other than that.

Dave: I was going to say I know Jonathan Neal, in order to reduce specificity, was like, "I'm just going to put all my third-party stuff in where."

Miriam: Uh-huh.

Dave: Like :where just to really make it as low as possible, but he could also just put in a layer and then I can decide how important it is.

Chris: Yeah. Unfortunately, those kind of happened at the same time, so where would have been great five years ago. But whatever. It's less useful now. It has other uses, but I think people are attracted to the idea that it wipes out the specificity of the selectors inside.

Miriam: Right.


Chris: But the point is that it also has coma-separated selectors. Comma-separated selectors in... Would you call it a function, or it's a pseudo function? I don't even know what the terminology is there. But that's just cool.

Miriam: Functional pseudo class, I think. Something like that.

Chris: Woo!

Dave: Woo, $5-word right there. Yeah.

Chris: Right. Out of the top hat. Nailed it. [Laughter]

Miriam: [Laughter]

Chris: Cool. Yeah, anyway, it's great. It's unbelievable that we can do that. To me, it's almost more unbelievable than container queries that we're just like, "We're going to ship an entire new layering system for styles, and have all browsers be like, "That's fine. Shipped." What?!

Miriam: Yeah, and not just... That's fine. They rushed it. They went in hard on that one, which took me by surprise because I was suggesting a core change to the cascade.

Dave: Not a usual thing people mess with.

Chris: Yeah! Normally, that's a hard no, in my very limited experience, like, "We're going to change everything."

Dave: But think it also -- not to... you shouldn't be too humble. You understood how the cascade operated, like, "Here's where the browser applies its things." You know? "And here's how importance work." And you were like, "What if we just shim in some user-defined things right here?"

You were like, "The browser is doing this anyway. But let's give the user some variability."

Chris: That was true, right? The user agent styles were already kind of occupied a layer of sorts.

Miriam: Yeah, there's already a layering of the user agent goes first, the browser. It provides all the styles that we think of as the defaults.

The spec has an initial value for, say, display. The initial value of display is inline, always. If you set display initial, you get inline. It doesn't matter if you're doing it on a paragraph.

Chris: If it's a div or what?

Miriam: It doesn't matter.

Chris: Yeah. oh, wow. Gees.

Miriam: Initial value is inline.

Chris: Oh, so that's not a user agent style sheet. That's even lower than that.

Miriam: Right. That's the spec initial value. Then the user agent comes along and provides some useful defaults like, "Hey, all these things should be display block, actually. Paragraphs should have some margins. Headings should be bigger."

Chris: I didn't think that was a layer. I thought it was just because A) it's the first thing to load and B) the selector is just really weak. It's just a P tag.

Miriam: No, if you look in there, there are some really complex, especially around tables. There'll be, like, when this type of table cell follows this series of rows and columns, then provide this border default.

Some of them get fairly complex. They're not using classes because it's all just HTML tags in there.

Chris: Yeah, you can't. How could it?

Miriam: Yeah. But they have some fairly high specificity for just stacking up element tags.

Chris: I see. Yeah, I see. Okay.

Miriam: And you can override those all with anything because we're at a higher layer.

Chris: Right, so if you said TD border bottom one-pixel solid block - or something - it's possible that borders are involved in the UA style sheet but in such a complex way that it's really table, T body, TR, TD first child, and all that.

Miriam: Right.

Chris: If they said border zero, they would win because that's higher specificity. But it's not because it's on a layer.

Miriam: Right.

Chris: Woo! I didn't really understand that. Thank you.

Miriam: Yeah, and user styles slot in between, so the user agent goes first with defaults, then user styles, which right now you just set as settings in a form in your settings on your browser. You can go in and say, "This is my default font. This is my default font size." A few things.

Chris: Right, right, which it doesn't even look like CSS.

Miriam: Right, but it is.

Chris: But it turns out it is applied as CSS. Yeah.


Miriam: Then we come last, but we shouldn't always win. So, that's why importance was invented. Importance exists for the browser and the user to day, "No, you have to use my font. You don't get to override me on this."

Importance is there for people to take the power away from us. It's not there for us to fight each other, which is what we use it for.

Chris: You're talking about bang important.

Miriam: Bang important.

Chris: Yeah.

Miriam: Yeah.

Chris: Right, which that's the suckiest thing to learn about cascade layers is you're like, "Well, it reverses important." You're like, "Wait. What?!" [Laughter]

Miriam: Yeah--

Chris: But it does make some logical sense after you get it. But it's an unfortunate thing to have to know.

Miriam: Right. The way that we've used importance is to say, "I want to override something that's already there." For that, we should start using layers instead.

Chris: Oh, right, right, right.

Miriam: If you want to override something that's already there, we use a layer. Importance is for saying, "This is so important, I need to protect it from future layers," so like this class doesn't work anymore if you take away this style.

The hidden attribute. If you override display none on the hidden attribute, it doesn't work. It's broken.

Chris: It's too weak?

Miriam: So, it's a reasonable one to say, "We're going to put it in a weak layer because it's just a reset. But we're going to put importance on it, and that's going to protect it from future layers."

Chris: Right, so the lower the layer, the weaker the layer, the stronger the important is on it.

Miriam: Exactly.

Chris: Blah.

Miriam: Because it's a defensive move.

Chris: Right.

Miriam: Not an aggressive move. We use the force to defend. [Laughter]

Chris: I see.


[Banjo music starts]

Chris: This episode of ShopTalk Show was brought to you by Miro. Thanks for the support, Miro.

Miro is really a tool for teams. You can think of it as an online visual workspace, really great for visual people like me. Or you could think of it as an infinite canvas tool. You make Miro boards, and they could be anything. In fact, you go to do it, and there are all kinds of templates in there for what a board could be. You're not even limited by these templates, but they really get your mind going on the possibilities of what it can be.

For example, project management is one of those things. For example, I can make a Miro board like a Kanban board kind of thing where I have tasks and the tasks are cards, and the cards can be from any source.

Dave and I were just in there today doing some episode planning so we can have our columns for our Kanban might be, for example, ideas or in progress, invited, recorded, finished, and we can be dragging the cards in between to keep us all on the same page.

Dave is in Austin. I'm in Bend. We're not together. But through a Miro board, we can do this in real-time. In fact, we were in a meeting, and we were doing all of this together.

We're like, "Okay. What's a great episode idea for a show?" We're dragging on the avatar of the guest. Then we're dragging on (in this beautiful Miro board) ideas for what we want to talk to them about. We're just brainstorming together in this kind of permanent way that's a permanent part of this Miro board.

But I can do it alone, and Dave can see it later. In fact, I can record a talk track to go with it and talk him through what I was thinking about. A tremendous feature of Miro.

Then we're on the same page. We've got a plan. We can rubberstamp the thing and say, "That's what Season 23 of ShopTalk Show is going to be all about. These are the guests. Thumbs up. Thumbs down," all that kind of planning. So good.

Find simplicity in your most complex projects with Miro. Your first three Miro boards are totally free--very generous of them--when you sign up today at Again, that's three free boards at

[Banjo music stops]


Chris: It reminds me of WordPress in two ways. Sorry to connect to it, but one of them is if you're going to ship a WordPress theme, Dave's theme, you should layer everything.

Miriam: Yeah.

Chris: Because it's meant for someone else to use it, and there's a chance that they want to write their own CSS, and they should probably win. So, it would just help them. It'll just be a better product if you do that.

Another one is I have used important because every time I use important, I'm like, "This is probably a learning opportunity of how I should not be doing this."

Miriam: [Laughter]

Chris: But the modern-day WordPress has the block editor, and it has stuff like, "Oh, I want to put two columns next to each other as this little block in the middle. Well, that's literally impossible." I mean I guess you could use a table or something. But for modern-day, that cannot be done without CSS.

WordPress injects some CSS onto your page in which to do stuff like that. I think it still uses Flexbox, like flex1, flex1 on two divs - or something. Great.

But if you want to override what's happening there with your own CSS, now you're in a fight. How they chose to do that is their business, and it's probably some internal classes and stuff. A class is already pretty high. It's a lot higher than some elements are.

Miriam: Mm-hmm.

Chris: If you just say, "I'm going to attach a class, too," now you're in a specificity war. One class versus one class, who wrote it last? Where'd you load your styles?

Where you load your styles in WordPress -- I know I'm being very WordPress specific, but this kind of matters to the overall concept -- I just probably have a link tag in my head where my CSS is. It just so happens, in this particular framework, that wherever you put this little PHP function wp_head() is where their styles get spit out. So, it's a little arbitrary in a theme which happens first.

I probably put their later because I feel like, "Eh, there's a chance some plugins and crap want to be last because they want to win some stuff." But now my CSS is lower.

Miriam: Mm-hmm.

Chris: It's not really on a lower layer yet because I haven't used that concept, but it is source order earlier.

Miriam: Right.

Chris: I'm going to lose that CSS battle of one class versus one class. So, my temptation... I have different options. I don't know. Double up the class. You ever do that one?

Miriam: Uh-huh, yep.

Dave: Yeah.

Chris: You just put the class twice. Why not? Now I win.


Chris: Or I could put an ID. Don't want to do that because you only use it once, yadda-yadda. Or maybe you put the tag first, like div.columns. A little bit of specificity.

All those options suck. What they should have done is rolled out all these block styles layered.


Miriam: I know they're discussing it now.

Chris: Oh, that's awesome.

Miriam: There's a discussion in the WordPress repo about, like, "Can we layer internal styles?"

Chris: Yes, you can.

Miriam: "And can we recommend layering for themes?"

Chris: Yes. [Laughter] I already answered both of those questions.

Miriam: Yeah, great.

Dave: Yes.

Miriam: I think that does give it a great use case, but also, the other thing that it points out is that layers, you can set the order of them, and then you can write your code in any order you want. You're not beholden to source order all the time if you've got your things in layers.

Chris: Right.

Miriam: You can say the layer order, and then it doesn't matter whose gets there first.

Chris: Yes. That's really cool. That's a powerful concept. You don't have to order your layers, but you maybe should because it gives you--

Miriam: Yes.

Chris: It gives you some power later that you might want. You don't have to name your container queries, but you probably should. [Laughter]

Miriam: Yes.

Chris: I hate to use the word best practices. I don't know. Somehow that became a dirty word, but it's kind of one.


Miriam: I don't know. Dave wants to get rid of nuance. You need a word like that, I guess.

Dave: Hey, "ruthlessly eliminate nuance" is a word practice. That's referencing this good post by Will King that just was kind of like, "Let's, instead of saying best practice all the time, we say readability pattern or performance pattern." Just kind of saying why we're doing this thing, not just "It's best!"

Chris: Say what the practice is.

Dave: Yeah.

Miriam: That makes sense.

Dave: Use your words. Use your words. Use your words.

Chris: [Laughter]

Dave: I was just going to point out, I looked in Bootstrap. There are 1,279 instances of important in Bootstrap 5.

Miriam: Whoa!

Dave: That's a lot of importance, which maybe they do need layers.


Dave: I feel like... I looked in Tailwind, too. There's a lot there, too.

I think it's like when you do the utility thing. If somebody adds a utility class, you kind of need to make it important.

Chris: They're trying to mean it.

Miriam: Mm-hmm.

Chris: Yeah.

Dave: They really wanted to display flex so much that they put it on the element.

Chris: Well, if your class is font-bold, you're very sure that you want the stupid text to be bold. Just win then. You know? Do what you've got to do to win.

Dave: But you could imagine a world where you put your utilities on the last layer, it's because last wins, right?

Miriam: Mm-hmm. Yep.

Dave: Yeah, or no layer. Ah... Because that also wins.

Chris: Yeah or say what you mean, then, like the winning layer.

Dave: Yeah.

Chris: No, that's bad, I guess. But some layer that somehow expresses that. I feel like utility doesn't say ultra important.

Dave: Yeah. Yeah, yeah. It needs to be like--

Chris: Maybe it does. I don't know. I waffle.

Dave: Maximum power is the name of the layer.

Chris: Yes, there you go.

Dave: Yeah.

Miriam: I don't know. I think I'd stick with utility, but....


Chris: All right. All right. Utility is....

Dave: Maybe it gets the arm emoji, like the muscle emoji.

Miriam: Oh, yeah.

Dave: Yeah. Yeah.

Miriam: I think emojis are allowed in layer names. I guess somebody should check that. But I think that works.


Chris: It seems fine. I do like how nesting kind of goes with all of these things. You don't have to write... You can write a container query right at the root of CSS, like all the way on the left. Then within it, say a selector of what it's applying to. That's fine.

Or you can nest it, which isn't just totally convenient. It means it assumes that whatever is in there, the next selector up is the name you're trying to apply it to. I feel like that's a nice thing about nesting that is a little unsung, perhaps, is that that works with container queries, and it works with scope, too, which is cool.

Miriam: Yeah, and media queries.

Chris: Media queries.

Miriam: And most of the at rules that you would nest selectors inside of.

Chris: Yeah. If that's all nesting did, I hate to say dumb stuff like that, but that's a powerful concept.

Miriam: Yeah.

Chris: You don't have to repeat a selector anymore. It's just in there. I guess that's what normal nesting does, too. But I think it's extra cool, for some reason, with at rules.

Miriam: Yeah. I feel like it's not just limited to putting elements inside other elements. It's useful for the modifiers as well.

Chris: Yes.

Miriam: The pseudo-classes, the media queries, container queries, all of that.

Chris: Yeah. Pretty nice. I love it with all those things. So, we didn't do scope yet, but that's another one. Less exciting if we're only just talking about browser support. It's not there yet like the other two are.

Miriam: Right.

Chris: I think.

Miriam: Yes.

Chris: But it's another at rule. Layer even is an at rule, isn't it?

Miriam: Mm-hmm.

Chris: Container queries definitely is, or at least part of it.

Miriam: Yep.

Chris: Scope is another at rule. At rules are really poppin'.

Miriam: Yeah.

Chris: I'd say.

Miriam: There are limited syntaxes in CSS to pull on.

Chris: Yeah, to pull on.

Miriam: That's sort of the block one you get.

Dave: That's kind like, "Put a bird on it."

Miriam: [Laughter]

Dave: Put an at on it. Yeah.

Chris: There you go.

Dave: Yeah.


Chris: Soon, we'll be in emoji town once we run out. I was surprised that the scope value works in the DOM, too. Like if you put a style block in the DOM and say @scope, it assumes that what you're scoping to is the next element in the DOM from where it is. I'm like, "Wow!"

Miriam: Yeah, that was our solution to style scope, which everybody kept asking for. It's a difficult one because you add that attribute in HTML and old browsers don't see it. Then they apply those styles un-scoped. That's pretty broken.

Chris: Yeah.

Miriam: You don't really want it. This way, you're using some new syntax that would hide it from older browsers, and you still get the same behavior, which is pretty cool.

Chris: Wasn't it, for a minute, it was a little uncool, maybe? I'm talking about the performance characteristics, I guess, as well as just semantics and HTML validity, I guess. Can you just put a style block in HTML? Are we past that being bad? Is that fine now?

Miriam: That's my understanding. It loads later, so you want to use that carefully. You don't want to use that for your most essential styles. If you want them to load before things are rendered, you're going to want to put it in the head.

Chris: In the head. I see.

Miriam: Maybe you want things to sort of... You lazy load images. Maybe you want some lazy-loaded CSS. Great.

Chris: Yeah.

Miriam: But it in the body.

Chris: I can't be too far behind either. It's still above the styles that you're about to apply it to, assuming that's what you do.

Miriam: I think it loads when the parser gets to it.

Dave: To me... I don't know. CSS Modules existed a long time. Vue has the ability to just put the scoped attribute on it. It used style scope, but it just uses some magical thing to do that. I don't even know what it does. It invents weird class names or something. But it means that you don't... It's scoping your styles for you. Astro does the same thing. I think there are lots of frameworks that allow you to scope a chunk of CSS to the component that it's talking to.

But it has some exotic build process to do that. Surely, somebody had to handwrite and hand-maintain that code. And it's probably nontrivial in a way. I feel like this makes it kind of trivial.

Miriam: Yeah.

Chris: If you want a chunk of CSS. I'm going to write .card, but I'm so nervous because what a boring class name.

Miriam: [Laughter]

Chris: Anybody could use that. I could use a weather widget and it uses .card. Now my styles are God knows where. Bad job. But if I put that style block, and I say @scope, and then I put in there .card, that card is totally isolated to that little piece of DOM. I use no build process or nothing to do that. That seems like... What?! That's a solution that's really good.


Miriam: Yeah, and with both that approach and writing your scopes by hand with sort of the selector syntax for scoping, in both cases that build step requires access to both the CSS and the DOM.

Chris: Yes.

Miriam: It needs to understand the whole structure of everything in order to do that build step, which that's a lot for your build step to know.

Chris: Truly.

Miriam: That's part of what excites me about scope is it does the same thing as that build step but without any of that knowledge of the whole system required to do it.

Chris: It's kind of what's part of the magic of Tailwind - to say something positive because I'm a compliment sandwich. Part of the config of it is that you have to tell it where all your templates are.

Miriam: Hmm...

Chris: You use *.html because you're like, "Please look at all my HTML." Part of its build process is, "Look at all my templates. Find all the classes from all of them. Then produce the minimum amount of CSS required for all of those templates," which I think is actually pretty clever and cool. But man, that's work.

You need an HTML parser that you can really rely on that even in busted-ass HTML, it's going to generally do a good job. Then it's not HTML. It could be your Nunjucks templates. It could be your .jsx templates. It could be anything. To have really reliable code that can do that, that's a lot.

Now look. The platform is just going to do it. Slick. And it's a little bit like properties, too. Now I feel like I'm talking too much, but wasn't that the cool part of CSS Custom Properties is it just inherently knows what's going on, on the page, in a way that a processor never could?

Miriam: Right. They're part of the cascade. Yeah.

Chris: Yeah.

Dave: Yeah, it's not this pre- or it's not static, right? It's not at compile time. It's at runtime. You can just change it.

Miriam: Mm-hmm.

Dave: You could write a plugin that just changes all CSS variables, just cycles them if you wanted.

Chris: Wow! Where is Alex? Alex, do that.

Dave: Yeah, Fimian to the chat.

Chris: That's weird. Yeah.


Dave: Paging Fimian to the... Fimian, please come to the podcast chatroom.

Chris: Do something weird with variables.

Dave: Your services are being requested.



Dave: No. Yeah, there was a neat post by Christopher Kirk-Nielsen, which I think I saw through Chris Coyier's likes, where he replicates scoped, like the donut scoping, with has. Did you see that post?

Miriam: No.

Dave: I can post a link, but it's really... And scroll to the bottom. There's a really good example. I'll mouth blog it here.

In CSS Scope, you would say @scope (.card) to (.card-content) and then a { color: var(--accent).

Sorry. Not, he's using not, not has. Sorry. The not version is .card a:not (.card-content *}.

Basically, he's just saying don't... Apply this variable but not for this. Anyway, it's just clever, but it actually helped me sort of wrap my head around what donut scoping is useful for. Then on top of this, you have the whole scope thing.

Chris: At first glance, those do seem... I know this is hard for people listening audio-wise, but what Dave just said was accurate. The idea of a donut scope is that it's starting at this selector but literally stop when you reach this other DOM.... And anything that's a child of it, stop applying styles to, which is very unique in CSS. I don't think we've had any other way of doing that.

Then I say that, and I'm like, "Well, this blog post says you could kind of use not." At first glance, it's like, "Yeah, that looks like that would work."

Miriam: Yeah, so the main difference there is this won't work if you start nesting them. This is going to stop if you've got any card content anywhere around the thing. Whereas scope says only between the scope root, between the card and card content. Card content has to also be inside of card.

You might be able to do it with some more trickery, but I think you can't quite say only this card element matters. The one that you've matched does the root of my scope.

Dave: Mm-hmm.

Miriam: Only it matters, and we want to style everything from it down. When you do these workarounds, you're hitting every card element, and if there's any card outside of your context.

Dave: Mm-hmm.

Miriam: If you're nested. If you're nesting these things, his workaround stops working.

Chris: I see. Yeah, that makes sense.

Miriam: But the basics get there.

Dave: It's tricky. Yeah.

Chris: That's good, though. To just say, "We can do that anyway," because that was my initial privileged white boy technique was, "Why do we need scope? That's just a selector. That is scope."

You're like, "Um... It's a little more complicated than that."


Miriam: It has a lot of overlap with nesting in the sense of actually styling elements inside other elements. But it really gets more to the point.

In my mind, it should replace most nesting. Scope actually says the thing that we mean, which is, "Find the element. Find its context. Ignore whether it's nested in other things. Just find that donut and style it."

I think, yeah, a lot of the things you can do with scope you could do with nesting, but scope is probably the more proper solution.

Chris: Isn't there some specificity? When you scope and then you select a single class within another single class, you haven't doubled the specificity, or have you?

Miriam: Right.

Chris: When you're nesting, you have because now there are two class selectors applying to it.

Miriam: By default, the scope specificity isn't added to the selectors inside, the specificity of the scope selector. You're selecting sort of three things here in an @scope rule. You're selecting the scope roots.

Chris: Yeah.

Miriam: It goes through, and it finds all of those. Then you're selecting inside of those any scope boundaries, any lower boundaries like the card content.

Chris: Yeah.

Miriam: You've selected those two things, and then you're looking between them in the fragments of DOM that remain, and you apply your other selectors in there. You've got three selectors going on.

Chris: Right, or two if you don't care about the lower boundary.

Miriam: Right. But they're sort of separate in a way that nested selectors aren't. Nested selectors don't have the concept of, like, "First, we're going to find a root. Then we're going to associate the thing to it."

But by default, the root selector is not added to the specificity of the selectors inside. You can get that behavior by using the ampersand.

Chris: Oh, ampersand is meaningful inside of scope?

Miriam: Yep.

Chris: Like it is in nesting? Oh, my gosh. I did not know that. Cool.

Miriam: And it does the same thing. It pulls in the parent selector.

Chris: Yeah. Huh.

Miriam: Then that would apply its specificity as well.

Chris: I liked what you said. Scope is what you mean. [Laughter]

Miriam: Right.

Chris: Which I do like that. I think that's meaningful when authoring code is that you should use the technology that expresses what you're trying to do, not just a tool that just happens to work historically.


Miriam: Well, and that's not just a value judgment, like it's a best practice. [Laughter] But it's what a declarative language is. We're using a declarative language. The purpose of a declarative language is that you say what you mean, and then the language figures out a good way to do it.

Chris: Yeah.

Miriam: If we're going to write a declarative language, we should try to say what we mean, I think.

Chris: I like it.

Dave: I mean it took 20 years, but yeah, I think... [Laughter] I think it's good to expand the idioms we have for expressing what we mean. I think it's great.


Chris: I want to ask you about CSS Functions. But before we get there, just to keep the at train rolling for a minute, I happen to be at a conference recently, and I was talking with Jessica Januik there who really wanted to do a CSS proposal, and Lea was there too. She was like, "We can work together," or at least give you a little juice for it.

Her idea was exit animations. The idea was that we have starting style - yet another at property in CSS. Pretty neat one that let's say you're going to add a transition to a list item or something. You could give it a starting style of opacity zero. Then the list naturally has opacity one, and it'll look like it fades in when it arrives on the page, which is extremely useful for things arriving that weren't in the DOM before and now are. That's great.

What about things that are in the DOM that are about not to be, like the exact reverse thing? So, the proposal was, if we have starting style, can we have exiting style or something like that? This does not exist in CSS yet. This is a GitHub issue. I don't even know if you call it a proposal. Is it a proposal as soon as it's an issue?

Miriam: Yeah, it's a proposal. Yeah.

Chris: Sure, proposal. Yeah.

Miriam: It's a great proposal.

Chris: Do you take a peek? Look at that. It's already great!

Miriam: Yeah. I like it.

Chris: See. Miriam says it's good.


Miriam: I guess implementers have some concerns about having control over things that you've removed from the DOM.

Chris: Mm-hmm.

Miriam: They're sort of like, "You removed it. Why do you want to keep styling it?" Or "How dangerous is it to be able to keep manipulating things you've removed?"

I don't know where that's going to end up, whether it's doable, whether browsers are going to go for it. But I love the idea.

Chris: Hmm... Yeah, it's a big maybe. Yeah, I can see lots of concerns about that. I saw Adam brought up, like, "What if you're not removing it, you're just moving it?"

Miriam: Right.

Chris: Is that--? How do you even talk about that? I have no idea. What if you don't call .remove, but you call .remove three parents up or something? How would it know? I don't know.

There are probably lots of what-ifs, but I feel like it can't be as hard as container queries was, right?

Miriam: You mean we can wait 15 years and then maybe we'll get it?

Chris: Yeah. [Laughter] I have 15 minutes, unfortunately. That's all I have.

Anyway, it could be cool. Maybe it will end up as an at function, @rule. God, there are so many words to know.

Dave: I feel like this is one of the ones where you could just walk over to Microsoft and be like, "Hey, Alex. Cool, huh? Wouldn't it be cool if you had this?"


Dave: Then they would be like, "Yes, $1 billion, we're doing it." So, that's it.

Miriam: It is often how these things get solved is some browser decides to try it.

Dave: Yep. You just need the gumption.


Chris: It is surprising. Dave, for a moment, you were a part of the OpenUI group. I saw one just the other day of some DOM attributes called Invoke Target and Invoke Action, or something. You just put them on an HTML element.

Dave: Yeah.

Chris: For example, on a button element, you could say, "Invoke target," and then ident. That's what they call it. A fancy way to say ID, I guess.

Then let's say you had an H1 tag just somewhere else in the DOM that had an ID that matched that. It's kind of like you're saying, "I want to invoke an action on that thing specifically, not just a click that you just have to watch for the click and then do whatever you're going to do with the click."

You're saying, "I want to do an action on that," and you can give it some kind of value to give it, too. Like, "I want to do an action," and that action is foo.

Dave: Mm-hmm.

Chris: Then, "If the action was foo, then do something." You're like, "Oh, wow. That's cool." It's a little bit like Alpine or Vue directives or something but just in HTML.

Dave: Yeah.

Chris: It's just in Chrome. I mean Chrome Canary.

Dave: Okay, yeah.

Chris: They just ship experiments. Then you can just use it. Then they pull them out, which they have to do because otherwise, we have a bad Internet.

Dave: No. It seems weird. Maybe even Firefox is going to do it, too. Did I read that? I don't know. But yeah, I think the classic case would be button, invoke target, my modal. Then invoke action. Is that the right one?

Chris: Yeah, I think so.

Dave: It'd show modal, because modal has open, close, and show modal. Bless this mess.

Chris: Oh, it's how you could make one button one and one modal, regardless of where they are in the DOM, be one-to-one with each other. That's pretty sweet, actually.

Dave: Yeah. Yeah, you don't use JavaScript. You just go bloop, and then--

Chris: Declarative, you might say.

Miriam: Mm-hmm.

Dave: Declarative words.

Chris: Speaking of CSS Proposals, when Miriam rolls in with a proposal, it's like 9,000 words.



Chris: The new one is CSS Functions. I only saw it because I think you posted it on OddBird or something, an early, like, "Here is all my thinking on CSS Functions." What's up with that? Tell me.

Miriam: Yeah, I mean it's very early. There have already been threads. As you would expect, people have talked about functions and mixins.

More and more, we're pulling things over from the preprocessors, and those are some of the remaining pieces, so there's been a lot of discussion. I just went through all those discussions and tried to--

Chris: Right, like Sass had functions, so maybe we should have them?

Miriam: Yeah. The difference between functions and mixins, I mean they look sort of similar, but a function works at the value level. Inside of a property, you want to do some math or whatever and get the result back inside a value.

Chris: Yeah, okay.

Miriam: Mixins work at the sort of declaration ruleset level.

Chris: Like here's a whole chunk of CSS that I'm going to put in here.

Miriam: Right. That's the main difference. And I just looked over both of those and tried to write up what I found and propose a potential path forward.

Chris: They can both take parameters, like arbitrary parameters, right?

Miriam: Yeah, that's the idea. You have some amount of logic wrapped up in a place, and you can pass in parameters, arguments, and then do something with those and return a value or a set of declarations.

Chris: Nice. I always had one for scrollbar styles because remember there are the ones that work in Firefox, like the standard ones, and then there are all the WebKit ones, which you have to use even if you don't want to because they're the only ones that work in WebKit browsers. That's a chunk of CSS.

Miriam: Mm-hmm.

Chris: It becomes a mixin, and I'd name the mixin like scrollbars or something. It would take maybe three parameters, like what's the background of the scrollbar itself, what's the color of the thumb (I think you call it), and then how wide is it - or something. You would take three parameters, and then you'd spit out all the CSS that's necessary for that. You could call it wherever because you can set that on the root, and then that affects the main scrollbar. But that doesn't affect scrollbars, like if you wanted to do something different in some sidebar or container where you're reading your email or who knows.

On CodePen, you can imagine we have scrollbars all over the place. Hence the mixin. But that's a pretty good use case, right? That's a mixin, not a function, because I need lots--

Miriam: Right.

Chris: I need different selectors and stuff, whereas you were saying a function is just a value.


Miriam: Yeah, it's just a value. Like calc is a function that just does the math for you and gives you back a value. Custom functions would be the same sort of idea. You use it inside of a property, so inside of color or background color.

Chris: Oh, I see.

Miriam: Whatever you call your color function, and it does some calculations - whatever - [laughter] to give you some... Yeah.

Chris: Yeah, that's cool. Maybe we'll get the new light-dark function, or one that--

Miriam: Right.

Chris: Remember there's supposed to be some kind of... Oh, I lost it. What is it? A color that picks the correct accessible color when you give it two colors.

Miriam: [Indiscernible]

Dave: Contrast?

Chris: Yeah.

Miriam: Yeah, color contrast.

Chris: It seemed like we were going to get it, but we didn't actually get it, I don't think. But you could write one, if this proposal was out.

Miriam: Right.

Chris: But do you have to write it in CSS, or could you write it in JavaScript or something?

Miriam: Yeah, you would write it in CSS. Part of the idea is that it overlaps with the Houdini proposal for custom functions you would write in JavaScript.

Chris: Oh...

Miriam: You would write a basic one in CSS if you want, and if you wanted to get more complex, you could move into JavaScript and do it there and do more complex things.

Chris: The truth is you can probably do some pretty fancy crap just in CSS alone, right? Every other day, I see something. I saw bubble sort in CSS the other day, and I was like, "Are you fricken' kidding me? What is happening." [Laughter]

Miriam: Right, and you can think of things like the sort of calc and clamp tricks that people use to get responsive typography the way they want. You could wrap those up in a function and make them look a lot neater, so you don't have to write out the whole calc every time.

Chris: Oh, I see.

Miriam: The math is wrapped up in the function.

Chris: Maybe from the creator, Suzie might have something to say about the usefulness of functions.

Miriam: You would think.

Chris: Yeah.

Miriam: We'll have to ask her.


Miriam: I mean, also, some of those things like color contrast. What's hard about the browser shipping it is they ship it once. They can't really change it down the road, and color contrast rules get better over time. That's not an issue if you're writing your own. You write your own, and then you change it when you want to change it.

Chris: That was kind of the thinking behind Houdini, too, right?

Miriam: Right.

Chris: R.I.P. I mean I don't know if it's actually dead, but it kind of seems like it.

Miriam: Yeah. It's at least not a whole cohesive project. It's little bits of projects that are coming through. Parts of it are shipping.

Dave: It's not dead yet. It's mostly dead.


Dave: [Indiscernible]

Chris: Got blood dribbling out of your mouth. "I'm not dead yet."

Dave: Not dead yet.


Dave: He's mostly dead.

Chris: But yeah, mixin is pretty cool. I did think when... What was it? We haven't talked about this--but I guess we should wrap it up pretty soon--the container-style queries. We didn't mention that during the show.

Miriam: Mm-hmm.

Chris: But that's a thing you can say, and I think it's kind of limited at the moment to if this selector ultimately has a CSS custom property applied to it, like foo=bar or foo:bar or something, then do something specifically.

I always thought, well, the most useful thing it could do is just say, "If that's the case, then apply these five things."

Miriam: Yes.

Chris: Instead of just one thing, like, "Okay, card style 1." Oh, that's the one that has lots of border-radius. It's purple. It has a border on the top. It has a box shadow. But card style 2 is orange.

You can do that because you're just setting one thing. That's a mixin, is it not?


Miriam: It's sort of mixin like it comes with a lot of restrictions. It's limited as a mixin because you're basically using the custom properties as parameters, but you can only define them once.

Chris: Hmm...

Miriam: You don't get to use the mixin multiple times in the same place. With some of those mixins, you don't need to. That's not going to matter.

You also get the restriction where it has to be querying a parent to affect a child because that's a container query restriction.

Dave: Mm-hmm.

Chris: Oh... Yeah, yeah.

Miriam: Again, you don't always want that restriction on a mixin. Mixins still would improve on it.

Chris: You can't even do sub... You can't nest more selectors, too, right?

Miriam: Yeah.

Chris: It affects that one thing only.

Miriam: Yeah.

Chris: I guess you could set a custom property.

Miriam: Yeah.

Chris: Oh, that would be--

Miriam: Well, inside of your container query, you could target lots of different selectors, so you could do some there.

Chris: Oh, okay. Ooh, gosh. That is really... If somebody was going to argue against the complexity of CSS, they would just point right to this and be like, "That. That's not good."

Miriam: Yeah. Yeah, I feel like style container queries were really designed for the case of, like, "I've got M's, the M element. I want it to be usually italic. But if the parent is already italic, give it a background instead."

Dave: Hmm...

Chris: Ah... But that didn't ship.

Miriam: But that only works... That didn't ship.

Chris: Yeah.

Miriam: Because browsers don't have good rules for querying normal properties. They don't all agree on how to serialize them.

Chris: Oh, really?

Miriam: Or what equality means in all those cases, so they weren't willing to do that because you'd have to go through 700 properties and define equality for all of them.

Chris: Oh, my gosh!

Miriam: It's a lot of work.

Chris: Oh, I did not know that that. That's fascinating. I have only recently learned that there are like ten different value types in CSS. There's what's in the style sheet. Then there's what happens after the style sheet is parsed. But then what if that value is a little weird or something? The browser can normalize it - or something. Then what actually gets applied to the page is different.

I don't know. There are all these different... Which one is it?! Which one are you checking against? Is it just what I wrote or is it what actually got applied to the DOM or what?

Miriam: Right. Yeah. In this case, for some of those use cases, you want different answers. Sometimes you want to say, "Is what I wrote equal to this?" and sometimes you want to say, "Which mode am I in?" I mean color scheme, light-dark. I set it to light-dark. Which one is being used? You want to query the used value not the specified value.

Chris: Used value, yeah, that's a special one.

Miriam: Yeah.

Chris: Yeah, that's tricky. I guess I can see why that didn't ship. Wah-wah. [Laughter]

Miriam: Wah-wah.

Chris: It's still cool. If all we ever got was the custom property one, it's still kind of cool. But at that point, you should almost rename it because it's not really a style query anymore. It's a custom property query.


Miriam: Yeah. Yeah, it's a custom property query. They're working on state queries now.

Chris: State queries, what's that?

Miriam: Yeah, so the first ones that they're working on are, "Is this position sticky and currently stuck? Is it in a stuck state?"

Dave: Yeah. Loving it.

Miriam: Is this in a snapping context and currently snapped?

Chris: Oh, wow. Yeah.

Miriam: Is this overflowing and currently--? Does it have overflow--?

Chris: So, they're states that already exist with some--

Miriam: Well, ways to query them now. Yeah.

Chris: Yeah, right. Stuck would be sweet. That's a good one.

Dave: Yeah.

Chris: Because even the little... There's a little snippet that everybody googles that has an intersection observer or something that figures it out for you.

Miriam: Yeah, Chrome Canary has a prototype of it. You can go play with stuck, stuck state query.

Chris: Oh, nice. What does it look like?

Miriam: @container.

Chris: Is it just ::stuck? Oh, no, it's a container deal?

Miriam: It's a container query, but you use the state function, so you could say @container state (stuck). Or I think you can say--

Dave: Stuck top.

Miriam: Stuck top or stuck bottom, yeah.

Chris: But how does that work if it's a parent? You can't style the thing that you're querying, so the thing that you're querying isn't stuck. It's the child that's stuck.

Miriam: Right, so it's like some of those cases where you need the extra wrapper on the card. You'd have to use that trick in some of those cases.

Chris: That's good, though. That's a good one. It's just amazing, you know? For a long time, people were like, "CSS is really poppin' off lately, amazing, right?" Then instead of it slowing down again and being like, "Woo, that was a crazy year the last couple of years."

Dave: Let's take a decade off. Yeah.

Chris: Yeah. Now it's staying just as fast.

Dave: Yeah, that's great.

Chris: Amazing. Well, it's good to have you on the show to be able to talk about these things.

Miriam: It's fun to be here.

Chris: Because holy cow, there's a lot of it. I'm glad you found a way to get yourself involved and get paid. [Laughter]

Miriam: [Laughter] Me too.

Chris: Yeah. [Laughter]

Dave: Yeah. Tis the season. Yeah, well, thank you, Miriam, so much for coming on the show. We really appreciate it. It's always good to see - I don't know - just get a recap of all the stuff I could be using or will hopefully be able to use in the future here. Very exciting times. Thank you for all your work that you do and proposing. I know it's got to be a brain-bender, so I appreciate all that work. Yeah.

Miriam: Yeah. Yeah, and we sort of don't get to get rid of nuance is the hard part of it. [Laughter]

Dave: No, well, if you need somebody to ruthlessly eliminate nuance, I can do that.

Miriam: Great.

Dave: I can come and bull in a China shop CSS and just start deleting things. That would be my job.


Miriam: I think that would be excellent. That would be a service.

Dave: It'd go over really well.

Miriam: [Laughter]

Dave: All right, well, great. Thank you so much. Thank you for coming on the show. For people who aren't following you and giving you money, how can they do that?

Miriam: Oh, go to Check out our work there. We're doing a lot of open-source work. You can help sponsor it or you can hire us to build your website or application or design system or whatever.

Dave: Nice.

Miriam: We've got a great team there, so check us out.

Dave: Cool. Awesome. Well, thank you so much. And thank you, dear listener, for downloading this in your podcatcher of choice. Be sure to star, heart, favorite it up. That's how people find out about the show.

Follow us on Mastodon... [mumbling]... And join us in the D-d-d-d-discord.


Chris: Yeah.


Chris: That's it.

Dave: Chris, do you got anything else you'd like to say?

Chris: I would. When animate to auto ships, please don't let it be too weird. It's looking real weird right now, and it just needs to normalize back down to what everybody wants, which is just animate zero to auto. No weird syntax. Okay, bye.