I like this point that Jonathan Snook made on Twitter and I’ve been thinking about it non-stop because it describes something that’s really hard about writing CSS:
I feel like that tweet sounds either very shallow or very deep depending on how you look at it but in reality, I don't think any system, framework, or library really take this into consideration—especially in the context of maintainability.
— Snook (@snookca) February 26, 2019
In fact, I reckon this is the hardest thing about writing maintainable CSS in a large codebase. It’s an enormous problem in my day-to-day work and I reckon it’s what most technical debt in CSS eventually boils down to.
Let’s imagine we’re styling a checkbox, for example – that checkbox probably has a position on the page, some margins, and maybe other positioning styles, too. And that checkbox might be green but turns blue when you click it.
I think we can distinguish between these two types of styles as layout and appearance.
But writing good CSS requires keeping those two types of styles separated. That way, the checkbox styles can be reused time and time again without having to worry about how those positioning styles (like margin, padding or width) might come back to bite you.
At Gusto, we use Bootstrap’s grid system which is great because we can write HTML like this that explicitly separates these concerns like so:
<div class="row">
<div class="col-6">
<!-- Checkbox goes here -->
</div>
<div class="col-6">
<!-- Another element can be placed here -->
</div>
</div>
Otherwise, you might end up writing styles like this, which will end up with a ton of issues if those checkbox styles are reused in the future:
.checkbox {
width: 40%;
margin-bottom: 60px;
/* Other checkbox styles */
}
When I see code like this, my first thought is, “Why is the width 40%
– and 40% of what?” All of a sudden, I can see that this checkbox class is now dependent on some other bit of code that I don’t understand.
So I’ve begun to think about all CSS as fitting into one of those two buckets: appearance and layout. That’s important because I believe those two types of styles should almost never be baked into one set of styles or one class. Layout on the page should be one set of styles, and appearance (like what the checkbox actually looks like) should be in another. And whether you do that with HTML or a separate CSS class is up for debate.
The reason why this is an issue is that folks will constantly be trying to overwrite layout styles and that’s when we eventually wind up with a codebase that resembles a spaghetti monster. I think this distinction is super important to writing great CSS that scales properly. What do you think? Add a comment below!
Really great observation. I think the simplest (and thus best?) approach to this problem is to leverage CSS’s built-in inheritance system. My CTA button class tells my button how to look, and all CTAs that are children of my #hero section will have a 3rem margin-right (for example). That way you’re scoping your layout styles to the place a button is being used once, but the appearance styles for the button can be reused anywhere.
I would tend to advise against using extra HTML for this, though. Especially with today’s technology like CSS grid and flexbox, which allows us to declutter our markup to keep it super simple and semantic. One of the biggest downsides to stuff like Bootstrap is how many containers are necessary. I can’t imagine using extra HTML for layout styles on top of all the Bootstrap containers.
CSS’s native inheritance is a godsend that I don’t think is leveraged quite enough. Possibly from the whole “high-specificity selectors are bad” dogma; people think high-specificity is bad in general, without understanding the ways in which it can be used for bad. Separating appearance and layout styles is not one of those reasons.
Totally agree with you, specially when you say people avoid nesting selectors only because the common sense says it is a bad idea. That’s one of the reasons I couldn’t stick to BEM as well.
Couldn’t agree more. In my last role, I inherited a code base that had been through the hands of 3 different designers. It was an incredible mess. There were commented sections of the CSS file for each of the mentioned people each overwriting the others styles with ! important. I ended up scrapping the entire thing and starting from scratch.
I think snook’s smacss book (that’s hard to day!) is probably the most important writing on css I’ve ever seen.
To your point about width specifically, I like Nicole Sullivan’s quote to the effect of “never use the ccss width property outside of your grid”.
I’ve been thinking about this a bunch over the last year. I was calling them layout and aesthetic styles though.
I have some initial ideas put down in a conceptual framework called Moose. It aims to cover all areas of the front end though. I’d love to hear any opinions of it.
https://oose.blueflag.codes/docs/moose/introduction
i can not agree with u anymore
Hello,
Good approach for that is to adopte atomic design method :
http://atomicdesign.bradfrost.com/chapter-2/
I suppose this is where BEM helps, that checkbox with 40% width could have a class of “form__checkbox” which whilst not necessarily referring to its parent at least indicates that this is meant to be used in a ‘form’ block.
I agree with your point though.
I don’t know how front-enders stay sane without this ‘basic’ knowledge
But bootstrap? Time to move on, embrace the grid! :)
I agree! This is a problem I face, and then feel like I resolve, with every new project. My number one code bloat issue.
The closest that I’ve seen to a real outlined solution is the SMACSS style guide. I would suggest anyone interested just Google the word SMACSS. There’s a bit of a learning curve to it, but it more or less solves this issue – to the degree that you’re able to. I’ll be honest though, it can be tough to integrate it into every project as it can be overkill sometimes.
The biggest issues with style maintainability seem to center around information architecture–around categorization of styles and how those categories interact when composed on a particular HTML structure. It’s not just that the element needs the style, it’s also critical to understand why and whether it’s style essential to the element’s function or style that orchestrates the element’s relationship with another element. Which itself looks different depending on whether the element is a descendant part of a component or the root of a component. This is, of course, why many CSS in JS approaches bore me, seeming a decade out of date in a platform working on shipping CSS Custom Properties, Shadow DOM, and Named Parts. We still need some kind of CSS module, though, for this purpose.
Yes I think, this is crucial.
I always add a class name for different layouts on the body tag and then target the individual components inside that layout to add their size and position properties.
I also create section elements that can be reused for particular layouts, I can even make them “component-independent” by writing something like:
I like this!
I highly agree with this. All to often do I see inline styles doing things row and col could have accomplished.
I like the approach! It doesn’t solve the problem of splitting up CSS in a component-based approach though. Ideally from a maintenance perspective, I’d like single file components with styling included. So that when a component is removed, I don’t have to go look for ancestor components with layout styles that should be removed with it.
I’m also undecided on what’s better, defining layout in:
1. The nearest ancestor
2. A single layout file
3. One layout file for each layout
The size of the project can be decisive for the choice between 2 and 3, but not sure if 1 is maybe the most predictable.
I think Harry Roberts has made a really cool analogy for this.
I believe he said something like this:
See your components as books. You can order them in a bookshelf, the bookshelf provides a strong, beautiful structure to carry your books. Don’t try to arrange your books without a bookshelf, because that will end up in an unstable pile of different books in different sizes which will top over if you try to get one out of change anything.
The bookshelf is the CSS for layout, the books are your components.
Well put. I try my best to do that. After reading this, I will pay even more attention. Thank you :)