Avoid Overstyling Base Styles
In SMACSS, I talk about the different categories of CSS that we write. The very foundation are base styles—plain element selectors. No classes, no IDs. The purpose of these selectors is to style those elements on every page across the site in a consistent way.
Many people I know like to use a CSS reset—like Eric Meyer’s or Normalize—on their project. These resets are base styles.
Something Something Considered Harmful
One of the things I often recommend in my workshop that people do is try removing their reset at the end of the project and see what happens. You might be surprised at how little the design changes.
There are two reasons for that:
Many of the styles declared in a reset are defaults across a large swath of HTML elements that are never used in a project. You’re literally using CSS that does absolutely nothing.
As we style parts of the page, we specify styles that override reset styles (and browser default styles). As a result of that subsequent redeclaration, that original reset style becomes unnecessary.
Generally speaking, I prefer to write CSS that solves a specific problem and I only write it when I need to solve that problem.
That’s not to say that I don’t believe in having a reset at all. I am saying that my resets are much more judicious and only declare default styles for a few elements—elements that I reset on every project.
body, and maybe some default heading and paragraph styles (if it’s a blog/content site).
Although even to that last point, these days, I’m inclined to scope styles like
Global isn’t so Global
Again, the reason for declaring base styles is to have everything look the same. For example, my blog only has one button, which is the ‘submit comment’ button on the article page. Why bother using a class selector when a simple element selector will do?
For my little ol’ blog, an element selector would be fine. The concept hasn’t changed much in the 15 years I’ve been running a blog.
At Shopify, the marketing site doesn’t have a lot of buttons. In fact, there was just one in the main sign-up form. It was big and bold and full of style to draw people in.
We also had a contact form which, originally, was sitting in an
iframe. As a result of said
iframe, the inputs and buttons used a default styling supplied by the third-party contact form service we were using.
I wanted to move the form from the iframe and put it on the actual page, where I believed it should’ve been. I felt the use of an iframe negatively impacted performance and accessibility.
When I moved the form, however, it suddenly picked up the base styles that had been declared. They were huge! Of course. They were never designed for this contact form. They were designed for a simpler, smaller sign-up form.
Now I had to write a bunch of CSS to undo the base styles that were originally declared. Definitely less than ideal.
Had the styles been originally declared using a class selector, the new form controls wouldn’t have needed any extra CSS. Any styles would be ones I specifically wrote to serve the design and not to override another design.
Maybe there is only a single style applied throughout a project. All text inputs, for example, might look the same and should always look the same.
Again, at Shopify, this was the case. Again, we had base styles that gave all text inputs a very specific look.
We wanted to update the design that required changing the HTML and CSS around inputs. With probably a couple hundred templates of screens, modals, and partials to update, doing this in one large pull request wasn’t ideal. The time required to make the change, have people review the change, and dealing with merge conflicts with other teams working on dozens of other pull requests meant that we needed to do this piecemeal.
The problem is that, again, we had to undo all the default styles in order to apply our own. In this case, we created a Sass mixin that handled our reset that was mixed in with our new style that used a class selector.
Once all styles used the new input styles, the old input styles could be removed along with the mixin.
During that transitional period, you have three times more code than you actually want.
If we had not used base styles and instead used a class for our text inputs, our transitional phase would’ve had a third less code and it would’ve been much more obvious as to when we could remove the old code—the class would be gone from all templates.
Solve the Problem
To reiterate, I prefer to write CSS that solves a specific problem and I only write it when I need to solve that problem. By keeping base styles minimalistic, I end up with less code to start the project and less code during design transitions and greater clarity around what code is and isn’t used. Win, win, win.
Not sure this adds much to the conversation, but rather than as a guideline saying base styles shouldn't do much, the example lends credence to not making base styles stray from the easily-recognizable. Not really sure the sentence I just wrote made any sense.
...would make purple buttons that look like purple buttons. If the padding were instead "20em 40em", they'd look far less button-y, and would have to be overridden more often than not.
So I guess what I'm saying is that a refactor of the shopify CSS might have benefited from the global buttons retaining the styling that makes them button-like, with an extender class for the special big calls to action?
Thanks, really great read. Although I tend to agree with your proposition, Rhetorically i'm wondering whether this type of encapsulation actually works against the intention of the Cascade? And in tern, what that means about CSS.
@Elise: it works against the cascade but works towards clarity of intent. In other words, we are trying to apply a collection of properties to a given element. The cascade allows us to apply those properties through compositional layering. We sabotage ourselves when we apply styles we don't want to some elements and then have to overwrite those properties with new values.