The No-Nonsense Styling Method

The “No-Nonsense Styling Method” is a set of guidelines that I've compiled that makes styling less surprising and more predictable. Specifically, it increases the scalability, maintainability, readability, and ease of change of your CSS.

These guidelines are based on my personal experience working with CSS in many different codebases of varying sizes and which used varying styling strategies.

However, the language here is normative for clarity only. It's not meant to be dogmatic and should be taken in context with the reader's own experience. It's mostly useful for developing highly interactive web apps and not as applicable to other types of website development.

The 5 guidelines are:

  1. Re-use components instead of classNames
  2. No components should support className
  3. No nesting, descendant selectors, or child selectors
  4. Use locally scoped styling only
  5. No CSS pre-processors (SASS, LESS) or naming philosophies (BEM)

The examples are in react but it’s applicable to any type of web app development.

1. Re-use components instead of classNames

The number one rule of the “no-nonsense styling method” is to make your main “reusable unit of styling” be components instead of classNames.

Good:

<Button color="primary"></Button>

Bad:

<button type="button" className="btn btn-primary"></button>

This approach embraces the power of component-based architecture. The superior unit of composition is the component - not the className.

Why?

2. No components should support className

Components should not support the className prop. Instead, they should support a small number of specific props.

Bad:

<Button className="colorPrimary smallMarginLeft" />

Good:

<Button color="primary" marginLeft="sm" />

Why?

3. No nesting, descendant selectors, or child selectors

Nesting, descendent selectors, or child selectors can be surprising when they are encountered. Developers often have to essentially debug where these extra styles are coming from. In the worst case, this can become very complex and hard to follow.

It’s much simpler and more consistent to just avoid this.

Bad:

<div className="authorSection">
  <div>Arthur Conan Doyle</div>
  <p>Arthur Conan Doyle is a British writer and physician. He created the character Sherlock Holmes in 1887 for A Study in Scarlet, the first of four novels and fifty-six short stories about Holmes and Dr. Watson.</p>
</div>

.authorSection div {
  color: red;
}

.authorSection p {
  color: blue;
}

Good:

<AuthorSection>
  <AuthorName>Ben Lorantfy</AuthorName>
  <AuthorBio>lorem ipsum</AuthorBio>
</AuthorSection>

Better:

<Box>
  <Typography color="primary">Ben Lorantfy</Typography>
  <Typography color="secondary">lorem ipsum</Typography>
</Box>

.

There’s one exception here: if you’re using :hover or :focus-within (to make a custom TextField, for example) it’s fine to use descendent selectors. But these selectors should be done in a non-brittle way and without using classNames. styled-components offers a specific syntax that works well for this use-case.

4. Use locally scoped styling only

Global styles is the largest anti-pattern in CSS. Global classNames cause numerous maintenance nightmares; they break encapsulation and information hiding, cause poor readability and discoverability, and pollute the global namespace.

Locally scoped CSS is an approach to CSS that fixes the problem of global styles. Locally scoped CSS can be implemented with one of several available technologies that encapsulates CSS so that it is only usable within one component. css-modules, for example, prefixes classNames at build time so they are only usable within the components that import them.

Good:

Bad:

One exception: it’s probably fine to use a framework like tailwindcss but only if you can enforce these utility classes are only used to build reusable components as mentioned in item 1. This can be enforced via linting (preferably) or code review guidelines.

5. No CSS pre-processors (SASS, LESS) or naming philosophies (BEM)

With the above guidelines, you don’t need SASS, LESS, BEM, etc. Plain old CSS works just fine. This way the learning curve is limited to just CSS and is not made steeper by any extra tools. It also cuts down on the build time.

Written By Ben Lorantfy

Ben is an award-winning software developer specializing in frontend development. He builds delightful user experiences that are fast, accessible, responsive, and maintainable and helps others to do the same. He lives with his partner and dog in Kitchener, Ontario.More About Ben »Follow @benlorantfy on twitter »