Table of Contents
- What is CSS Architecture?
- BEM (Block Element Modifier)
- Core Principles
- Syntax & Naming Convention
- Example Implementation
- Pros & Cons
- OOCSS (Object-Oriented CSS)
- Core Principles
- Example Implementation
- Pros & Cons
- SMACSS (Scalable and Modular Architecture for CSS)
- Core Principles: The 5 Categories
- Example Implementation
- Pros & Cons
- Comparing BEM, OOCSS, and SMACSS
- When to Use Each Methodology
- Conclusion
- References
What is CSS Architecture?
CSS architecture refers to the set of guidelines, patterns, and best practices used to organize and write CSS in a way that is scalable, maintainable, and collaborative. Without a clear architecture, CSS tends to suffer from:
- Specificity conflicts: Styles overriding each other unexpectedly.
- Code duplication: Repeating the same styles across components.
- Lack of reusability: Difficulty repurposing components in new contexts.
- Poor readability: New team members struggling to understand the codebase.
The goal of methodologies like BEM, OOCSS, and SMACSS is to solve these problems by enforcing structure, consistency, and modularity.
BEM (Block Element Modifier)
BEM, developed by Yandex, is a naming convention for CSS classes that makes the relationship between HTML and CSS explicit. It focuses on breaking UIs into independent, reusable components.
Core Principles
BEM is built on three concepts:
- Block: A standalone component (e.g., a button, card, or menu). Blocks are independent and can be reused across projects.
- Element: A part of a block that has no meaning on its own (e.g., a button’s icon or a card’s title). Elements are dependent on their parent block.
- Modifier: A flag that changes the appearance or behavior of a block or element (e.g., a “disabled” button or a “large” card).
Syntax & Naming Convention
BEM uses a strict naming pattern to avoid ambiguity:
block: The root class of the component (e.g.,button).block__element: An element inside the block (double underscore, e.g.,button__icon).block--modifier: A modifier for the block (double hyphen, e.g.,button--primary).block__element--modifier: A modifier for an element (e.g.,button__text--bold).
Example Implementation
Let’s build a “card” component using BEM:
HTML
<div class="card card--featured">
<img class="card__image" src="product.jpg" alt="Product">
<h3 class="card__title">Wireless Headphones</h3>
<p class="card__description">High-quality sound with noise cancellation.</p>
<button class="card__button card__button--primary">Add to Cart</button>
</div>
CSS
/* Block: Card */
.card {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 16px;
max-width: 300px;
}
/* Element: Card image */
.card__image {
width: 100%;
border-radius: 4px;
}
/* Element: Card title */
.card__title {
font-size: 1.2rem;
margin: 12px 0 8px;
}
/* Element: Card description */
.card__description {
color: #666;
font-size: 0.9rem;
margin: 0 0 16px;
}
/* Element: Card button */
.card__button {
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* Modifier: Featured card */
.card--featured {
border-color: #2196F3;
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
/* Modifier: Primary button */
.card__button--primary {
background: #2196F3;
color: white;
}
Here, card is the block, card__image/card__title are elements, and card--featured/card__button--primary are modifiers.
Pros & Cons
| Pros | Cons |
|---|---|
| Clear relationship between HTML and CSS (no “magic” classes). | Verbose class names (e.g., card__description--large). |
| Avoids specificity conflicts (flat hierarchy). | Steeper learning curve for teams new to BEM. |
| Highly scalable for large projects and component-based architectures (e.g., React, Vue). | Overhead for small, simple projects. |
OOCSS (Object-Oriented CSS)
OOCSS, created by Nicole Sullivan, applies object-oriented programming principles to CSS. It focuses on separating concerns to create reusable, modular “objects” (UI components).
Core Principles
OOCSS is guided by two key rules:
- Separate Structure from Skin: Define the structural properties (e.g., padding, margins, positioning) in one class, and visual properties (e.g., colors, fonts, shadows) in another.
- Separate Container from Content: Ensure components are independent of their parent containers. A button, for example, should look the same whether it’s in a header or a footer.
Example Implementation
Let’s build a reusable “media object” (a common UI pattern with an image and text) using OOCSS:
HTML
<!-- Media object with "default" skin -->
<div class="media">
<img class="media__img" src="avatar.jpg" alt="Avatar">
<div class="media__body">
<h4 class="media__title">John Doe</h4>
<p class="media__text">Frontend developer passionate about CSS architecture.</p>
</div>
</div>
<!-- Media object with "highlighted" skin -->
<div class="media media--highlighted">
<img class="media__img" src="avatar.jpg" alt="Avatar">
<div class="media__body">
<h4 class="media__title">Jane Smith</h4>
<p class="media__text">Design systems specialist.</p>
</div>
</div>
CSS
/* Structure: Base media object */
.media {
display: flex;
gap: 16px;
padding: 16px;
border-radius: 4px;
}
.media__img {
width: 64px;
height: 64px;
border-radius: 50%;
}
.media__body {
flex: 1;
}
.media__title {
margin: 0 0 8px;
font-size: 1.1rem;
}
.media__text {
margin: 0;
font-size: 0.9rem;
}
/* Skin: Highlighted variant */
.media--highlighted {
background: #f5f5f5;
border: 1px solid #e0e0e0;
}
.media--highlighted .media__title {
color: #2196F3;
font-weight: bold;
}
Here, .media defines the structure, and .media--highlighted adds the “skin.” The component works anywhere in the DOM (container-agnostic).
Pros & Cons
| Pros | Cons |
|---|---|
| Highly reusable components (reduces code duplication). | Requires upfront planning to define objects. |
| Easier to theme (swap skins without changing structure). | Risk of over-abstracting (creating too many small classes). |
| Works well for UI libraries (e.g., Bootstrap, Foundation). | Less explicit than BEM (no strict naming convention). |
SMACSS (Scalable and Modular Architecture for CSS)
SMACSS, created by Jonathan Snook, is a categorization-based approach that organizes CSS into five distinct types. It focuses on reducing complexity by imposing strict organization rules.
Core Principles: The 5 Categories
SMACSS divides CSS into five categories, each with a specific purpose:
-
Base: Default styles for HTML elements (e.g., resets, typography).
- Example:
body { margin: 0; font-family: sans-serif; }ora { color: #2196F3; }.
- Example:
-
Layout: Styles for major page sections (e.g., header, sidebar, footer).
- Prefix with
l-(e.g.,l-header,l-sidebar).
- Prefix with
-
Module: Reusable components (e.g., buttons, cards, navigation).
- Modules should be independent and nestable (e.g.,
.nav,.card).
- Modules should be independent and nestable (e.g.,
-
State: Styles for dynamic states (e.g., active, disabled, hidden).
- Prefix with
is-(e.g.,is-active,is-hidden). These often use!importantsparingly to override module styles.
- Prefix with
-
Theme (Optional): Styles for visual themes (e.g., dark mode, brand colors).
Example Implementation
Let’s organize a simple page using SMACSS categories:
CSS
/* 1. Base: Resets and defaults */
body {
margin: 0;
font-family: 'Arial', sans-serif;
line-height: 1.6;
}
a {
text-decoration: none;
color: #333;
}
/* 2. Layout: Major sections */
.l-header {
background: #fff;
padding: 16px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.l-container {
max-width: 1200px;
margin: 0 auto;
padding: 0 16px;
}
.l-sidebar {
float: left;
width: 25%;
padding: 16px;
}
.l-main {
float: right;
width: 75%;
padding: 16px;
}
/* 3. Module: Reusable component (button) */
.btn {
display: inline-block;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
}
/* 4. State: Dynamic state for buttons */
.btn.is-disabled {
opacity: 0.5;
cursor: not-allowed;
/* Override hover styles */
pointer-events: none;
}
/* 5. Theme: Dark mode (optional) */
.theme-dark .btn {
background: #333;
color: #fff;
}
HTML
<header class="l-header">
<div class="l-container">
<h1>My Website</h1>
<button class="btn is-disabled">Sign In</button>
</div>
</header>
<div class="l-container">
<aside class="l-sidebar">Sidebar</aside>
<main class="l-main">Main Content</main>
</div>
Pros & Cons
| Pros | Cons |
|---|---|
| Highly organized (clear separation of concerns). | Steeper learning curve than BEM or OOCSS. |
| Scalable for large applications (e.g., enterprise software). | Requires strict discipline to maintain category boundaries. |
| Reduces specificity issues (categories have implicit priority). | Overkill for small projects. |
Comparing BEM, OOCSS, and SMACSS
| Feature | BEM | OOCSS | SMACSS |
|---|---|---|---|
| Core Focus | Naming convention for components | Separating structure/skin and container/content | Categorizing CSS into types |
| Syntax | block__element--modifier | No strict syntax (uses descriptive class names) | Category prefixes (l-, is-) |
| Key Strength | Clarity in component relationships | Maximum reusability | Scalability via organization |
| Best For | Large teams, component-based UIs (React/Vue) | UI libraries, reusable design systems | Enterprise apps, complex websites |
| Learning Curve | Moderate (strict naming) | Easy (simple principles) | Steep (5 categories to master) |
When to Use Each Methodology
-
Choose BEM if:
- You’re working with a large team and need strict naming conventions.
- Your project uses component-based frameworks (React, Vue, Angular).
- You want to avoid specificity wars.
-
Choose OOCSS if:
- You’re building a UI library with highly reusable components (e.g., buttons, cards).
- You prioritize minimal code duplication.
- Your team prefers flexibility over rigid structure.
-
Choose SMACSS if:
- You’re working on a large-scale application with complex layouts.
- You need strict organization to manage thousands of CSS rules.
- Your project requires theming or dynamic state management.
Conclusion
BEM, OOCSS, and SMACSS are not mutually exclusive—many teams combine their principles (e.g., BEM naming with OOCSS’s structure/skin separation). The key is to choose a methodology that aligns with your project’s size, team expertise, and long-term goals.
Remember: The best CSS architecture is one that your team can consistently follow. Start with the basics, iterate, and adapt as your project evolves.