CSS Style Guide - BEM Approach

| Comments

I’m trying to maintain a living CSS style guide which helps as a self guide for me & to get insights from others. Most of the content is picked from Spatie CSS Guidelines & few from Chainable BEM modifiers

Feel free to drop on comments section about what you use and what you feel can be changed here.

Table of Contents

BEM

BEM — Block Element Modifier is a methodology that helps you to create reusable components and code sharing in front-end development. I use a slightly changed modifier naming convention(see below).

1
2
3
4
5
6
7
8
9
10
11
12
.component                            /* Component */
.component__element                   /* Child */
.component__element__element          /* Grandchild. PS. Avoid Grandgrandchild */

.--modifier                           /* Single property modifier, can be chained */

.h-property                           /* Helpers (eg. `h-align-right`, `h-margin-top-s`) */

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

.items                                /* Use plurals if possible */
.item

.component and .component__element

1
<div class="menu"></div>
  • A reusable component, which can be shared between pages/modules
  • Children are separated with __
  • All lowercase, can contain - in name
  • Avoid more than 3 levels so that your html is not filled with lengther class names
1
2
3
4
5
6
<div class="menu">
    <div class="menu__item">
        <div class="menu__item__icon"></div>
        <div class="menu__item__name"></div>
    </div>
</div>

Be descriptive with component elements. Consider class="team__member" instead of class="team__item"

1
2
3
<div class="team">
    <div class="team__member"></div>
</div>

You can use plurals & singulars for readability. Consider class="member" instead of class="members__member"

1
2
3
<div class="members">
    <div class="member"></div>
</div>

.–modifier

1
<div class="button --rounded --active"></div>
1
2
3
4
5
6
7
8
9
.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
  • 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

.h-property

1
2
3
4
<div class="h-align-right"></div>
<div class="h-visibility-hidden"></div>
<div class="h-text-ellipsis"></div>
<div class="h-margin-top-s"></div>
  • Prefix with h- helps identify easily that’s its a helper class
  • Reusable utility classes throughout the entire project
  • Each helper class is responsible for a well-defined set of properties.
  • It should be clear that these are not components

.js-hook

1
2
3
4
5
<div class="js-map"
     data-map-icon="url.png"
     data-map-lat="4.56"
     data-map-lon="1.23">
</div>
  • Use js-hook to initiate handlers like document.getElementsByClassName("js-hook")
  • Use data-attributes only for data storage or configuration storage
  • Has no effect on styling whatsoever

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, moveable in a project, or between projects
  • Avoid multiple components on 1 DOM-element. Break them up.
1
2
3
4
5
6
7
<!-- Try to avoid, news padding or margin could break the grid-->
<div class="grid__col news"></div>

<!-- More flexible, readable & moveable -->
<div class="grid__col">
    <article class="news"></article>
</div>

Tags are interchangeable since styling is done by class.

1
2
3
4
<!-- All the same -->
<div class="article"></div>
<section class="article"></div>
<article class="article"></div>

Class Visual Grouping

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

Visual class grouping can be done with … | …

1
<div class="js-news-click | news__item --blue --small --active | h-padding-top-s h-align-right"></div>

Code Style

Use stylelint to lint stylesheets. Configuration is done at custom .stylelintrc which extends stylelint-config-standard.

1
2
3
4
5
6
7
8
9
10
{
  "extends": "stylelint-config-standard",
  "ignoreFiles": "resources/assets/css/vendor/*",
  "rules": {
      "indentation": [2],
      "at-rule-empty-line-before": null,
      "number-leading-zero": null,
      "selector-pseudo-element-colon-notation": "single",
    }
}

Installation

1
2
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

Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/* Comment */
.component {                      /* Indent 2 spaces, space before bracket */
    @at-rule ;                    /*  @at-rules first */

    a-property: value;            /* Props sorted */
    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__element {            /* Separate class for readability, searchability instead of `&__element`*/

}

Folder/File structure

5 folders and a main app.css file:

1
2
3
4
5
6
7
|-- base       : basic html elements
|-- components : single components
|-- helpers    : helper classes
|-- pages      : page related styles
|-- settings   : variables
|-- vendor     : custom files from 3rd party components like select2, jqueryui etc.
|-- app.css    : main file

app.css

Import in proper order to take care of variable declaration & specificity

1
2
3
4
5
6
@import "settings/**/*";
@import "base/**/*";
@import "components/**/*";
@import "pages/**/*";
@import "helpers/**/*";
@import "vendor/**/*";

Base Folder

Contains resets and sensible defaults for basic html elements.

1
2
3
4
5
6
7
|-- normalize.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.

1
2
3
4
|-- modal.css
|-- buttons.css
|-- table.css
|-- 

Helper Folder

Stand-alone helper classes for small layout fixes.

1
2
3
4
5
|-- align.css
|-- margin.css
|-- padding.css
|-- text.css
|-- 

Pages Folder

Page related styles (not reusable but needed for pages)

1
2
3
|-- about.css
|-- dashboard.css
|-- 

Settings Folder

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

1
2
3
4
5
|-- color.css
|-- fonts.css
|-- grid.css
|-- typography.css
|-- 

Vendor Folders

Imported and customized CSS from 3rd party components (you don’t want to lint this).

1
2
3
|-- jquery-ui.css
|-- select2.css
|-- 

This guide is inspired from various sources, thanks to those who shared their views which help me build this self guide.

Comments