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.scssSMACSS
Base → Resets, defaults
Layout → Header, footer, sidebar
Module → Reusable components (button, card)
State → Active, hidden, error
Theme → Color schemes7-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, themesMobile-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.jsxVanilla CSS
src/
├── css/
│ ├── base/
│ │ ├── _reset.css
│ │ └── _typography.css
│ ├── components/
│ │ ├── _button.css
│ │ └── _card.css
│ ├── layout/
│ │ ├── _header.css
│ │ └── _footer.css
│ └── main.css
└── index.htmlSCSS
src/
├── scss/
│ ├── abstract/
│ │ ├── _variables.scss
│ │ └── _mixins.scss
│ ├── base/
│ │ ├── _reset.scss
│ │ └── _base.scss
│ ├── components/
│ │ ├── _button.scss
│ │ └── _card.scss
│ └── main.scss
└── index.htmlCSS 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