Skip to content

CSS

Good practices

CSS is a lot harder to undo than it is to do.

Harry Roberts

Stay as close as possible to the standard

Don’t use Stylus, Sass without the SCSS syntax, or other exotic syntax
Don’t use framework features with no added value like Tailwind’s @apply flex
Use native CSS syntax and features, eventually with syntactic sugar (such as nesting) to reduce repetitions and improve readability
Use framework tools when it prevents repetition and improve consistency: box-shadow: 0 0 10px theme('colors.blue.500'); write plain declarations otherwise: display: flex;

Create reusable patterns

Apply the principles of Object-oriented CSS.

Don’t couple CSS with the HTML structure or elements as it prevent patterns from being reused: header > div, button.btn, #header
Stick to classes for selectors to maximize reusability and ease overrides: .site-header, .card, .list-arrows

Also split each component into a dedicated file (see Files Organization below).

Use conventionnal naming

Don’t randomly name classes using various syntaxes and patterns. Example: .Header, .the_header, .the_header-Menu
Name classes according to the BEM syntax to highlight design tokens hierarchy and variants, or in kebab-case when not applicable

Keep the specificity low

Never use !important, :not(…), or any feature that would unnecessarily increase the precedence when a refactor could have prevented using them in the first place
Only when strictly necessary, use !important on very specific declarations, like utility classes. For example: a class named hidden applying display: none only must override any other display declaration on the same element. If the element must become visible, the style shouldn’t be altered, the class must be removed from the element instead.
Don’t unnecessarily nest selectors or alter components behavior based on unrelated parents: .article .article__body, .intro-block--full .slider--fullscreen > .slider__item .btn
css
.navbar {
  background-color: white;

  /* This is wrong, there’s no need to nest it under `.navbar`,
     it unnecessarily increases the specificity. Simply place it after. */
  &.navbar--expanded {
    background-color: black;
  }
}
.navbar {
  background-color: white;

  /* This is wrong, there’s no need to nest it under `.navbar`,
     it unnecessarily increases the specificity. Simply place it after. */
  &.navbar--expanded {
    background-color: black;
  }
}
Create variants with class names specific enough to live on their own or use utility classes: .btn--link, .text-center
css
/* Always start with the block */
.box {
  background-color: white;
}

/* Then list modifiers, at the same level than the element */
.box--negative {
  background-color: black;

  /* You can nest elements in modifiers */
  .box__body {
    color: white;
  }
}

/* And finally elements, by order of appearance in the HTML */
.box__body {
  color: black;
}
/* Always start with the block */
.box {
  background-color: white;
}

/* Then list modifiers, at the same level than the element */
.box--negative {
  background-color: black;

  /* You can nest elements in modifiers */
  .box__body {
    color: white;
  }
}

/* And finally elements, by order of appearance in the HTML */
.box__body {
  color: black;
}

Take advantage of the cascade

Don’t set identical, inheritable properties like color, font-…, direction, … on many sibling elements
Set inheritable properties targeting multiple children on a common parent

Enjoy utility classes

Avoid cluttering your CSS with many variants of the same pattern: .list-inline--right, .media--right, .actions--right
Use a single utility classes to alter the behavior: .text-right, .items-end, .text-gray-500

Let the parent handle sizing and outer spacing

A rule of thumb you can apply in 99% of cases is: a component should adapt to its parent size and only care about its own inner spacing.

  • Need to lay cards on multiple columns? Use display: grid on the parent.
  • Need space between items in a list or around columns and rows in a grid? Use gap on the parent.
  • Need space between a title and a paragraph? Add margin-bottom on the title or margin-top on the paragraph depending if one or the other is optional, but do it only for this title or this paragraph in particular (using utility classes for example). Alternatively, add a wrapper around both and use… gap!

It’s gaptastic!

Eric Meyer

Augment rather than deconstruct

Undoing existing style can be tedious, reduce composability and requires more code:
css
.card {
  display: flex;
  background-color: var(--light-blue);
}

.card--no-background {
  background-color: transparent;
}
.card {
  display: flex;
  background-color: var(--light-blue);
}

.card--no-background {
  background-color: transparent;
}
Create additionnal variants and compose them instead:
css
.card {
  display: flex;
}

