CSS
- We prefer Tailwind over other frameworks.
- We postprocess our stylesheets with PostCSS, for example to ensure browsers support or optimize the output.
- If really necessary, we preprocess our stylesheets with Sass using the SCSS syntax.
Good practices
CSS is a lot harder to undo than it is to do.
Stay as close as possible to the standard
@apply flex
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.
header > div
, button.btn
, #header
.site-header
, .card
, .list-arrows
Also split each component into a dedicated file (see Files Organization below).
Use conventionnal naming
.Header
, .the_header
, .the_header-Menu
kebab-case
when not applicableKeep the specificity low
!important
, :not(…)
, or any feature that would unnecessarily increase the precedence when a refactor could have prevented using them in the first place!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..article .article__body
, .intro-block--full .slider--fullscreen > .slider__item .btn
.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;
}
}
.btn--link
, .text-center
/* 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
color
, font-…
, direction
, … on many sibling elementsEnjoy utility classes
.list-inline--right
, .media--right
, .actions--right
.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 ormargin-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!
Augment rather than deconstruct
.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;
}
.card {
display: flex;
}
.card--default {
background-color: var(--light-blue);
}
.card {
display: flex;
}
.card--default {
background-color: var(--light-blue);
}
.btn {
display: flex;
}
.btn {
display: flex;
}
In the HTML below, the sm:flex
style duplicates the value from the CSS above:
<button class="btn hidden sm:flex"></button>
<button class="btn hidden sm:flex"></button>
<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
background: red
, padding: 0 10px
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:
.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:
Folder | Description | Children |
---|---|---|
settings | Variables & common settings | Usually one settings file |
tools | Sass functions and mixins | Usually one mixins and one functions file |
vendor | Third-parties code, prefer Node modules when available | |
base | All the default styling and global elements (html, body, h1, p, blockquote, …) | We often see layout , typography , forms , or fonts here |
components | Standalone group of classes forming a single reusable component (.user-card , .dashboard-panel , .site-header , …) | One file per component, named as the component main class |
pages | Very specific code dedicated to one page | One file per page |
utilities | Various 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.