CSS Architecture: BEM, OOCSS, SMACSS
Lesson 36 โข Advanced Track
What You'll Learn
- Apply BEM naming (Block__Element--Modifier) for predictable CSS
- Understand OOCSS: separate structure from skin
- Organize styles using SMACSS categories (Base, Layout, Module, State, Theme)
- Compare modern approaches: utility-first CSS and CSS Modules
- Choose the right methodology for your project size
๐ก Real-World Analogy
CSS architecture is like organising a kitchen. Without a system, utensils end up in random drawers. BEM labels every drawer (block), shelf (element), and size (modifier). SMACSS groups by category: pots together, spices together. OOCSS uses one handle design for all cabinets โ separating the shared structure from individual appearance.
Why CSS Architecture Matters
CSS has no built-in scoping or module system. In a large codebase, class name collisions, specificity battles, and unpredictable overrides make stylesheets unmaintainable. CSS architecture methodologies solve this by providing naming conventions and organisational rules.
The goal isn't to follow rules for their own sake โ it's to make your CSS predictable (you know where to find styles), reusable (components work independently), and scalable (new features don't break existing ones).
Methodology Comparison
| Method | Core Idea | Naming | Best For |
|---|---|---|---|
| BEM | Flat naming convention | .block__element--modifier | Teams, large codebases |
| OOCSS | Separate structure & skin | .media + .media--bordered | Reusable component libraries |
| SMACSS | Categorise rules | l-layout, is-state | Medium-large projects |
| Utility-first | Compose from utilities | .flex .gap-4 .text-sm | Rapid prototyping, Tailwind |
1. BEM in Practice
<!DOCTYPE html>
<html><head><style>
body { font-family: system-ui, sans-serif; padding: 24px; background: #fafafa; }
.card { background: white; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.08); overflow: hidden; max-width: 350px; margin: 16px 0; }
.card__header { padding: 20px 20px 0; }
.card__title { margin: 0; font-size: 1.25rem; color: #1a1a1a; }
.card__body { padding: 12px 20px 20px; color: #555; line-height: 1.6; }
.card__footer { padding: 12px 20px; border-top: 1px solid #eee; d
... BEM golden rule: Never nest more than one level. Write .card__title, not .card__header__title. If an element feels too deeply nested, it should be its own block.
2. OOCSS: Structure vs Skin
<!DOCTYPE html>
<html><head><style>
body { font-family: system-ui, sans-serif; padding: 24px; }
/* Structure (shared) */
.media { display: flex; gap: 16px; padding: 16px; border-radius: 8px; margin: 12px 0; }
.media__img { width: 64px; height: 64px; border-radius: 8px; object-fit: cover; flex-shrink: 0; }
.media__body { flex: 1; }
.media__title { margin: 0 0 4px; font-weight: 700; }
.media__text { margin: 0; color: #555; line-height: 1.5; }
/* Skin (variations) */
.media--light { background: #f5
...3. SMACSS Categories
<!DOCTYPE html>
<html><head><style>
/* ============ BASE ============ */
body { font-family: system-ui, sans-serif; margin: 0; color: #1a1a1a; line-height: 1.6; }
h1, h2, h3 { margin-top: 0; }
a { color: #1976D2; text-decoration: none; }
a:hover { text-decoration: underline; }
/* ============ LAYOUT ============ */
.l-container { max-width: 700px; margin: 0 auto; padding: 24px; }
.l-header { background: #1976D2; color: white; padding: 16px 24px; }
.l-sidebar { background: #f5f5f5; padding: 16px;
...4. Modern Hybrid Approach
<!DOCTYPE html>
<html><head><style>
body { font-family: system-ui, sans-serif; padding: 24px; }
h2 { color: #1565C0; }
/* Modern: Utility + Component hybrid */
:root { --primary: #1976D2; --danger: #D32F2F; --success: #2E7D32; --radius: 8px; --shadow: 0 2px 8px rgba(0,0,0,0.08); }
/* Component */
.card { background: white; border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden; }
.card-body { padding: 20px; }
.card-footer { padding: 12px 20px; border-top: 1px solid #eee; displ
...When to Use This
- BEM: Vanilla CSS projects with teams. Everyone follows the same naming system.
- OOCSS: Building a shared component library used across projects.
- SMACSS: Large applications needing strict file organisation.
- Utility-first: When speed matters more than semantic naming (prototyping, Tailwind).
- CSS Modules: React, Vue, or Svelte projects where build tools handle scoping.
Common Mistakes
- Over-nesting in BEM โ Never write
.card__header__title. Flatten to.card__title. - Mixing methodologies randomly โ Pick one system and be consistent within a project. Mixing BEM with SMACSS creates confusion.
- Too many modifiers โ If an element has 5+ modifiers, it may need to be a separate block/component.
- Overusing !important โ If you need !important, your architecture has a specificity problem. Fix the structure.
- Not documenting the system โ Architecture only works if the team knows the rules. Create a style guide.
- Premature abstraction โ Don't create a reusable component class until you've used the pattern at least 3 times.
๐ Lesson Complete
- โ BEM uses Block__Element--Modifier for conflict-free flat naming
- โ OOCSS separates structural CSS from visual skin for maximum reuse
- โ SMACSS categorises styles into Base, Layout (l-), Module, State (is-), Theme
- โ Utility-first (Tailwind) composes styles from small, single-purpose classes
- โ CSS Modules provide automatic scoping in component frameworks
- โ Consistency matters more than which methodology you pick
- โ Don't over-nest, don't use !important, and document your conventions
- โ Modern projects often combine components + utilities for flexibility
Sign up for free to track which lessons you've completed and get learning reminders.