April 27th, 2026 ×
Writing Maintainable CSS
Wes Bos Host
Scott Tolinski Host
Transcript
Wes Bos
Welcome to Synapse. Today, we're talking about writing maintainable CSS, how to structure your project, how to write CSS so that you don't end up with just a dumpster fire of CSS that's impossible.
Wes Bos
Your website starts to rot over time.
Wes Bos
Randomly, you find like, the one thing that you can tell when a website has rotting CSS is you see, like, a Times New Roman sneak out or, like, a weird font that doesn't belong there. You know? It's just like, oh, man. You know that this is this is probably a mess inside.
Wes Bos
So how do you write maintainable, manageable CSS? What are some good approaches to do? What are some methods? As well as what about Tailwind utility frameworks, atomic CSS, stylex, component Scott CSS? There's different approaches to do. We're gonna talk through those as well as, maybe some tools to enforce that yourself. My name is Wes Bos. I'm a developer from Canada. With me is mister Scott Tolinski, absolute slop master of all CSS. Knows what he's talking about here. Yes.
Scott Tolinski
Yes. I I I have been there. I have been there, done that.
Scott Tolinski
Man, Wes, I I, speaking of non slop, I, went to dance yesterday, and it was my first dance practice in my forties.
Scott Tolinski
And boy Oh. Does, does that hit different.
Scott Tolinski
Boy, does that hit different. That's that's for sure. I'm feeling it.
Scott Tolinski
Oh.
Wes Bos
Oh, man. That's great.
Wes Bos
Alright. Let's get on into it. First of all, let's talk about what makes CSS manageable or or unmanageable, and then we're gonna go into the different methods and approaches that you can use as well as some tips as to how to write good CSS. So first of all, like like, what causes CSS to be a mess or or unmanageable? Right? Very high Vercel, CSS does not leak into other parts of the website. This is a very clear one. JS if you are writing some CSS and those styles are accidentally leaked to other parts of the website or those styles are so broad that you would not be able to take part of a website away. We're we'll we'll use the word component in this. You you should be able to take a component out of your website and render it on a white page, and it should still look mostly the same or entirely the same. Right? And and if that component only looks that way inside of a specific part of your website, you have a bit of a rat's nest of CSS.
Scott Tolinski
Yeah.
Scott Tolinski
Man.
Scott Tolinski
Which is something that I I feel like, you know, with the current landscape of how AI likes to write CSS and things like that, it it's definitely a code smell that I think a lot of people will have in their projects. Yeah.
Wes Bos
Yeah. I feel like it's it's less of an issue these days as people most people are using something in their CSS. Instead of just having one big style dot CSS file and dumping a whole bunch of rules in there, I feel like it's a little bit more maintainable. Most people have some sort of idea of components and, hopefully, some way to to manage that CSS. But even with those things in place, it can still get out of hand.
Scott Tolinski
Yeah. And and I think a bigger concern these days is having every single component as a tight unit that if you do adjust anything JS a global anything, then that tight unit will remain in the old style of things. Right? It's like a lack of the cascade
Wes Bos
is a huge problem. The tight units are a problem.
Scott Tolinski
Tight units.
Wes Bos
Another thing, what makes me CSS maintainable is is it easy to maintain? Updates, edits, this includes being able to find the actual thing because there are certainly lots of CSS approaches out there that are so stringent and so hard to use that people end up not being able to to to do what they want. Right? And you you're you're baked into this is kinda thing with, like, design systems as well. With larger companies, you need the larger the company, the more places that it touches, you need a more strict design system so that you can enforce these things across the thing. And that always comes with a trade off of, like, I'm not actually able to like, a good design system will let you do whatever it is that you want. But there certainly is this other spot where if it's too stringent, you're not able to actually implement the design that you're you're looking for.
Wes Bos
And then that causes people to sort of step outside and then just quickly do a little hack here and there, and then voila, a year later, you have quite a bit of rot in your code base. Yeah. Yeah. Totally.
Scott Tolinski
That's a problem that I have. I'm really good at designing a system, but less good at designing individual unique elements.
Scott Tolinski
So for me, my stuff can feel like it's soulless in a system.
Scott Tolinski
Mhmm. But I I I am afraid.
Scott Tolinski
I'm afraid, a fire bad, of of of doing a,
Wes Bos
you know I think we're the leading gang of Wes. We are. You are you're the the system guy.
Wes Bos
And I love a good system, but I also sometimes find it, like, I just wanna set a freaking font size on this thing. And it's the the font size is this, like, 92 line clamp function Wes I can't figure it out.
Wes Bos
And and I think, like, those are fine for 90% of use cases, but you should still have a maintainable way to sort of break outside. Even on the syntax website, I think we ended up we have have that those font sizes for most things, but I added a couple Sanity classes for simply just changing the font size to something that Wes, outside of that clamp function.
Scott Tolinski
Yeah. Yeah. Totally. For good CSS to to be maintainable, it has to be reusable. And this has gotten different now with components, scoping things to components, because many times that unit of what is reusable can just be in a component rather than just a class or this or that. But CSS should not be a one off solution. I actually have this kind of, same thing listed as global solutions, instead of local solutions. Wes I say global, I don't mean in a global dot CSS file that gets imported everywhere. What I mean is that, like, the table CSS shouldn't live in the page admin table component. It should live in a more generic, reusable component and or class, that is then able to be then used anytime you have a table. Yes.
Wes Bos
Yes. Exactly. And what that ends up looking like is you you find yourself reimplementing a lot of the base elements in in HTML. Right? You you find yourself reimplementing a heading component.
Wes Bos
Obviously, a table is a a very common one, you know, like, maybe a a section because, like, those are your base cases that you can then pass in arguments or overwrite values with with variables.
Wes Bos
Now here's one dot that I have with a lot of CSS that people have is that your CSS needs to embrace the flex. And and what I mean by this is writing good CSS means that your CSS will adapt to breakpoints, container sizes, different types of content wrapping without too much extra code.
Wes Bos
Often what I'll see is people are simply just reimplementing the CSS for every single breakpoint, or Yeah. They have they have to duplicate their HTML because it's it's so different in from one to another.
Wes Bos
Where writing media queries and container queries and all that stuff, that is fine, but your media queries should not have to, like, write every single selector and reimplement absolutely everything JS that they should be flexible enough that when things change, when a component is in a space that has more width or height or when a when a breakpoint is much smaller than larger, that the contents will sort of just flex to them. You don't even have to write media queries. Or if you are writing media queries, you are writing container queries. A lot of that work is simply just updating variables. Alright. At at this breakpoint, I'm going down to three columns, and I'm changing the the font size to be something slightly different, right, rather than having to just, like, write every single selector again. Because I hate debugging that CSS where it's just like, oh, I wanna edit this thing.
Wes Bos
Now I have to go through 11 different media queries, find all of the selectors. I prefer I prefer nesting my media queries inside of my CSS Same. Versus the other way around. But that's that's one thing. Especially, AI does that all the time, and I hate it. Yeah. Yeah. I I think this is one that,
Scott Tolinski
man, it's hard to wrap your head around these types of things sometimes because it's so easy to read a media query where it's like, at this, it's this. At this, it's this. At this, it's this. Rather than Yeah. Building more flexible systems that adapt. The things that you would use there are what? Like, min max Yep.
Wes Bos
Auto fit, autofill, and grid Clamp. Flex flap, clamp. That's a really good one.
Wes Bos
There's quite a few little things where if you can just learn how these all work, then you you might not even have to write any media queries.
Wes Bos
Yeah. I Grid, man. Grid has a just such an amazing capacity to adapt to its container. And can you explain your your clamp font sizing hack where, like, you don't even have to? Like, I'm I know I was rousing you earlier, but it actually makes a lot of sense because there are very few use cases where you need to make the font smaller, mobile when you use this approach. Yeah. So this is, my this is a fluid hyphen type dot Tolinski dot ski. This is a fluid type generator
Scott Tolinski
that I I built that everything is based off of math, ratios, and CLAMP.
Scott Tolinski
And, if we look at this, you have this massive clamp function where you have, a 16 pixel based, rem based, clamping function that basically says, here's what the font size is preferred to be at any given point, and then it's going to clamp down to a minimum for mobile. In this case, it's 14 pixels, for mobile at the viewport size of 400 and the maximum of 20 pixels at desktop size, and that's for the base level font, like your your paragraph font. Then at any given point, it's going to if it can be its maximum based on the viewport size, in this case, it will be its maximum.
Scott Tolinski
And at the minimum viewport size, it will be its minimum. But in between there, what it does is it picks the the point in the middle of all of that, making it just totally fluid. And it's funny. I actually have this be, container query based as well too. So you can have this be container query based or viewport based based on, how you how you choose. I have it Bos on a toggle. And then the way I also have it, because this is all just the base level font size, you can choose the font scale as well. So, like, what is that ratio between the two of these? Is that ratio is bigger than your font sizes at the larger end of the spectrum will be massive. Oh, that's cool. It's smaller, then that ratio ends up becoming smaller. And then you can tweak the baseline like, if you want your smallest font size to be 16, you can have that be 16 instead of whatever. So, check out this fluid type calculator because at the end of the day, what it spits out for you is just, man, a handful of lines of CSS that calculates all of this fluid type, fluid font based on CSS variables. This is what I tend to use for all of my font sizing. It it can, though, Wes, like, as you mentioned, it can become a a PIA if you just want a stinking font size. But if you're like, oh, I just want a system that looks nice, I I like this quite a bit. And, like, it's just mobile friendly already. You don't even have to think about it. Right? Like that Exactly. You don't have to slap any media queries in there. It just simply goes.
Scott Tolinski
And the scale is all relative, so it always
Wes Bos
looks like the same. Yeah. Yeah. I saw a tweet the other day. Someone said, why are we setting font size based on, like, pixels or rems or whatever? Why is it not why is everything just not line height? Because you have this, like, new value in CSS, like l h. Right? Mhmm. And we also have, like, c h and e x, which is the size of an pnpm x and the size of a what's c h? Is it a c? Oh, character height? Character height. Yeah. Yeah. Exactly. But, like, line height, sizing everything based on line height. That way, you get, like, a nice rhythm vertically. And I was like,
Scott Tolinski
I think that makes sense. I don't know why I've never tried that. There used to be come from focus to people don't know, there used to be this thing called Sass. There when when Sass came out, there was this thing called Compass, which is like a toolkit Yes. For Sass. And in that toolkit was vertical rhythm, which took line height and distributed the font size and put it all as if you would establish a vertical rhythm for your entire document, then it would make sure your text always fell into that vertical rhythm. I like that. And you could and if you were, like, doing, like, icons or something, you could snap them to the closest
Wes Bos
vertical rhythm with clamp. Right? Makes a lot of sense. I guess, like, lots of sense Node do that as well. But, yeah, kind of a neat approach. I'm gonna try it on my next project.
Scott Tolinski
Yeah. And if you want to see all of the errors in your application, you'll want to check out Sentry at sentry.io/syntax.
Scott Tolinski
You don't want a production application out there that, well, you have no visibility into in case something is blowing up, and you might not even know it. So head on over to century.io/syntax.
Scott Tolinski
Again, we've been using this tool for a long time, and it totally rules. Alright.
Wes Bos
Alright. So that I think, like, anything else that makes your your CSS unmanageable or unmaintainable?
Scott Tolinski
Things that make my CSS unmaintainable.
Scott Tolinski
I I think one of the bigger things that, we we've talked a little bit about being systems and reusable and stuff. Yeah. But it's using values instead of variables.
Scott Tolinski
I know we'll talk about using variables in a bit here, but there are some things that just straight up should be variables in my mind all the time.
Scott Tolinski
Fonts, font sizes, colors, shadows, those types of things. When you define them one off, especially with AI agents, you can have, next thing you know, 40 different shadow types in your site. And that's like a guaranteed way to make things Scott only unmaintainable, but also noncohesive in the way that it looks. Yeah. So, again, we're talking I I'm system guy. Right? So I I really love variables for everything, and I forbid them certain properties to have
Wes Bos
individual values set up that aren't a variable. Honestly, it's a great approach because as as soon as you introduce, like, eight different types of, like, gray borders in into your website, then and you wanna update it. Like, you wanna add dark mode, you know, or you wanna restyle your thing, you're just hunting through the website for all these different use cases. One kind of cool site is if you go on projectwallace.com and put put your site in, they will show you all of the colors that are used on a website. And it's kinda funny to, like, Scott pipe in a I think you go to, yeah, you go to the design tokens, and it it'll show you all the colors that are used on a website. If you type in several different websites, you're gonna hit upon some sites that, like, oh, I see that they've used the blue, but the blue has deviated because somebody used a color picker here. Someone used RGBA here versus somebody else used, like, HSL, and it's slightly different. And then it's just it's just deviated over time. And, I'm very happy looking at syntax.fm Wes there is one yellow, two yellows. There's a variable system for a bunch of different yellows. We just don't use them. Yeah. Oh, yeah. But Yeah. I mean, like, the the actual used yellow that we use for syntax JS the same across the board. And that way, we actually have theming in the syntax site. We can just change one variable, and the whole site will update.
Scott Tolinski
Yeah. And in that same regard about changing one variable and having the site update, I think, one thing that, is people using nonrelative things. Like, we have especially with colors nowadays, we have relative colors. Colors can be derived from other colors.
Scott Tolinski
Yep. Those types of systems, I think, often, end up being the most maintainable because even if you're using an opacity, right, if you you have, like, a transparent blue, people will define the blue, and then they'll define the parent blue instead of having the blue and then deriving the transparent blue from that blue. Right? You can get things out of sync that way.
Wes Bos
And if let's say you have, like, a, like, a purple, and then you want, like, a slightly brighter purple to put as, like, a border on a card, and then you want a slightly darker one for, like, a box shadow.
Wes Bos
Are you then sticking those in variables as Wes? Or are you sort of just computer? Okay. Good. Because you're not just Yeah. That's another thing AI loves to do JS just compute them in place. Because I had this rule. Yeah. Do not use any colors that are not, in variables. And then what it did is it's like, okay. It just took the variable and then used relative colors.
Wes Bos
Yeah. I I'm using it, but I'm just computing what I want from that. Yeah. Yeah. Right. Yeah. I I have,
Scott Tolinski
we we talked about this in the last episode, Wes, about nondeterministic tools or deterministic tools. StyleLint, blocks me from that. Yeah. So it says That's good. Specifically, if it's a color value and it's not a custom property as the value, then
Wes Bos
error out. Yeah. Yeah. That's that's good. You need to be very stringent with those types of things. Otherwise, it kinda gets away from you.
Wes Bos
Let's talk about methods and approaches.
Wes Bos
Right? Like, when what is not important is which system you pick. What is important is that you pick a system and you stick with it as close as you can. Because Mhmm. If you have a system and then you maybe use a different system here and you mix and match and then all of a sudden, they used to start to deviate from each other, that's where you can you can run into trouble. So let's let's run through some of the more common approaches out there. So first one here is utility CSS.
Wes Bos
Most likely, everybody is using Tailwind for this type of thing Wes you have lots of classes that are associated with the different properties, different padding values.
Wes Bos
They're scoped a little bit smaller, meaning that you don't have access to the full gamut of of values, which is often good because then you have, like, six different kinds of shadows, or four different kinds of spacing. But then, of course, you can use computed properties to actually inject your own version in there as well. And, quite honestly, when I use Tailwind myself, I find myself using the computed values quite a bit because I don't I I find myself wanting, like, a little slice in between one of these values or setting up my own utility class extending it a little bit.
Wes Bos
With a utility CSS approach, the reusable reusability factor moves from, like, selectors to, like, components that are are reusable. Because, like, if you look at it, there's a bazillion classes on on an element, and then you find yourself going, oh, well, like, now I have two things on this page that need to look the same way.
Wes Bos
Mhmm. Am I just copy pasting it? Or sometimes people put the classes in, like, a variable, and then they use that. That that's a okay way to do it. But, generally, the approach to this is instead of creating a selector somewhere with your CSS, you're simply just making a component that has all of those reusable components on. It's not my favorite approach. I've certainly used it in I don't know. I have three or four websites that use it, but lots of people absolutely love this approach.
Scott Tolinski
Yeah. I think people like it because it solves scoping for them because they're using component flows. They're scoping their CSS. They're not having to worry about classes and leaking and those types of things. They like it because there's a system.
Scott Tolinski
But, again, yeah, I I I find it's just like a shorthand, like a CSS shorthand.
Scott Tolinski
Yeah. And to me, personally, yeah, that's why I don't I don't personally use it, but I get why people like it. It it does it makes it easier to have a a system in place.
Scott Tolinski
You have atomic CSS as being a separate thing in here as to utility CSS. I've always seen those as the same thing, but I don't, have any strong feelings there. Do or do you see them as being different? Honestly, I don't I don't either. Atomic CSS is the same
Wes Bos
idea. Right? You have these small classes that simply do one thing. It changes the border color. It changes the width of the element.
Wes Bos
Node. CSS is very big in this regard, and it differs from Tailwind in that Tailwind is is somewhat opinionated with with what you can do with it, which is good because then it stops people from making a mess with with everything. Right? Like, it it it scopes down what you can change on your, on your selectors. With with atomic CSS, you can essentially build your own Tailwind. So if you don't like the way that Tailwind does something or if you don't like the fact that it doesn't have, the ability to do a certain pixel value, you can you can go and build your own little, thing with Node CSS.
Wes Bos
And, it's pretty cool. It uses lightning CSS. It's from Ant Fu, who's the creator of absolutely everything.
Wes Bos
And, yeah, it's pretty cool. I'm I'm looking at this and thinking, that'd be kinda cool to build my own, but I don't think I ever will. I I prefer we'll get to what I prefer, but, I I like a utility CSS as a sprinkle on top for common use cases Mhmm. For things that I wanna do, you know, changing the font size, maybe margins here or there, but I don't like it for for absolutely everything. I rather have a selector that I can reuse throughout my my code base. Yeah. Next, we have
Scott Tolinski
style x, which this one this is is this a React specific thing? I think it is. No? It is from Facebook, though.
Wes Bos
Okay. It's like style JSX, I guess. We did a show on it quite a while ago called why is Facebook's CSS such a mess? Because if you inspect element on any Facebook property, you're going to see just generated class names. And if you look at those generated class names, you'll see that every single one of those generated class names, it'll be like x four h two f, and that will be related to, like, border bottom red. And that's not how it's actually authored. That is simply the what Stylex does is it takes in kind of like your traditional, CSS Wes you you write, like, a you don't write a class. You write it in line in a JavaScript object, and then you you apply all the styles that you want. You know? You can apply font size and border and padding and all of that stuff, and then it will take all of those for your from your entire project and go, oh, they used margin 40 pixel in 19 times throughout this entire website. I'm gonna replace that with one single class called b f r l o l 69.
Wes Bos
And then so if if you look at Facebook's source code, people are like, who would write code this way? They're not. They're not authoring that at all. They're simply just writing the CSS in line as JavaScript objects on their components, and then they have a a build step that sort of takes that out. And, the benefit to that is that you never write the same line of CSS twice. You never ship the same line of CSS twice. You could use margin 40 pixels a thousand times throughout your website, and you're only ever shipping one selector and one property value for that.
Scott Tolinski
Yeah. Yeah.
Scott Tolinski
I got I gotta say there's there's a large parts of StyleX syntax that I just can't I can't be I I hit it. Right? The media queries the media queries syntax in this because yeah. Because it yeah. You're writing it as a JavaScript object, which already sucks because No thanks. No thanks. Yeah. But then you look at the the media query syntax, and it is just, what are we doing here? So, yeah, it's it's bizarre.
Scott Tolinski
It's not for me. I'll just say that. And you you think about, like,
Wes Bos
container queries, and now we have style queries and Right. Like, nesting and all that. It's just like, this is not the right way to build it. One kinda interesting spot is if you are interested in this sort of area, Panda CSS has kind of the same idea, but they have multiple ways to write it. So you can write it in CSS modules, or you can write it in line.
Wes Bos
And then, again, they just parse it all out for you. So Panda CSS is a is a really nice approach. I quite like this one myself.
Scott Tolinski
Yeah. Yeah. Next is component Scott CSS. This is how I prefer to work. Now, Vue JS has component scoped CSS.
Scott Tolinski
Svelte has component scoped CSS.
Scott Tolinski
Back when I used CSS and JS like styled components, I wrote it in a way that was just scoped to my component.
Scott Tolinski
I I adore this way of working because you can target elements without having class names and things like that. You can, your CSS becomes scoped to the component that you're authoring the the CSS in. That way, you can have a layer of base CSS that's global. You can have local CSS that doesn't leak anywhere.
Scott Tolinski
You don't have to come up with a thousand different classes for naming things. That's the best. It's the best. And it's only gonna get better because we're getting native, scoping in CSS.
Scott Tolinski
Therefore, you can, not rely on your JavaScript framework to do that scoping. You can use the scope and then scope to a class or anything like that and then have that type.
Wes Bos
Wes. Yeah. This honestly, this is the one thing that I miss from when I'm not doing a Svelte project. And it's like, I just wanna put a style tag in the same file as my my component. And and that's why people like Tailwind so much as well is because I go to the component that I'm working on, and what it looks like, how it's styled, and often the actual, like, logic behind how it works is often in the same file. And it's it's beautiful. I I absolutely love it. And, like, you can simply just write very bare selector, like, div or strong, and you don't have to, like, come up with, like, a crazy name for it. And I love that approach, to this. The one thing I don't like about this component Scott CSS is when you have a component and you have some CSS in there and then you nest a component inside that's maybe two or three levels down and you say, okay.
Wes Bos
When like, let's say, for example, I have, like, a tag and it's inside of, like, a a show card. And I say, I want the tag to be red in this case. There's no way to, like, select the child component without having to use the weird, like, colon global thing, or you would have to, like, pass down a prop from the parent to the child and then then your prop drilling, which which I don't like as well.
Wes Bos
So sometimes I just wanna simply just say, yeah. When there's a child that has, ideally, by the component name or maybe by the class name, that you could have. That's that is something that CSS modules does support, which is really cool.
Scott Tolinski
Yeah. Yeah. It's, it's I I agree on all all those cases. The nice thing about this flow in general is that you get access to all of CSS in an ergonomic syntax where, like, if you're using something like StyleLint or even Tailwind, you have to have them I mean, you can obviously write normal CSS when you write Tailwind.
Scott Tolinski
But, like, if you're going all in on their classes, you have to learn their their version of doing things, whether that is container queries or whatever. CSS just got it available from day one. If the moment it's available in the browsers, you got it. It's available to you. And any tools
Wes Bos
that are are therefore working with CSS generally work immediately with this because it's it's just CSS. Right? CSS modules has been one that's been around forever. The way that this works is that you write your CSS in a separate dot CSS file, and then you import the classes from that CSS file in your your JavaScript. So, maybe I'll have a a footer, and then I will import the footer styles from that. And then what that turns into in your bundling step is like a, like, a class name that's associated with those scope styles, and then you can apply that class to your footer.
Wes Bos
And then if you have other elements, the one thing I don't like about it is if you have other elements. Like, let's say you have, like, a footer header, then you have to also import the footer footer header, styles from that one. You can't just simply just, like, use nesting. I get it because, like, you can get in trouble with writing very deeply nested CSS, and they much prefer you to say, no. Let me just write this top level scope CSS that is not dependent on any of its parents. But sometimes, I just wanna select the h three inside of my footer without having to do all these jumping around, which is why I like the the Svelte or the Scott CSS approach so much more. I use CSS modules on my own personal website.
Wes Bos
I I moved it over, I don't know, maybe a year or two ago, and I've been I've I've been, like, a 91% happy with it. And, I think the only I don't like about it is that I have separate files,
Scott Tolinski
and I'd much rather have the CSS and the component in the same file. Yeah. It's one of the reasons why I like the single file component thing, but then that has its own trade offs, which
Wes Bos
yeah. Yeah. Like like, let's say you want two different components, but you wanna share the CSS. Like, what what do you do in that case? Can you import external CSS in Svelte? Or Yeah. Or yeah. You just import an external file. No problem. Yeah. And then it scopes it to that that value there? I don't know if it scopes it. I don't know if it scopes it. I think it just is global CSS. Yeah. That's actually Yeah. See, that's that's sucks, because I'm like, I want this scope. But then so what you have to do then is you have to make a component that is reusable, and then that component needs to be extended Yes. On the two different use cases. And then it's it's a problem. I don't find that I hit that that often, though. Do you? No. No. I don't. No. No. It's very what else is there? CSS modules we talked about. There's so many other methods. CSS and JS Wes very popular.
Wes Bos
Panda is technically CSS in JS, but it's not a runtime thing, which is is great. That's a style components Wes a runtime thing, which at the time, it was great because you could use your JavaScript values inside your CSS, but then you have all this rendering overhead. So Panda is is simply a build time thing, mean meaning that it will you write them in your JavaScript, but it will strip out those styles, and and you don't actually have to they're not calculated every single time your component rerenders. Right. Yeah. BEM was really popular. SMACS, object oriented CSS.
Wes Bos
These are all approaches to build things that were scoped, that were composable. You Node? Like, if you have a button, and then you want a button that is big and a button that is red or a button that is a warning, you can compose these things together to to build what you want. They are all really necessary.
Scott Tolinski
Yeah. BEM was really necessary because we didn't have components. You didn't have scoping in that kind of way. And it was block element modifier. It was a system for devising names for things.
Scott Tolinski
Again, we we had to name things in this sort of way, in a way that was, like, a structured system, and it felt verbose to me.
Scott Tolinski
I did use BEM quite a bit in the past, but I I haven't reached for BEM in a really long time.
Wes Bos
Me neither. And for some reason, my AI always tries to get me to use it, and I was like, no. Like, I don't I don't need this anymore. You know? But, like, do do you remember what the BEM methodology was? Like, if I were to ask you to write a BEM selector right now?
Scott Tolinski
I remember there was hyphens and underscores.
Scott Tolinski
The block is like a component.
Scott Tolinski
Right? Or block is a collection of components, maybe, like, feature? Like a component like a card or a footer or something like that. And then the element is the individual element, and then the modifier would be like an is active. But what I don't know is, like, what's the underscores and what's the hyphens? It's been a while. Yeah. It would be like like footer JS your block. Underscore underscore
Wes Bos
heading would be like a footer heading, and then a modifier would be, like, invalid or on sale. And that was the dash dash value there. And and people love that because in SAS, you could nest your selectors, and they would just chain them into one big one. And you can't do that in in regular CSS nesting, which you also probably shouldn't do that because it's not statically analyzable.
Scott Tolinski
I used the life out of that. Yes. I did. Yeah. BEM was the greatest. Big fan, but no
Wes Bos
longer. Tips.
Wes Bos
Let's talk about writing writing CSS and good tips.
Wes Bos
A good global CSS. We talk so much about, like, scope your styles, make them tight, Scott repeatable.
Wes Bos
But then a lot of people who do that, they find themselves writing the same CSS over and over again, where in in reality, you should have a good base that includes some sort of normalize or reset. I really like the Josh Komu reset. I've been finding myself. I just copy paste that one every single time I start a project.
Wes Bos
And then that global base will have all of your your defaults for your typography, has a lot of your colors and your variables that are being used.
Wes Bos
Often, you should set your color scheme in there if you support light or dark or both.
Wes Bos
What other types of stuff is is, like, kinda globally done?
Scott Tolinski
Yeah. For me, I I I actually, Wes, I lean pretty hard on global CSS. So, I've talked about this a number of times on our show. I lean so hard into to global CSS that I wrote my own, UI library, Graffiti, which has a lot of, global CSS. So I do all my typography. But I also like, at what point JS your variable system? Your variable system feels like that is global CSS to me, because that's usually included everywhere.
Wes Bos
I think so. If I'm defining a variable, I either define it globally because it needs to be throughout the entire thing, and and those are generally, like, font sizes, colors, etcetera, or you do it at a, like, a component Vercel. Or you do you do your component variables globally as default, and then your components can simply just overwrite those variables.
Wes Bos
If if you're asking me,
Scott Tolinski
a a good global CSS should mean that with just elements and no classes, you should be able to have decent looking forms. Like, your form should look like all of your form elements should look good. All of the base level elements should match your theme. And if you were to just write HTML Node classes, it should look good. Okay. Node to me, that's what a base level CSS should do. And then everything else on top of there JS, like, icing on the component cake there.
Wes Bos
A lot of people say the opposite where your CSS should be simply just stripped out.
Wes Bos
That's what, like, the tailwind pre fit flight does JS it it goes even further in than normalize, and it takes off all the styles. So you put an h three in there, you can't tell the difference from an h three to a paragraph tag. I think I agree with you as well, but I certainly do hit cases where I'm just like, ah, now I have to undo Yeah. All of the stuff that you added to my table because I don't want that. And it can be Deno, though, with, one used property in CSS people don't know a lot about is the unset all. And that will simply just take all the properties that were applied to it and and unset them and and bring it back to the base. It's a little bit of a pain in the butt every now and then because I find that that overrides some of my specificity,
Scott Tolinski
but it's fine. I would I will say Wes I Sanity looks good, I mean, it looks like if you were having, like, a blank page, it shouldn't have a lot of character. It should look good good within your system. Because I think one of the things that people fall into the trap of is is really finally having to tune every single component just to have it look good rather than having a system that looks good and using the tuning to tune. So that's just mine. But I again, that yeah. That's definitely, like, a a preference thing. I agree, actually. Because when I used to do, like, WordPress themes, I would
Wes Bos
at one point, I was stripping all the styles, and then I would just build them all up again. And then what would happen is the the client would, like, go in the WYSIWYG and add some content, like a like a UL nested inside of an Wes, or, like, they would do some case where I didn't account for that. Mhmm. And and then I was, oh, I didn't I didn't account for that type of content. Right? If you're stripping out all of the browser styles, you better, like, make sure you put them all back. Otherwise, you're gonna hit some weird use case, some markup that you didn't account for, and it's gonna look weird. Yeah. Yeah. Variables.
Scott Tolinski
Yes. I, man, variables are great in modern CSS.
Scott Tolinski
And for people who Node because in SAS, it was a build time thing. In CSS, these things are updated live. You can think about your props. Right? You change your prop, your component updates. So with CSS variables, you change your variable, it updates. You change it at its parent level, it nests down like the cascade. It cascades down. There are so many wonderful things about variables. They can be used to then generate other things like colors.
Scott Tolinski
They can be used in calc to be able to have relative systems of spacing and stuff like that.
Scott Tolinski
I define all of my variables at a root level, using the colon root pseudo selector and then override where needed.
Scott Tolinski
I think an underused feature of CSS variables is the at property definition.
Scott Tolinski
At property allows you to get a little bit more control over some of your variables.
Scott Tolinski
This is like defining a type for it.
Scott Tolinski
People often say that's great. Animated. Right? And yeah. Because now you know exactly what type it is. It's not just like a string. But I think one of the things that people don't use very much is the inherits value in at property.
Scott Tolinski
Inherits can be true or false, and that means that if, like, for instance, if I'm building I use this in graffiti. If you have a a a gap, if you have a a a layout class and you have two elements inside of there and you set the gap on the parent, and then you have another layout that's nested inside of that without the inherits on here, inherits false, this gap would then cascade down to the other gap. So you set a cap here. That gap is now big on any children and any children children and any children children. And if you have inherit set to false, it doesn't cascade down. Therefore, it gives you the ability to still use variables to control, essentially, properties or props on on elements or components without having to worry about that cascading downwards effect, which, again, I think underutilized.
Wes Bos
Scott true. Like, the gap one is a really good example because if you have, like, a layout and then your entire site layout oh, I wanna change the gap on the layout, right, to 10 pixels.
Wes Bos
If without that, you all you just change the gap for everything else, and then you have to go in back and set it back on the all the other ones. So and, also, for things like like in CSS, there's many properties, like like, top right, bottom left.
Wes Bos
What are other things? Like, padding, margin, borders.
Wes Bos
These things don't necessarily inherit. When you set a a border on an element,
Scott Tolinski
all of its childrens don't automatically inherit that value. Right? Right. So Yes. You wanna use this. And it allows you to build relative systems without having to worry about, like, cascading downwards effects. It's great. Yes. I put everything in variables, by the way, folks. I put everything, any type of thing. It's in variables. So
Wes Bos
It's all there. Another thing you can use in CSS that is, I think, severely underused is, CSS layers. What this allows you to do is you can essentially take your CSS and and put it into a specific layer.
Wes Bos
And this may be a a reset layer, a default layer, an animations layer, and then you can control the order in which the that CSS applied in the cascade.
Wes Bos
So if you have ever fought with the the wrong CSS being applied over one or the other, it is so much easier to simply just stick them in a layer and explicitly tell the browser, apply them in this order.
Wes Bos
And Tailwind four uses what uses CSS layers as Wes. So you're you're starting to see it quite a bit be applied to it. And especially also if you have, like if you're writing some, like, customization. Right? You may have a base theme, and then you wanna, like, add a bit of customization to overwrite some of those values. Just make another layer, tack that on the end, and you know that that CSS is gonna be applied over top of the existing one. You don't have to start fighting with crazy specificity selectors or, like, over you're you're like, oh, the dot heading didn't work. Let me just do h two dot heading. Now that's more specific.
Scott Tolinski
Yep.
Scott Tolinski
Yeah. I I I think, you know, that's one of those things that people can get really into trouble with with this JS, like, the moment they start applying overrides to the specificity tree to gain some sort of control, it's the same classic issue that we've talked about going back to day one of CSS. If you throw an important on something, it is a sign that there's something wrong. Like, an important is is not something you should be using. And, likewise, there are times when you start to write some really icky selectors, and and it's like, I don't wanna be doing this.
Scott Tolinski
That's a good sign that, like, a layer system layers could help you out in terms of, like, being able to actually gain control over that cascade, which I like CSS layers quite a bit. Yeah. Yeah. I was very sad to find out, though, that important still takes precedence
Wes Bos
over top of a layer.
Scott Tolinski
Important is just like, move out of the way. It's me. It's me time. Yes. Boss.
Wes Bos
Next up, we have scoping. So, again, not a lot of people know this, but CSS, since December 2025, it's been in Firefox, and it's it's been in the rest of the browsers for over a Yarn, almost two years in in many of them. We have CSS scoping.
Wes Bos
And what this allows you to do is, much like a layer, you can simply just say at scope, and you can give it a selector and then write all of your CSS inside of of that scope. And what it will do is it will simply just scope that to to that specific selector, and that allows you to you can write things like h three inside of there, and you don't have to worry. One cool thing about CSS scoping is, like, of course, you can just give it, like, a a a selector, which you're probably saying, well, how is that different than just using regular CSS nesting? But one neat thing you can do is if you pop a style tag inside of an element and simply just write at scope and write your CSS inside of there, it will automatically scope that CSS to the closest parent element.
Wes Bos
Meaning that, like, we're just talking with Scott about how I just want to write my CSS in the same file as my my markup, you can do that. You just simply need to you put you need to put a style tag in there, and then you need to write at scope.
Wes Bos
You don't have to provide a selector or anything like that. Just simply at scope, and you will then be able to apply all of the CSS to only the elements that exist inside of that element. And then you can also stop the scope by using something called donut scope, meaning that you can you can tell it where the scope starts, like a selector, but you can also tell it where the scope stops. And that's really handy JS if you're nesting cards.
Wes Bos
You can say, start the scope from the card, but then stop it at a card.
Wes Bos
Stop it at, like, the next card and and or or stop it at like, maybe you have a child element. Stop it at dot child. And then that way, your cast the cascade stops.
Scott Tolinski
Yeah. Yeah. Scoping is one of those things I think people will start to figure out that really helps them if they, pay attention to it because I it's great. It's a, API we've always wanted. It's native. Yeah. And it's so it's gonna be fun to see frameworks like Vue and Svelte eventually move over to native scoping CSS. It's like one less thing they'll have to support in their own platforms, which is great.
Scott Tolinski
We talked a little bit about tooling and enforcement.
Scott Tolinski
StyleLint is a great project for this because you can set up your rules, and those rules can, become something that is loud. Hey.
Scott Tolinski
You just defined a color with a variable or with a value instead of a variable.
Scott Tolinski
Go go make sure you don't do this. But it can also be extremely important when working in teams because we all know that everybody has a different idea of what CSS is. I've worked on teams where I'm just like and not this team to be clear because Wes and, CJ write good CSS. But I would just look at CSS and be like, I want to rewrite all of this. I I don't like any of this. But now you don't have to be the bad guy. If you have a tool like this, it can be the bad guy for you. Like, hey.
Scott Tolinski
Go fix this thing that you shouldn't have done. This is bad. Yeah.
Wes Bos
It gives you the error.
Wes Bos
Biome also has a CSS linter in it.
Wes Bos
There's an ESLint plug in. So, like, whatever your stack is, there likely is already a plug in that will allow you to to do these things. They're not all exactly the same. You might you may find that they leave it to be desired, and you wanna switch over to one of them. But having a tool like this in your code Bos is kinda key to stop you from from doing crazy stuff, especially when you have, like, dozens of people writing CSS in there. It's very hard to, like, enforce that, and nobody likes the guy who comes in, swings into the pull request, and then starts giving feedback. Yeah. Yeah. Right. Yes. Exactly.
Scott Tolinski
Cool. I don't I don't have too many other things here. I I do wanna stress, relative things are really helpful.
Scott Tolinski
And I've said this a number of times in here, but I think oftentimes, even in variants and things like that, what we do is we default to going straight to CSS properties.
Scott Tolinski
Like, one thing that, we didn't touch on when we talked about variants and and variables is that you could do something where a button is getting a background color of a variable, and then that variant could then change the variable, not the background color itself.
Scott Tolinski
Because that variable can then be used for other relative systems, like you mentioned, the border radius, the box shadow, those types of things.
Scott Tolinski
And then, therefore, your variant code doesn't end up being a whole bunch of CSS property definitions. It's like a Node CSS custom property override, and that's it. That's
Wes Bos
that's so key. Because, like, sometimes I look at these things, and it's like, you just made variables for every single property that existed.
Wes Bos
And now instead of setting border, 10 pixel at red, I'm updating variables called border width, border color, border style. You know? And it's like you just reinvented CSS and and put them into variables.
Wes Bos
But if you can look at it in terms of a way that is computed where you're simply just changing one value or and one thing we didn't even talk about is, like, passing in CSS variables as, like, inline style values. If if you want a variant for something, a great way to do that is you can simply just pass in an inline style variable
Scott Tolinski
Yes. And then that will overwrite it and and compute its way out. I feel like I could talk about this stuff all day, Wes. Yeah. I feel like I could talk about it all day. But we don't have all day stuff. All day. We gotta wrap it up. Let us know down below
Wes Bos
what your tips are for writing maintainable CSS or maybe some of the worst CSS you've seen your coworkers write.
Wes Bos
Yes.
Wes Bos
Please.