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.css2. 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.