HomeCSS Tailwind
Chapter 11

11 — CSS Architecture

BEM Methodology

<!-- Block -->
<div class="card">
  <!-- Element -->
  <img class="card__image" src="...">
  
  <!-- Element with Modifier -->
  <div class="card__content card__content--featured">
    <h3 class="card__title">Title</h3>
    <p class="card__description">Description</p>
  </div>
</div>
/* Block */
.card { }
 
/* Element */
.card__image { }
.card__content { }
 
/* Modifier */
.card__content--featured { }
.card--dark { }

ITCSS (Inverted Triangle)

Settings    → Variables, config
Tools       → Mixins, functions
Generic     → Reset, box-sizing
Elements    → HTML tags (h1, a, etc.)
Objects     → Layout (grid, container)
Components  → UI (button, card)
Utilities   → Helpers (mt-4, text-center)

File Structure

styles/
├── _settings.colors.scss
├── _settings.fonts.scss
├── _tools.mixins.scss
├── _tools.functions.scss
├── _generic.reset.scss
├── _elements.headings.scss
├── _elements.links.scss
├── _objects.container.scss
├── _objects.grid.scss
├── _components.card.scss
├── _components.button.scss
└── utilities
    ├── _utilities.spacing.scss
    └── _utilities.display.scss

SMACSS

Base    → Resets, defaults
Layout  → Header, footer, sidebar
Module  → Reusable components (button, card)
State   → Active, hidden, error
Theme   → Color schemes

7-1 Pattern

partials/
├── _abstracts/     → Variables, mixins, functions
├── _vendors/       → Third-party CSS
├── _base/          → Resets, typography
├── _layout/        → Header, footer, grid
├── _components/    → Button, card, nav
├── _pages/         → Home, about (page-specific)
└── _themes/        → Dark mode, themes

Mobile-First vs Desktop-First

Mobile-First (Recommended)

/* Base: Mobile styles */
.container { padding: 1rem; }
 
/* Tablet */
@media (min-width: 768px) {
  .container { padding: 2rem; }
}
 
/* Desktop */
@media (min-width: 1024px) {
  .container { padding: 4rem; }
}

Desktop-First

/* Base: Desktop styles */
.container { padding: 4rem; }
 
/* Tablet */
@media (max-width: 1023px) {
  .container { padding: 2rem; }
}
 
/* Mobile */
@media (max-width: 767px) {
  .container { padding: 1rem; }
}

Naming Conventions

PascalCase (React Components)

function UserProfile() { }
function PrimaryButton() { }

kebab-case (CSS Classes)

.user-profile { }
.primary-button { }
.card-title { }

camelCase (JavaScript Variables)

const userProfile = document.querySelector('.user-profile');

File Structure Examples

React + Tailwind

src/
├── components/
│   ├── Button/
│   │   ├── Button.jsx
│   │   └── Button.module.css
│   ├── Card/
│   │   ├── Card.jsx
│   │   └── Card.module.css
│   └── Layout/
│       ├── Header.jsx
│       └── Footer.jsx
├── pages/
│   ├── Home.jsx
│   └── About.jsx
├── styles/
│   ├── globals.css
│   └── tailwind.css
└── App.jsx

Vanilla CSS

src/
├── css/
│   ├── base/
│   │   ├── _reset.css
│   │   └── _typography.css
│   ├── components/
│   │   ├── _button.css
│   │   └── _card.css
│   ├── layout/
│   │   ├── _header.css
│   │   └── _footer.css
│   └── main.css
└── index.html

SCSS

src/
├── scss/
│   ├── abstract/
│   │   ├── _variables.scss
│   │   └── _mixins.scss
│   ├── base/
│   │   ├── _reset.scss
│   │   └── _base.scss
│   ├── components/
│   │   ├── _button.scss
│   │   └── _card.scss
│   └── main.scss
└── index.html

CSS Modules

/* Button.module.css */
.button {
  padding: 0.5rem 1rem;
  background: blue;
  color: white;
}
 
.primary {
  background: green;
}
import styles from './Button.module.css';
 
function Button({ primary }) {
  return (
    <button className={`${styles.button} ${primary ? styles.primary : ''}`}>
      Click
    </button>
  );
}

Benefits: Scoped styles, no conflicts


Utility-First (Tailwind)

<!-- No custom CSS needed -->
<button class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
  Click
</button>
 
<!-- Extract component if reused -->
<button class="btn-primary">
  Click
</button>
// Extract with @apply (use sparingly)
.btn-primary {
  @apply px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600;
}

Component Composition

// Bad: Too many props
<Button size="large" variant="primary" disabled={false} />
 
// Good: Compose components
<PrimaryButton size="large">
  <ButtonContent icon={<Icon />}>Click</ButtonContent>
</PrimaryButton>
/* Bad: Overly specific */
div.container > ul.list > li.item:first-child { }
 
/* Good: Simple class */
.item { }

State Management

/* Use data attributes for state */
.button { }
.button[data-state="loading"] {
  opacity: 0.7;
  pointer-events: none;
}
 
/* Or classes */
.button.is-loading { }
.button.is-disabled { }
.button.is-active { }
// Toggle state
button.classList.add('is-loading');
button.dataset.state = 'loading';

Theming

/* CSS Custom Properties */
:root {
  --color-primary: #3b82f6;
  --color-secondary: #8b5cf6;
  --font-main: 'Inter', sans-serif;
}
 
[data-theme="dark"] {
  --color-primary: #60a5fa;
  --color-secondary: #a78bfa;
}
 
.button {
  background: var(--color-primary);
  font-family: var(--font-main);
}

Best Practices

✅ Use semantic class names (btn, card, not red-button)
✅ Keep selectors simple (avoid deep nesting)
✅ Mobile-first media queries
✅ Use CSS custom properties for theming
✅ Extract repeated patterns into components
✅ Comment complex CSS decisions
✅ Use linters (stylelint)
 
❌ Avoid !important
❌ Avoid IDs in selectors
❌ Avoid inline styles (except dynamic values)
❌ Avoid over-nesting (max 3 levels)
❌ Avoid presentational class names (float-left)

Code Organization

/* Component: Card */
/* ============================================ */
 
.card {
  /* Structure */
}
 
.card__header {
  /* Element */
}
 
.card--featured {
  /* Modifier */
}
 
/* States */
.card.is-loading { }
.card.is-expanded { }
 
/* Responsive */
@media (min-width: 768px) {
  .card { }
}

Key Takeaways

  • BEM: Block__Element--Modifier for scalable naming
  • ITCSS: Layer CSS from generic to specific
  • Mobile-first: Base styles → media queries for larger screens
  • CSS Modules: Scoped styles for components
  • Utility-first: Tailwind for rapid development
  • Custom properties: Easy theming and dynamic values
  • Keep it simple: Avoid over-engineering, favor readability
  • Consistency: Pick a convention and stick to it