A simple CSS ruleset

The content of this article is a set of 8 rules along with a CSS writer's workflow, grown out of developing small web projects. It's designed for simple layouts with minimal JavaScript interactiveness, and its top concern is code readability, rather than DRY.


1. No preprocessors

Using a preprocessor, such as Sass, for a few thousand lines of CSS code is a clear case of overengineering. The scope of a project is the most crucial datum for the preprocessor decision, but what happens in modern web development is that the preprocessor overhead is downplayed because of the omnipresence of the Node.js toolset.

2. No frameworks

Unless one plans to use every Bootstrap component it's not worth adding 160KB of un-gzipped CSS files. In addition to the size tradeoff, the framework buy-in is an important engineering decision as one is potentially adding something that they will have to fight either in a case of over-growing it or in a case of not understanding how it's designed to be extended.

3. Yes CSS reset

Browser implementation inconsistencies1 are undying. Therefore, while no framework is advised, a CSS reset library is. I've been using normalize.css for the last many years with no issues.

4. No externally loaded fonts

Typography is great and fun. In cases of doubt Practical Typography provides enlightenment. But this is the case against fonts, and especially against Google Fonts2, as the only real contender for free web fonts. Our criteria are quality and speed. All OSes have good enough default fonts, thus it's not worth loading a slightly different font and introducing yet another third-party dependency. But maybe one wants a more-than-slightly different font. Then, my argument is that most Google Fonts are not of high quality, and a professional font might be worth buying.

5. Yes semantic HTML elements

Semantic HTML is great. Not only does it enable one to think through the information architecture of their layout, but also improves the accessibility of the website.

6. Yes CSS variables

CSS variables have good enough browser support for a while now. Colours and margin/padding lengths are ideal usecases for them.

7. Yes namespaces

I've found very useful to overload class names with namespaces, based on page or resource names. For example, if form buttons are different than bare buttons, then those classes will be form-btn-submit. Another recurring example is special styling for the landing page, which I'd namespace as landing-*.

8. Yes rule-local responsive media queries

The question is whether to place all rules for a specific breakpoints all together, or rules for the same classes together across different breakpoints. I vote for the second option, so that when one wants to read or change the rules for e.g. nav, they see all rules for all breakpoints together, rather than jumping to different places of the file for the other breakpoints. Example:

.projects-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
@media (max-width: 490px) {
  .projects-grid {
    grid-template-columns: 1fr 1fr;
@media (max-width: 340px) {
  .projects-grid {
    grid-template-columns: 1fr;


The limitations of this system lie mostly on compatibility.

Firstly, preprocessors would automagically fill the blanks with vendor-prefixed properties and polyfills. Without those, some problems might arise.

Secondly, IE11 does not support CSS variables, which we say yes to.


Most of the times I'm designing a new webpage with no existing design, I have found that capturing my vague ideas into a concrete design in a vector editor is the best way to start. After that, I focus on writing the HTML. The reason for not writing the HTML and the CSS in parallel lies mostly in the unknown intricacies of the layout that will be followed. If a CSS grid is needed, for example, this is the step to decide that.

Final stage is actually writing the CSS code. I try to group the rules together based on where they are used. Generic selectors like a and h1 go first, then form and their conceptual children such as input, and then namespaces of other resources and pages.

One can find an actual example of all the ideas in action on the repo of the project.

  1. Stephanie Stimac has a interesting example on font rendering incosistencies. Also, the source code comments for normalize.css are enlightening. 

  2. Matthew Butterick provides another case, a very interesting critique on Google Fonts, in regards to them not being open-source.