CSS Style Guide

Preprocessing

We use PostCSS with CSSNext, but these principles are applicable to any pre- or postprocessors out there.

BEVM

We use a BEM-like syntax with some custom accents. The 'variation' is a concept picked up from Chainable BEM modifiers.

We only use classes for styling, with the following ingredients:

.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`) */

.js-hook                        /* Script hook, not used for styling */

.component and .component__element

<div class="news">
<div class="news">
    <div class="news__item">
        <div class="news__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"

<div class="members">
    <div class="member">

.-modifier

<div class="button -rounded -active">
.button {
    &.-rounded {
        …  
    }

    &.-active {
        …
    }
}

.component--variation

<div class="button--delete">
.button--delete {
    /* Base button classes */
    …
    
    /* Variations */
    background-color: red; 
    color: white;
    text-transform: uppercase;
}

.helper-property

<div class="align-right">
<div class="visibility-hidden">
<div class="text-ellipsis">
<div class="margin-top-s">

.js-hook

<div class="js-map …"
     data-map-icon="url.png"
     data-map-lat="4.56"
     data-map-lon="1.23">

DOM structure

<!-- 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>   

Tags are interchangeable since styling is done by class.

<!-- All the same -->
<div class="article">
<section class="article">
<article class="article">

Html tags that are out of control (eg. the output of an editor) are scoped by the component.

<div class="article">
    <!-- custom html output -->
</div>    
.article {
    /* Tag instead of class here */
    & h2 {
        …
    }

    & p {
        …
    }    
}

Class order

<div class="js-hook component__element -modifier helper">

Visual class grouping can be done with … | …:

<div class="js-masonry | news__item -blue -small -active | padding-top-s align-right">

Code style

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

Examples

/* Comment */

.component {                      /* Indent 4 spaces, space before bracket */                                   
    @at-rule …;                   /*  @at-rules first */
         
    a-property: value;            /* Props sorted automatically by eg. PostCSS-sorting */
    b-property: value; 
    c-property: .45em;            /* No leading zero's */
    
    &:hover {                     /* Pseudo class */
        …
    }
    
    &:before,                     /* Pseudo-elements */
    &:after {                     /* Each on a line */
        …
    }
    
    &.-modifier {
        …                           
    }
     
    &.-modifier2 {
        …                        
    }
    
    /* Try to avoid */
    
    @apply …;                     /* Use only for variations */
    
    &_subclass {                  /* Unreadable and not searchable */
        …
    }
                
    h1 {                          /* Avoid unless you have no control over the HTML inside the `.component` */
        …
    }
          
}
                                  /* Line between classes */
.component--variation {           /* A component with few extra modifications often used together */
    @apply .component;            /* Only good use for @apply */
    …
}
    
.component__element {             /* Separate class for readability, searchability instead of `&__element`*/
    …
}

File structure

We typically use 5 folders and a main app.css file:

|-- base       : basic html elements
|-- components : single components
|-- helpers    : helper classes
|-- settings   : variables
|-- vendor     : custom files from 3rd party components like fancybox, select2 etc.
`-- app.css    : main file

app.css

@import 'settings/**/*';
@import 'base/**/*';
@import 'components/**/*';
@import 'helpers/**/*';
@import 'vendor/**/*';

Base folder

Contains resets and sensible defaults for basic html elements.

|-- universal.css
|-- html.css
|-- a.css
|-- p.css
|-- heading.css (h1, h2, h3)
|-- list.css (ul, ol, dl)
`-- …

Components folder

Stand-alone reusable components with their modifiers and variations.

|-- alert.css
|-- avatar.css
`-- …

Helpers folder

Stand-alone helper classes for small layout issues.

|-- align.css
|-- margin.css
|-- padding.css
`-- …

Settings folder

Settings for colors, breakpoints, typography, etc. You can start small with one settings.css and split them up in different files if your variables grow.

|-- breakpoint.css
|-- color.css
|-- grid.css
`-- …

Vendor folder

Imported and customized CSS from 3rd party components (this is the syntactical Wild West, you probably don't want to lint this).

|-- pikaday.css
|-- select2.css
`-- …

Inspiration