Skip to content
This repository has been archived by the owner on Nov 26, 2023. It is now read-only.

mathieueveillard/crafting-css

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Crafting CSS

A practical guide to crafting better CSS. Highly opinionated.

Questions

  • How to enforce visual consistency, i.e. a visual grammar made of visual patterns?
  • How no to repeat oneself?
  • How to ensure component's CSS code isolation/avoid leakages?
  • How to minimize coupling between structure (think div) and style?

For sure, there will be trade-offs.

Summary

Define styles in a dedicated stylesheet

Don't

<!-- HTML -->
<p style="color: red;">Lorem ipsum dolor sit amet.</p>

Do

<!-- HTML -->
<p class="danger">Lorem ipsum dolor sit amet.</p>
/* CSS */
.danger {
  color: red;
}

Why

High coupling. In the first place, CSS was designed to decouple structure and style. But in fact, that's a matter of choice (avoiding coupling is hard, so some developers prefer not even try to avoid it, hence CSS-in-JS).

Summary


Do not refer to elements

Don't

<!-- HTML -->
<p>Lorem ipsum dolor sit amet.</p>
/* CSS */
p {
  color: red;
}

Do

<!-- HTML -->
<p class="danger">Lorem ipsum dolor sit amet.</p>
/* CSS */
.danger {
  color: red;
}

Why

High coupling. Separating structure and skin allows to:

  • apply different styles to a given element, or no style at all
  • apply the same style to other elements
  • use another more suited element without breaking the style

Summary


Do not refer to IDs

Don't

<!-- HTML -->
<p id="danger">Lorem ipsum dolor sit amet.</p>
/* CSS */
#danger {
  color: red;
}

Do

<!-- HTML -->
<p class="danger">Lorem ipsum dolor sit amet.</p>
/* CSS */
.danger {
  color: red;
}

Why

Overly specific. There's simply no reason to use IDs. ID selectors introduce an unnecessarily high level of specificity and they are not reusable. IDs are primary used for anchoring (see: Linking to an element on the same page).

Summary


Separate layout and skin

Don't

<!-- HTML -->
<div class="danger">Lorem ipsum dolor sit amet.</div>
/* CSS */
.danger {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  box-sizing: border-box;
  padding: 1rem;
  background-color: red;
  text-align: center;
  color: white;
  font-weight: bold;
}

Do

<!-- HTML -->
<div class="danger-layout danger">Lorem ipsum dolor sit amet.</div>
/* CSS */
.danger-layout {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
}

.danger {
  box-sizing: border-box;
  padding: 1rem;
  background-color: red;
  text-align: center;
  color: white;
  font-weight: bold;
}

Why

Layout refers to properties that determine the size and the positionning of an element, and consequently the overall aspect of the page. Skin refers to properties relative to colors, fonts, text alignment and so on. Skin is much more likely than layout to be reused.

Summary


Separate container and content

In fact, the previous code could (should?) be refactored!

Don't

<!-- HTML -->
<div class="danger-layout danger">Lorem ipsum dolor sit amet.</div>
/* CSS */
.danger-layout {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
}

.danger {
  box-sizing: border-box;
  padding: 1rem;
  background-color: red;
  text-align: center;
  color: white;
  font-weight: bold;
}

Do

<!-- HTML -->
<div class="container">
  <div class="danger">Lorem ipsum dolor sit amet.</div>
</div>
/* CSS */
.container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
}

.danger {
  box-sizing: border-box;
  padding: 1rem;
  background-color: red;
  text-align: center;
  color: white;
  font-weight: bold;
}

Why

An element should not be responsible for its own positionning!

Summary


Do not use location-dependent styles

Don't

<!-- HTML -->
<div class="container">
  <p class="content">Lorem ipsum dolor sit amet.</p>
</div>
<p class="content">Lorem ipsum dolor sit amet.</p>
/* CSS */
.container .content {
  color: red;
}

Or:

// SASS
.container {
  & .content {
    color: red;
  }
}

Do

<!-- HTML -->
<div class="container">
  <p class="content danger">Lorem ipsum dolor sit amet.</p>
</div>
<p class="content">Lorem ipsum dolor sit amet.</p>
/* CSS */
.danger {
  color: red;
}

Why

An object should look the same no matter where you put it. Otherwise, there is a coupling between structure (.html) and style (.css). As a consequence, you should avoid combinators and nesting with preprocessors.

Oh, by the way, are you sure you need a preprocessor?

Summary


Create small objects

An example, please!

<!-- HTML -->
<div class="top-fixed-container content-horizontally-centered">
  <div class="danger standard-padding">Lorem ipsum dolor sit amet.</div>
</div>
/* CSS */
.top-fixed-container {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
}

.content-horizontally-centered {
  display: flex;
  justify-content: center;
}

.danger {
  background-color: red;
  color: white;
  font-weight: bold;
}

.standard-padding {
  box-sizing: border-box;
  padding: 1rem;
}

Why

Doing so, you define a visual grammar of styles once and for all, in an index.css or common.css file for instance. If you do that in a large extent, remember that that's basically what CSS frameworks do and jump to the next paragraph.

Ok, top-fixed-container, content-horizontally-centered and standard-padding have finally took place in our .html, as soldiers with the Trojan horse, but we knew that some compromises had to be made. Here, we agree on not separating concerns (structure and style) in favor of a reduced coupling.

Limitations

The object's granularity is up to you. We usually refer to an extreme granularity as "Atomic CSS", which leads to writing such things:

.background-blue {
  background-color: blue;
}

Doing so, is it still usefull to define CSS classes? Should you prefer a red backgroud, then the naming should be adapted accordingly. Which basically means defining and refering to a new class. Heading in this direction, why not simply write CSS in HTML or CSS in JS?

We strongly discourage this approach because it stands down on all the ambitions we had.

Summary


Use a CSS framework

The choice is yours, between Bootstrap and Material Design for the main ones, as well as Pure CSS, Bulma or Tailwind for emerging ones. See 9 Best CSS Frameworks in 2021 for their respective pros and cons.

Summary


Create components with your favorite library/framework

Don't

<!-- HTML -->
/* CSS */

Do

<!-- HTML -->
/* CSS */

Why

As the React documentation suggests, if you find yourself always the same and same styles, maybe you should create a component for that.

Summary


The Block__Element--modifier naming convention

For those components where you need to write some specific CSS code, BEM is your friend. In essence, it's a useful naming convention and a simple way to avoid leakages. That's what we're going to use it for, although some people use it as a broader methodology.

Please refer to the BEM documentation.

Summary


Should I use a preprocessor after all?

We've seen before that nesting should be avoided as much as possible and that small objects are a valid alternative to preprocessors when it comes to creating a visual vocabulary.

This makes preprocessors (LESS, SASS) much less usefull, though maybe not useless in some very specific cases.

Summary


What should I do now?

TODO

Summary


Further reading

Summary

About

A practical guide to crafting better CSS.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published