.card--default {
  background-color: var(--light-blue);
}
.card {
  display: flex;
}

.card--default {
  background-color: var(--light-blue);
}
Redefining the same value multiple times at different places can leads to unexpected behaviors and bugs:
css
.btn {
  display: flex;
}
.btn {
  display: flex;
}

In the HTML below, the sm:flex style duplicates the value from the CSS above:

html
<button class="btn hidden sm:flex"></button>
<button class="btn hidden sm:flex"></button>
Avoid duplicates by altering only the necessary properties:
html
<button class="btn max-xs:hidden"></button>
<button class="btn max-xs:hidden"></button>

Use a mobile-first approach

When they do not imply deconstructing or duplicating code as stated above, you should always use min-width media queries first and alter style from the smallest screen and up.

Use shorthands responsibly

Do not use shorthands to set some values without the intent to explicitly override all the others: background: red, padding: 0 10px
Set only the value(s) you need: background-color: red, padding-left: 10px; padding-right: 10px.

Please read CSS Shorthand Syntax Considered an Anti-Pattern for a detailed explanation.

Group and order declarations

Separate declarations of the same type into groups and keep them ordered:

scss
.class {
  // Layouting
  // When this group is simple enough, we merge it with the box below
  display: grid;
  grid-template-columns:
    minmax(100px, max-content)
    repeat(auto-fill, 200px) 20%;
  grid-auto-rows: minmax(200px, auto);
  align-items: center;
  justify-content: end;

  // The box
  width: 100px;
  height: 100px;
  margin: 10px;
  padding: 10px;
  overflow: hidden;

  // Positioning
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;

  // Typeface
  color: white;
  font-family: 'Helvetica', sans-serif;
  font-size: 1.2rem;
  font-weight: bold;
  text-align: center;
  text-decoration: underline;

  // Styling
  background-color: red;
  border: 1px solid blue;
  border-radius: 3px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.25);
  transform: scale(1.1);
  transition: scale 0.2s ease-in-out;

  // All other properties
  cursor: pointer;
  pointer-events: none;
}
.class {
  // Layouting
  // When this group is simple enough, we merge it with the box below
  display: grid;
  grid-template-columns:
    minmax(100px, max-content)
    repeat(auto-fill, 200px) 20%;
  grid-auto-rows: minmax(200px, auto);
  align-items: center;
  justify-content: end;

  // The box
  width: 100px;
  height: 100px;
  margin: 10px;
  padding: 10px;
  overflow: hidden;

  // Positioning
  position: absolute;
  top: 0;
  left: 0;
  z-index: 1;

  // Typeface
  color: white;
  font-family: 'Helvetica', sans-serif;
  font-size: 1.2rem;
  font-weight: bold;
  text-align: center;
  text-decoration: underline;

  // Styling
  background-color: red;
  border: 1px solid blue;
  border-radius: 3px;
  box-shadow: 0 0 20px rgba(0, 0, 0, 0.25);
  transform: scale(1.1);
  transition: scale 0.2s ease-in-out;

  // All other properties
  cursor: pointer;
  pointer-events: none;
}

Tools

You can install Stylelint to validate stylesheets code style. We have our own Stylelint configuration package with predefined rules to validate code styling compliance.

Check the list of editor plugins for instant validation right in your favorite editor.

Files organization

We organize our partials into separates folders:

FolderDescriptionChildren
settingsVariables & common settingsUsually one settings file
toolsSass functions and mixinsUsually one mixins and one functions file
vendorThird-parties code, prefer Node modules when available
baseAll the default styling and global elements (html, body, h1, p, blockquote, …)We often see layout, typography, forms, or fonts here
componentsStandalone group of classes forming a single reusable component (.user-card, .dashboard-panel, .site-header, …)One file per component, named as the component main class
pagesVery specific code dedicated to one pageOne file per page
utilitiesVarious specific classes reusable anywhere (.text-brand, .img-circle, …)Group similar classes per files (text, images, …)

Legacy

Kanbasu

Kanbasu was our open-source framework that we used on almost all projects. It’s a set of common components and helpers to build interfaces written in Sass and following the BEM syntax. It is deprecated and we do not use it for new projects.