CSS is written slowly, line by line, and with each passing moment, we limit the space of what’s possible for our design system. Take this example:
body {
font-family: 'Proxima-Nova', sans-serif;
color: #333;
}
With just a couple of lines of CSS we’ve set the defaults for our entire codebase. Most elements (like paragraphs, lists and plain ol’ divs) will inherit these instructions. But what we rarely think about when we write CSS is that from here on out we’ll have to continuously override these rules if we want another typeface or color. And it’s those overrides that cause a lot of issues in terms of maintenance and scalability. And it’s those issues that cost us heartbreak, time and money.
In the example above that’s probably not an issue but I think in general we don’t recognize the true strength and dangers of the cascade and what it means to our design systems; most folks think that the cascade is designed to let us overwrite previous instructions but I would warn against that. Every time we override a style that is inherited we are making our codebase vastly more complex. How many hours have you spent inspecting an element and scrolled through each rule in order to understand why an element looks the way it does or how the long chain of inheritance has messed up your styles completely?
I think the reason for this is because we often don’t set the proper default styles up for our elements. And when we want to change the style of an element, instead of taking the time to question and refactor those default styles, we simply override them – making matters worse.
So I’ve been thinking a lot about how we ought to make a codebase that incentivizes us all to write better code and how to design our CSS so that it doesn’t encourage other people to make hacky classes to override things.
One of my favorite posts on this subject was written earlier this month by Brandon Smith where he describes the ways in which CSS can become so complicated (emphasis mine):
…never be more explicit than you need to be. Web pages are responsive by default. Writing good CSS means leveraging that fact instead of overriding it. Use percentages or viewport units instead of a media query if possible. Use min-width instead of width where you can. Think in terms of rules, in terms of what you really mean to say, instead of just adding properties until things look right. Try to get a feel for how the browser resolves layout and sizing, and make your changes and additions on top of that judiciously. Work with CSS, instead of against it.
One of Brandon’s suggestions is to avoid using the width
property altogether and to stick to max-width
or min-width
instead. Throughout that post he reminds us that whatever we’re building should sit between ranges, between one of two extremes. So here’s an example of a class with a bad default style:
.button {
width: 300px;
}
Is that button likely to be that width always, everywhere? On mobile? In every media query? In every state? I highly doubt it and in fact, I believe that this class is just the sort that’s begging to be overwritten with yet another class:
.button-thats-just-a-bit-bigger {
width: 310px;
}
That’s a silly example but I’ve seen code like this in a lot of teams – and it’s not because the person was writing bad code but because the system encouraged them to write bad code. Everyone is on a deadline for shipping a product and most folks don’t have the time or the inclination to dive into a large codebase and refactor those core default styles I mentioned. It’s easier to just keep writing CSS because it solves all of their problems immediately.
Along these lines, Jeremy Keith wrote about this issue just the other day:
Unlike a programming language that requires knowledge of loops, variables, and other concepts, CSS is pretty easy to pick up. Maybe it’s because of this that it has gained the reputation of being simple. It is simple in the sense of “not complex”, but that doesn’t mean it’s easy. Mistaking “simple” for “easy” will only lead to heartache.
I think that’s what’s happened with some programmers coming to CSS for the first time. They’ve heard it’s simple, so they assume it’s easy. But then when they try to use it, it doesn’t work. It must be the fault of the language because they know that they are smart, and this is supposed to be easy. So they blame the language. They say it’s broken. And so they try to “fix” it by making it conform to a more programmatic way of thinking.
I can’t help but think that they would be less frustrated if they would accept that CSS is not easy. Simple, yes, but not easy.
The reason why CSS is simple is because of the cascade, but it’s not as easy as we might first think because of the cascade, too. It’s those default styles that filter down into everything that is the biggest strength and greatest weakness of the language. And I don’t think JavaScript-based solutions will help with that as much as everyone argues to the contrary.
So what’s the solution? I think that by designing in a range, thinking between states and looking at each and every line of CSS as a suggestion instead of an absolute, unbreakable law is the first step forward. What’s the step after that? Container queries. Container queries. Container queries.
In my view a good idea is to follow a strict pattern, something like Atomic design. http://bradfrost.com/blog/post/atomic-web-design/
This way you create high level cascading classes that are designed as templates rather than a global thing as per your first example.
I mostly agree, but after some months using atomic, I still find kinda difficult to determine in which category some elements fall into.
This just reminds me that one of the most difficult things to do in developing interface is naming things… usually very similar elements cannot have the same name (or class) because they won’t share that much characteristics…
But I do agree that designing in a range could be the solution.
Isn’t even your first declaration (ie, body {font-family:…} overriding the default style sheet of the browser? This means everything is overriding something. I don’t think this is something to be concerned about.
I think the real issue you are actually facing is laziness/lack of skill with structure, or perhaps more likely, time requirements of production code override the personal requirements of perfection in code.
When you are producing a few websites a week, and the value of the sites is low, these kinds of things are trivial and a total non-issue, “overrides away my boys!” If you are working on one single site for a year… then redoing great sections of CSS over time works out the kinks.
Either way, still a non-problem, a temporary issue (with expected resolution in the future), or simply “not worth the budget to the client to make maintainable… cause we will redo their site in a year or two anyways…”
I feel that this is an important issue that a lot of people are struggling with. CSS has a tendency to grow into an unmaintainable mess. I try hard to only change what’s needed, and refactor when appropriate, but when time is short, or other people are editing the CSS, things get out of hand fast.
Also, good class names are hard, even when using stuff like BEM. I’ve been working a bit with CSS-in-JS, which solves some of these issues for me, but I’m not sure that is an appropriate solution in all circumstances.
I wonder if you are primarily a designer?
It would be interesting to see a poll on who has a hard time with keeping CSS clean vs who does not, based on technical interest or skills in design vs programming.
I thoroughly enjoy coding with CSS, and as half coder/half designer, I have never felt that CSS get’s messy or unwieldy, and this is not unique to CSS, check out http://thedailywtf.com/ for all sorts of messes in non-css code.
I suspect those have a hard time managing CSS in general, maybe are not primarily coders? I have no issues naming things, in fact, I enjoy this process, and have many naming tiers depending the value of the project (deadline * production budget / size of project + maintenance budget = which naming scheme to use)
I have a naming scheme for cheap sites with little to no maintenance requirements, and a different one for code bases that span many years of development. Why try to shoehorn in one scheme into every situation? Give yourself a break and the small projects, so you have mental space left for the big ones. :)
In my previous comment I address the type of project and the effects on maintenance (which decides naming scheme), but overall, budget, time, effort and skill can fix any coding issue.
I would say I’m mostly a developer. I guess I might be overthinking it, looking for the holy grail. OOCSS recommends naming classes by visual semantics, which I find a bit hard to put names on – I often end up with class names derived from content semantics or functionality, leading to little reuse of classes.
TBH I enjoy working with CSS-in-JS the most, and it’s excellent for my own React projects; when I’m at work I collaborate with designers knowing som CSS and no coding, and back-end developers not necessarily knowing the intricacies of CSS. It is very easy to end upp with thousands of lines of redundant/obsolete CSS when several people work together like that.
This was an excellent introduction for the article I was hoping to read.
Couple of word for you: BEM and variables/constants. Resulting bundle is bloated? Oh yea. But here we go – almost no casscade, independet blocks etc, etc