CSS Coding Standards

CSS in a large Drupal theme can turn into a tangle fast, which is why a component-based approach — small, self-contained pieces of styling rather than one long cascading sheet — pays off far sooner than it looks like it will.

1. Component-Based Organization

Styles are grouped by component rather than by page, each in its own file: a card.css, a site-header.css, a pager.css. A component's file only styles that component and the elements inside it — reaching out to style something unrelated a few DOM levels up is a sign the styles belong somewhere else.

css/
components/
card.css
site-header.css
pager.css
base/
elements.css
variables.css

2. BEM Naming

Class names follow BEM: a Block is the component itself, an Element is a part of it joined with a double underscore, and a Modifier is a variation joined with a double hyphen. Seeing the relationship in the class name means never having to open a second file just to figure out what a class belongs to.

/* ❌ Incorrect: no visible relationship between the class names. */
.card {
}

.title {
}

.featured {
}

/* ✅ Correct: BEM naming shows the relationship. */
.card {
}

.card__title {
}

.card--featured {
}

3. Selectors

ID selectors are never used for styling — an ID's specificity is high enough to make later overrides painful, and Drupal's own markup often reuses IDs in ways that make them unreliable hooks anyway. Selectors stay shallow, ideally a single class, and nesting rarely goes more than two or three levels deep.

/* ❌ Incorrect: an ID selector, and unnecessary nesting. */
#sidebar .block .block-content ul li a {
  color: blue;
}

/* ✅ Correct: a single, shallow class selector. */
.sidebar-block__link {
  color: blue;
}

!important is avoided outright — reaching for it is almost always a sign that a selector further up needs to be less specific, not that this declaration needs to win by force.

4. Formatting

One selector per line in a multi-selector rule, one declaration per line, a space before the opening brace, and a space after the colon in each declaration. Hex colors are lowercase, and shorthand is used wherever it's genuinely shorter.

/* ❌ Incorrect. */
.card,.card--featured{
color:#FFFFFF;background-color:#000000;
}

/* ✅ Correct. */
.card,
.card--featured {
  color: #fff;
  background-color: #000;
}

5. Stylelint

Drupal core's Stylelint configuration checks most of the rules above automatically, the same role ESLint plays for JavaScript and PHP_CodeSniffer plays for PHP — running it locally catches formatting and selector issues well before a review would.

Latest update: 21.09.2026 09:27