Q&A
What is a CSS class naming convention?
Overview
Without a naming convention, class names quickly become inconsistent, collision-prone, and opaque. A convention gives every developer a shared vocabulary: you can read a class name and immediately understand what it styles, which component it belongs to, and whether it's a variant. This is especially important when multiple people work on the same codebase.
graph TD
A[CSS naming conventions] --> B["BEM: Block__Element--Modifier"]
A --> C["OOCSS: structure + skin separated"]
A --> D["SMACSS: categorized rules"]
A --> E["Utility-first: single-purpose classes"]
style B fill:#1e1b4b,color:#fff
BEM (Block, Element, Modifier)
The most widely used convention. Names encode three things:
- Block - an independent component:
.card,.navbar,.button. - Element - a part of a block, written with
__:.card__title,.card__body,.navbar__logo. - Modifier - a variant or state, written with
--:.button--primary,.card--featured,.navbar--sticky.
<article class="card card--featured">
<h2 class="card__title">My Post</h2>
<p class="card__body">Content here</p>
<button class="button button--primary">Read more</button>
</article>
.card { border: 1px solid #ddd; border-radius: 8px; }
.card--featured { border-color: #6366f1; } /* modifier */
.card__title { font-size: 1.25rem; } /* element */
.card__body { color: #555; }
.button { padding: 8px 16px; }
.button--primary { background: #6366f1; color: #fff; }
Benefits: names are self-contained and don't conflict across components; any developer can look at .card__title and know it styles the title inside a card block.
OOCSS (Object-Oriented CSS)
Two principles: separate structure from skin (layout properties vs visual decoration) and separate container from content (don't style a heading based on where it lives).
/* Structure */
.btn { display: inline-block; padding: 8px 16px; }
/* Skin (visual) */
.btn-primary { background: #6366f1; color: #fff; }
.btn-outline { border: 2px solid #6366f1; color: #6366f1; }
Compose: <button class="btn btn-primary">. The structure class is shared; only the skin changes.
SMACSS (Scalable and Modular Architecture for CSS)
Categorizes CSS into five types: Base (resets, defaults), Layout (l- prefix), Module (reusable components), State (is- prefix), Theme.
/* State */
.is-active { display: block; }
.is-hidden { display: none; }
.is-loading { opacity: 0.5; }
/* Layout */
.l-sidebar { width: 240px; }
State classes (is-*) added/removed by JavaScript clearly signal dynamic conditions.
Utility-First (Tailwind CSS style)
Single-purpose classes describe exactly one CSS property:
<button class="px-4 py-2 bg-indigo-600 text-white rounded hover:bg-indigo-700">
Submit
</button>
No custom CSS file - just compose built-in utility classes. Controversial but very productive once learned; avoids naming altogether by not having component classes. Tailwind CSS is the dominant implementation.
General Best Practices
- All lowercase, hyphen-separated:
.user-profile, not.userProfileor.UserProfile. - Descriptive, not presentational:
.error-message, not.red-text(colors change; roles don't). - Avoid specificity wars: prefer classes over IDs and deeply nested selectors.
- Consistent prefix for JS hooks:
js-toggle-menu(never styled in CSS, only selected by JS) - lets you refactor one without breaking the other.
Choosing a Convention
| Project | Recommended |
|---|---|
| Component-based (React/Vue) | BEM or CSS Modules |
| Large multi-developer team | BEM |
| Rapid prototyping, design system | Tailwind (utility-first) |
| Legacy codebase retrofitting | SMACSS states (is-*), OOCSS skins |
Why This Matters in Interviews
CSS architecture interviews use naming conventions to test scalability thinking. Know BEM (the dominant convention: block/element/modifier, __ and -- syntax), utility-first (Tailwind), and the general principle of semantic over presentational names. Explaining why conventions matter - collision prevention, self-documentation, team consistency - is as important as naming any specific system.
Common Pitfalls
- Using presentational names (
red-box) that become wrong when the design changes. - Deep nesting in selectors instead of flat BEM classes (specificity creep).
- Using IDs for styling (too specific, hard to override, non-reusable).
- Inconsistent use of a convention (BEM in some files, ad hoc in others) - worse than no convention.
- Styling using JavaScript
js-*hooks (breaks separation of concerns - keep CSS and JS hooks separate).
References
- BEM methodology: https://getbem.com/
- SMACSS: https://smacss.com/
- Tailwind CSS: https://tailwindcss.com/