CSS Style Guide
NOTE!
This style guide is outdated and should be updated to reflect the current state of our projects. It's still a good starting point, but it's not the final word on how we write CSS.
We always use Sass (the scss
flavour) in our projects.
We generally use TailwindCSS for all new projects.
Class naming & components
Use simple classes with words separated with hypens. Try to avoid creating components. Instead try to style as much as you can with Tailwind classes and only extract components when you have to.
Bad:
.sidebar__link {}
Good:
.sidebar-link {}
Try not to use too many general html-selectors, this will eventually have unwanted side effects:
Bad:
.sidebar {
a {}
}
Good:
.sidebar {}
.sidebar-link {}
// or
.sidebar {
.link {}
}
Nesting
Try to avoid nesting more then 2 levels deep:
Bad:
.component {
h2 {
i {}
}
}
Good:
.component {
h2 {}
i {}
}
If you need to style stuff with css and you feel the need to nest stuff deep, add a class instead - it's ok!
Indentation
Always use 4 spaces (not tabs) for indentation (make sure your IDE is setup correctly). For PHPStorm, this is done by going to Preferences => Editor => Code Style => SCSS/CSS and there set the options:
- Tab size: 4
- Indent: 4
- Don't check the "Use tab character" option
This is already configured in our own phpstorm .xml-file.
Code style linting
We use stylelint to lint our stylesheets.
Configuration is done a custom .stylelintrc
which extends stylelint-config-standard
.
{
"extends": "stylelint-config-standard",
"ignoreFiles": "resources/assets/css/vendor/*",
"rules": {
"indentation": [4],
"at-rule-empty-line-before": null,
"number-leading-zero": null,
"selector-pseudo-element-colon-notation": "single",
}
}
Installation
yarn add stylelint
yarn add stylelint-config-standard
Usage
Most projects have a lint script (with the --fix
flag) available in their package.json
.
stylelint resources/assets/css/**/**.css --fix -r
Projects without Tailwind
For older projects where we don't use Tailwind, we try to follow a BEM-like structure. Everything from this point is only important for older projects without Tailwind.
BEM
.component /* Component */
.component__element /* Child */
.component__element__element /* Grandchild */
.items /* Use plurals if possible */
.item
.-modifier /* Single property modifier, can be chained */
.component--variation /* Standalone variation of a component */
.component__element--variation /* Standalone variation of an element */
.helper-property /* Generic helper grouped by type (eg. `align-right`, `margin-top-s`) */
.component, .component__element
<div class="article">
- A single reusable component or pattern
- Children are separated with
__
- All lowercase, can contain
-
in name - Avoid more than 3 levels deep (important!)
<div class="article">
<div class="article__item">
<div class="article__item__publish-date">
Be descriptive with component elements. Consider class="team__member"
instead of class="team__item"
<div class="team">
<div class="team__member">
You can use plurals & singulars for readability. Consider class="member"
instead of class="members__member"
. Not everything must be inside of the same component!
<div class="members">
<div class="member">
.-modifier
Don't use the -modifier
for all variations, just single modifier classes like active
.
<div class="button -rounded -active">
.button {
&.-rounded {
}
&.-active {
}
}
- A modifier changes only simple properties of a component, or adds a property
- Modifiers are always tied to a component, don't work on their own (make sure you never write "global" modifier selectors)
- Multiple modifiers are possible. Each modifier is responsible for a property:
class="alert -success -rounded -large"
. If you keep using these modifiers together, consider a variation (see below) - Since modifiers have a single responsibility, the order in HTML or CSS shouldn't matter
.component--variation
A variation should be used together with the base class.
<div class="button button--delete">
.button {
// Button styles
}
.button--delete {
// Variation styles
background-color: red;
color: white;
text-transform: uppercase;
}
- A variation adds more than one properties at once to a class, and acts as a shorthand for multiple modifiers often used together
- It's NOT used stand-alone. Always use with the base class (eg.
button
)
.helper-property
<div class="align-right">
<div class="visibility-hidden">
<div class="text-ellipsis">
<div class="text-muted">
- Reusable utility classes throughout the entire project
- Prefixed by type (= the property that will be effected)
- Each helper class is responsible for a well-defined set of properties. It should be clear that these are not components
Nesting
Make sure that you don't nest your components in the SASS code unless you have to.
Best:
.search {
}
.search__input {
}
OK in some scenarios:
.search {
// Need to nest this because of form input base style
.search__input {
}
}
Bad:
.search {
.search__icon {
}
}
Js-hooks / Data-attributes
<div class="…"
data-trigger-map
data-map-icon="url.png"
data-map-lat="4.56"
data-map-lon="1.23">
- Try to use data-attributes, eg.
data-trigger-x
to initiate handlers likedocument.getElementsByClassName('[data-trigger-x]')
- Use other
data-attributes
(eg.data-map-lat
) for data storage or configuration storage - Has no effect on styling whatsoever (never style a js hook/data-attributes in css!)
DOM structure
- All styling is done by classes (except for HTML that is out of our control)
- Avoid #id's for styling
- Make elements easily reusable, movable in a project, or between projects
- Avoid multiple components on 1 DOM-element. Break them up.
<!-- Try to avoid, news padding or margin could break the grid-->
<div class="grid__col -1/2 news">
…
</div>
<!-- More flexible, readable & moveable -->
<div class="grid__col -1/2">
<article class="news">
…
</article>
</div>