Modern Css Architecture Design Systems

views

title: 'Modern CSS Architecture: Building Scalable Design Systems' description: 'A comprehensive guide to CSS architecture patterns, custom properties, and design tokens for enterprise applications' category: 'Frontend Development' categorySlug: 'frontend' difficulty: 'intermediate' icon: 'solar:pallete-bold' gradient: 'linear-gradient(135deg, #f5576c, #f093fb)' publishDate: '2025-12-07' readTime: '45 min read' views: '7.8K' tags: 'CSS', 'Design Systems', 'Custom Properties', 'Architecture', 'Sass', 'Tokens' author: name: 'PlayHve' initials: 'PH' role: 'Tech Education Platform' bio: 'Your ultimate destination for cutting-edge technology tutorials. Learn AI, Web3, modern web development, and creative coding.'

Modern CSS Architecture: Building Scalable Design Systems from Scratch

A comprehensive guide to CSS architecture patterns, custom properties, and design tokens for enterprise applications

Introduction

In the modern web development landscape, CSS has evolved far beyond simple styling rules. Today's applications demand sophisticated design systems that scale across teams, maintain consistency, and adapt to changing requirements without breaking existing functionality.

This tutorial explores advanced CSS architecture patterns used by leading tech companies. We'll build a complete design system from the ground up, implementing everything from design tokens to component patterns, with a focus on maintainability and developer experience.

The Evolution of CSS Architecture

CSS has come a long way since its inception. Let's trace the evolution of CSS architecture approaches:

1. Plain CSS (1996-2006)

/* The wild west - no organization */
.button { background: blue; }
.header .button { background: red; }
#sidebar .button { background: green; }

2. Preprocessors Era (2007-2015)

// Variables and nesting with Sass
$primary-color: blue;

.button {
  background: $primary-color;
  
  &:hover {
    background: darken($primary-color, 10%);
  }
}

3. Methodologies Era (2012-Present)

/* BEM: Block Element Modifier */
.button { }
.button--primary { }
.button__icon { }

4. Modern CSS (2020-Present)

/* Native features: Custom Properties, Container Queries, :has() */
.button {
  background: var(--color-primary);
  container-type: inline-size;
}

Setting Up the Design System Foundation

Directory Structure

A well-organized design system follows a clear directory structure:

styles/
溾€ tokens/
?  溾€ colors.css
?  溾€ typography.css
?  溾€ spacing.css
?  溾€ shadows.css
?  溾€ animations.css
?  € breakpoints.css
溾€ base/
?  溾€ reset.css
?  溾€ typography.css
?  € utilities.css
溾€ components/
?  溾€ button.css
?  溾€ card.css
?  溾€ input.css
?  € modal.css
溾€ layouts/
?  溾€ grid.css
?  溾€ container.css
?  € sidebar.css
溾€ themes/
?  溾€ light.css
?  € dark.css
€ main.css

Design Tokens: The Foundation

Design tokens are the atomic values that define your design language. They create a single source of truth:

/* tokens/colors.css */

:root {
  /* Color Primitives - Raw color values */
  --color-white: #ffffff;
  --color-black: #000000;
  
  /* Neutral Palette */
  --color-neutral-50: #fafafa;
  --color-neutral-100: #f5f5f5;
  --color-neutral-200: #e5e5e5;
  --color-neutral-300: #d4d4d4;
  --color-neutral-400: #a3a3a3;
  --color-neutral-500: #737373;
  --color-neutral-600: #525252;
  --color-neutral-700: #404040;
  --color-neutral-800: #262626;
  --color-neutral-900: #171717;
  --color-neutral-950: #0a0a0a;
  
  /* Primary Palette - Brand colors */
  --color-primary-50: #eef2ff;
  --color-primary-100: #e0e7ff;
  --color-primary-200: #c7d2fe;
  --color-primary-300: #a5b4fc;
  --color-primary-400: #818cf8;
  --color-primary-500: #6366f1;
  --color-primary-600: #4f46e5;
  --color-primary-700: #4338ca;
  --color-primary-800: #3730a3;
  --color-primary-900: #312e81;
  --color-primary-950: #1e1b4b;
  
  /* Success Palette */
  --color-success-50: #f0fdf4;
  --color-success-100: #dcfce7;
  --color-success-200: #bbf7d0;
  --color-success-300: #86efac;
  --color-success-400: #4ade80;
  --color-success-500: #22c55e;
  --color-success-600: #16a34a;
  --color-success-700: #15803d;
  --color-success-800: #166534;
  --color-success-900: #14532d;
  
  /* Warning Palette */
  --color-warning-50: #fffbeb;
  --color-warning-100: #fef3c7;
  --color-warning-200: #fde68a;
  --color-warning-300: #fcd34d;
  --color-warning-400: #fbbf24;
  --color-warning-500: #f59e0b;
  --color-warning-600: #d97706;
  --color-warning-700: #b45309;
  --color-warning-800: #92400e;
  --color-warning-900: #78350f;
  
  /* Error Palette */
  --color-error-50: #fef2f2;
  --color-error-100: #fee2e2;
  --color-error-200: #fecaca;
  --color-error-300: #fca5a5;
  --color-error-400: #f87171;
  --color-error-500: #ef4444;
  --color-error-600: #dc2626;
  --color-error-700: #b91c1c;
  --color-error-800: #991b1b;
  --color-error-900: #7f1d1d;
  
  /* Semantic Colors - Use these in components */
  --color-text-primary: var(--color-neutral-900);
  --color-text-secondary: var(--color-neutral-600);
  --color-text-tertiary: var(--color-neutral-500);
  --color-text-disabled: var(--color-neutral-400);
  --color-text-inverse: var(--color-white);
  --color-text-link: var(--color-primary-600);
  --color-text-link-hover: var(--color-primary-700);
  
  --color-bg-primary: var(--color-white);
  --color-bg-secondary: var(--color-neutral-50);
  --color-bg-tertiary: var(--color-neutral-100);
  --color-bg-inverse: var(--color-neutral-900);
  --color-bg-overlay: rgba(0, 0, 0, 0.5);
  
  --color-border-default: var(--color-neutral-200);
  --color-border-strong: var(--color-neutral-300);
  --color-border-focus: var(--color-primary-500);
}

Typography Tokens

/* tokens/typography.css */

:root {
  /* Font Families */
  --font-family-sans: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 
                      'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  --font-family-serif: 'Merriweather', Georgia, 'Times New Roman', serif;
  --font-family-mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', 
                      Menlo, Monaco, Consolas, monospace;
  
  /* Font Sizes - Using a modular scale (1.25 ratio) */
  --font-size-xs: 0.75rem;     /* 12px */
  --font-size-sm: 0.875rem;    /* 14px */
  --font-size-base: 1rem;      /* 16px */
  --font-size-lg: 1.125rem;    /* 18px */
  --font-size-xl: 1.25rem;     /* 20px */
  --font-size-2xl: 1.5rem;     /* 24px */
  --font-size-3xl: 1.875rem;   /* 30px */
  --font-size-4xl: 2.25rem;    /* 36px */
  --font-size-5xl: 3rem;       /* 48px */
  --font-size-6xl: 3.75rem;    /* 60px */
  --font-size-7xl: 4.5rem;     /* 72px */
  
  /* Line Heights */
  --line-height-none: 1;
  --line-height-tight: 1.25;
  --line-height-snug: 1.375;
  --line-height-normal: 1.5;
  --line-height-relaxed: 1.625;
  --line-height-loose: 2;
  
  /* Font Weights */
  --font-weight-thin: 100;
  --font-weight-extralight: 200;
  --font-weight-light: 300;
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --font-weight-extrabold: 800;
  --font-weight-black: 900;
  
  /* Letter Spacing */
  --letter-spacing-tighter: -0.05em;
  --letter-spacing-tight: -0.025em;
  --letter-spacing-normal: 0;
  --letter-spacing-wide: 0.025em;
  --letter-spacing-wider: 0.05em;
  --letter-spacing-widest: 0.1em;
  
  /* Semantic Typography */
  --text-heading-font: var(--font-family-sans);
  --text-body-font: var(--font-family-sans);
  --text-code-font: var(--font-family-mono);
}

Spacing System

/* tokens/spacing.css */

:root {
  /* Base spacing unit: 4px */
  --spacing-px: 1px;
  --spacing-0: 0;
  --spacing-0-5: 0.125rem;  /* 2px */
  --spacing-1: 0.25rem;     /* 4px */
  --spacing-1-5: 0.375rem;  /* 6px */
  --spacing-2: 0.5rem;      /* 8px */
  --spacing-2-5: 0.625rem;  /* 10px */
  --spacing-3: 0.75rem;     /* 12px */
  --spacing-3-5: 0.875rem;  /* 14px */
  --spacing-4: 1rem;        /* 16px */
  --spacing-5: 1.25rem;     /* 20px */
  --spacing-6: 1.5rem;      /* 24px */
  --spacing-7: 1.75rem;     /* 28px */
  --spacing-8: 2rem;        /* 32px */
  --spacing-9: 2.25rem;     /* 36px */
  --spacing-10: 2.5rem;     /* 40px */
  --spacing-11: 2.75rem;    /* 44px */
  --spacing-12: 3rem;       /* 48px */
  --spacing-14: 3.5rem;     /* 56px */
  --spacing-16: 4rem;       /* 64px */
  --spacing-20: 5rem;       /* 80px */
  --spacing-24: 6rem;       /* 96px */
  --spacing-28: 7rem;       /* 112px */
  --spacing-32: 8rem;       /* 128px */
  --spacing-36: 9rem;       /* 144px */
  --spacing-40: 10rem;      /* 160px */
  --spacing-44: 11rem;      /* 176px */
  --spacing-48: 12rem;      /* 192px */
  --spacing-52: 13rem;      /* 208px */
  --spacing-56: 14rem;      /* 224px */
  --spacing-60: 15rem;      /* 240px */
  --spacing-64: 16rem;      /* 256px */
  --spacing-72: 18rem;      /* 288px */
  --spacing-80: 20rem;      /* 320px */
  --spacing-96: 24rem;      /* 384px */
  
  /* Semantic Spacing */
  --spacing-section: var(--spacing-24);
  --spacing-component: var(--spacing-8);
  --spacing-element: var(--spacing-4);
  --spacing-inline: var(--spacing-2);
}

Shadow System

/* tokens/shadows.css */

:root {
  /* Elevation shadows */
  --shadow-xs: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  
  --shadow-sm: 
    0 1px 3px 0 rgba(0, 0, 0, 0.1),
    0 1px 2px -1px rgba(0, 0, 0, 0.1);
  
  --shadow-md: 
    0 4px 6px -1px rgba(0, 0, 0, 0.1),
    0 2px 4px -2px rgba(0, 0, 0, 0.1);
  
  --shadow-lg: 
    0 10px 15px -3px rgba(0, 0, 0, 0.1),
    0 4px 6px -4px rgba(0, 0, 0, 0.1);
  
  --shadow-xl: 
    0 20px 25px -5px rgba(0, 0, 0, 0.1),
    0 8px 10px -6px rgba(0, 0, 0, 0.1);
  
  --shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  
  --shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.05);
  
  /* Focus ring */
  --shadow-focus: 
    0 0 0 2px var(--color-bg-primary),
    0 0 0 4px var(--color-primary-500);
  
  /* Colored shadows for buttons */
  --shadow-primary: 
    0 4px 14px 0 rgba(99, 102, 241, 0.4);
  
  --shadow-success: 
    0 4px 14px 0 rgba(34, 197, 94, 0.4);
  
  --shadow-warning: 
    0 4px 14px 0 rgba(245, 158, 11, 0.4);
  
  --shadow-error: 
    0 4px 14px 0 rgba(239, 68, 68, 0.4);
}

Animation Tokens

/* tokens/animations.css */

:root {
  /* Duration */
  --duration-instant: 0ms;
  --duration-fast: 100ms;
  --duration-normal: 200ms;
  --duration-slow: 300ms;
  --duration-slower: 500ms;
  --duration-slowest: 700ms;
  
  /* Easing functions */
  --ease-linear: linear;
  --ease-in: cubic-bezier(0.4, 0, 1, 1);
  --ease-out: cubic-bezier(0, 0, 0.2, 1);
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  
  /* Spring-like easings */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  
  /* Semantic transitions */
  --transition-colors: color, background-color, border-color, 
                       text-decoration-color, fill, stroke;
  --transition-opacity: opacity;
  --transition-shadow: box-shadow;
  --transition-transform: transform;
  
  /* Common transitions */
  --transition-fast: all var(--duration-fast) var(--ease-out);
  --transition-normal: all var(--duration-normal) var(--ease-out);
  --transition-slow: all var(--duration-slow) var(--ease-out);
}

/* Keyframe animations */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes fade-out {
  from { opacity: 1; }
  to { opacity: 0; }
}

@keyframes slide-in-up {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slide-in-down {
  from {
    opacity: 0;
    transform: translateY(-20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slide-in-left {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slide-in-right {
  from {
    opacity: 0;
    transform: translateX(20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes scale-in {
  from {
    opacity: 0;
    transform: scale(0.95);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}

@keyframes bounce {
  0%, 100% {
    transform: translateY(-5%);
    animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
  }
  50% {
    transform: translateY(0);
    animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
  }
}

@keyframes shimmer {
  0% {
    background-position: -200% 0;
  }
  100% {
    background-position: 200% 0;
  }
}

Modern CSS Reset

A proper CSS reset ensures consistency across browsers:

/* base/reset.css */

/*
  Modern CSS Reset
  Based on Josh Comeau's CSS Reset and modern best practices
*/

/* Box sizing rules */
*,
*::before,
*::after {
  box-sizing: border-box;
}

/* Prevent font size inflation */
html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

/* Remove default margin and padding */
* {
  margin: 0;
  padding: 0;
}

/* Set core body defaults */
body {
  min-height: 100vh;
  line-height: var(--line-height-normal);
  font-family: var(--font-family-sans);
  font-size: var(--font-size-base);
  color: var(--color-text-primary);
  background-color: var(--color-bg-primary);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Remove list styles */
ul[role='list'],
ol[role='list'] {
  list-style: none;
}

/* Set shorter line heights on headings and interactive elements */
h1, h2, h3, h4, h5, h6,
button, input, label {
  line-height: var(--line-height-tight);
}

/* Balance text wrapping on headings */
h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;
}

/* Improve text wrapping for paragraphs */
p {
  text-wrap: pretty;
}

/* A elements that don't have a class get default styles */
a:not([class]) {
  text-decoration-skip-ink: auto;
  color: currentColor;
}

/* Make images easier to work with */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

/* Remove all animations and transitions for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
  html:focus-within {
    scroll-behavior: auto;
  }
  
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Remove button styling */
button {
  background: none;
  border: none;
  cursor: pointer;
}

/* Make sure textareas without a rows attribute are not tiny */
textarea:not([rows]) {
  min-height: 10em;
}

/* Anything that has been anchored to should have extra scroll margin */
:target {
  scroll-margin-block: 5ex;
}

/* Remove default fieldset styles */
fieldset {
  border: none;
}

/* Focus visible styles */
:focus-visible {
  outline: 2px solid var(--color-border-focus);
  outline-offset: 2px;
}

/* Remove tap highlight on mobile */
* {
  -webkit-tap-highlight-color: transparent;
}

Building Component Patterns

The Button Component

/* components/button.css */

.btn {
  /* Layout */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--spacing-2);
  
  /* Typography */
  font-family: var(--font-family-sans);
  font-weight: var(--font-weight-medium);
  text-decoration: none;
  white-space: nowrap;
  
  /* Visual */
  border-radius: var(--radius-md);
  border: 1px solid transparent;
  cursor: pointer;
  
  /* Transition */
  transition: 
    background-color var(--duration-fast) var(--ease-out),
    border-color var(--duration-fast) var(--ease-out),
    color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out),
    transform var(--duration-fast) var(--ease-out);
  
  /* States */
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    pointer-events: none;
  }
  
  &:active:not(:disabled) {
    transform: scale(0.98);
  }
}

/* Size variants */
.btn--xs {
  height: var(--spacing-7);
  padding-inline: var(--spacing-2-5);
  font-size: var(--font-size-xs);
}

.btn--sm {
  height: var(--spacing-8);
  padding-inline: var(--spacing-3);
  font-size: var(--font-size-sm);
}

.btn--md {
  height: var(--spacing-10);
  padding-inline: var(--spacing-4);
  font-size: var(--font-size-sm);
}

.btn--lg {
  height: var(--spacing-11);
  padding-inline: var(--spacing-5);
  font-size: var(--font-size-base);
}

.btn--xl {
  height: var(--spacing-12);
  padding-inline: var(--spacing-6);
  font-size: var(--font-size-lg);
}

/* Style variants - Primary */
.btn--primary {
  background-color: var(--color-primary-600);
  color: var(--color-white);
  
  &:hover:not(:disabled) {
    background-color: var(--color-primary-700);
  }
  
  &:focus-visible {
    box-shadow: var(--shadow-focus);
  }
  
  &:active:not(:disabled) {
    background-color: var(--color-primary-800);
  }
}

/* Secondary variant */
.btn--secondary {
  background-color: var(--color-neutral-100);
  color: var(--color-text-primary);
  
  &:hover:not(:disabled) {
    background-color: var(--color-neutral-200);
  }
  
  &:focus-visible {
    box-shadow: var(--shadow-focus);
  }
}

/* Outline variant */
.btn--outline {
  background-color: transparent;
  border-color: var(--color-border-default);
  color: var(--color-text-primary);
  
  &:hover:not(:disabled) {
    background-color: var(--color-neutral-50);
    border-color: var(--color-border-strong);
  }
  
  &:focus-visible {
    box-shadow: var(--shadow-focus);
  }
}

/* Ghost variant */
.btn--ghost {
  background-color: transparent;
  color: var(--color-text-primary);
  
  &:hover:not(:disabled) {
    background-color: var(--color-neutral-100);
  }
  
  &:focus-visible {
    box-shadow: var(--shadow-focus);
  }
}

/* Destructive variant */
.btn--destructive {
  background-color: var(--color-error-600);
  color: var(--color-white);
  
  &:hover:not(:disabled) {
    background-color: var(--color-error-700);
  }
  
  &:focus-visible {
    box-shadow: 
      0 0 0 2px var(--color-bg-primary),
      0 0 0 4px var(--color-error-500);
  }
}

/* Icon button */
.btn--icon {
  aspect-ratio: 1;
  padding: 0;
  
  &.btn--xs { width: var(--spacing-7); }
  &.btn--sm { width: var(--spacing-8); }
  &.btn--md { width: var(--spacing-10); }
  &.btn--lg { width: var(--spacing-11); }
  &.btn--xl { width: var(--spacing-12); }
}

/* Full width */
.btn--full {
  width: 100%;
}

/* Loading state */
.btn--loading {
  position: relative;
  color: transparent !important;
  pointer-events: none;
  
  &::after {
    content: '';
    position: absolute;
    width: 1em;
    height: 1em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: 50%;
    animation: spin 0.6s linear infinite;
    color: var(--color-white);
  }
}

/* Button group */
.btn-group {
  display: inline-flex;
  
  & > .btn {
    border-radius: 0;
    
    &:first-child {
      border-top-left-radius: var(--radius-md);
      border-bottom-left-radius: var(--radius-md);
    }
    
    &:last-child {
      border-top-right-radius: var(--radius-md);
      border-bottom-right-radius: var(--radius-md);
    }
    
    &:not(:first-child) {
      margin-left: -1px;
    }
  }
}

The Card Component

/* components/card.css */

.card {
  --card-padding: var(--spacing-6);
  --card-radius: var(--radius-lg);
  --card-bg: var(--color-bg-primary);
  --card-border: var(--color-border-default);
  
  position: relative;
  display: flex;
  flex-direction: column;
  background-color: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  overflow: hidden;
}

/* Card sections */
.card__header {
  display: flex;
  align-items: center;
  gap: var(--spacing-4);
  padding: var(--card-padding);
  border-bottom: 1px solid var(--card-border);
}

.card__title {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-primary);
}

.card__description {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  margin-top: var(--spacing-1);
}

.card__body {
  flex: 1;
  padding: var(--card-padding);
}

.card__footer {
  display: flex;
  align-items: center;
  gap: var(--spacing-3);
  padding: var(--card-padding);
  border-top: 1px solid var(--card-border);
  background-color: var(--color-bg-secondary);
}

/* Card image */
.card__image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Interactive card */
.card--interactive {
  cursor: pointer;
  transition: 
    box-shadow var(--duration-normal) var(--ease-out),
    transform var(--duration-normal) var(--ease-out),
    border-color var(--duration-normal) var(--ease-out);
  
  &:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--color-border-strong);
    transform: translateY(-2px);
  }
  
  &:focus-visible {
    outline: none;
    box-shadow: var(--shadow-focus);
  }
  
  &:active {
    transform: translateY(0);
  }
}

/* Card variants */
.card--elevated {
  border: none;
  box-shadow: var(--shadow-md);
  
  &:hover {
    box-shadow: var(--shadow-lg);
  }
}

.card--ghost {
  border: none;
  background-color: transparent;
  
  & .card__footer {
    background-color: transparent;
    border-top: none;
  }
}

/* Card sizes */
.card--sm {
  --card-padding: var(--spacing-4);
  --card-radius: var(--radius-md);
}

.card--lg {
  --card-padding: var(--spacing-8);
  --card-radius: var(--radius-xl);
}

Form Input Component

/* components/input.css */

.form-group {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2);
}

.form-label {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-primary);
}

.form-label--required::after {
  content: '*';
  color: var(--color-error-500);
  margin-left: var(--spacing-1);
}

.form-input {
  --input-height: var(--spacing-10);
  --input-padding: var(--spacing-3);
  --input-radius: var(--radius-md);
  --input-border: var(--color-border-default);
  --input-bg: var(--color-bg-primary);
  
  width: 100%;
  height: var(--input-height);
  padding-inline: var(--input-padding);
  font-size: var(--font-size-sm);
  background-color: var(--input-bg);
  border: 1px solid var(--input-border);
  border-radius: var(--input-radius);
  transition: 
    border-color var(--duration-fast) var(--ease-out),
    box-shadow var(--duration-fast) var(--ease-out);
  
  &::placeholder {
    color: var(--color-text-tertiary);
  }
  
  &:hover:not(:disabled):not(:focus) {
    border-color: var(--color-border-strong);
  }
  
  &:focus {
    outline: none;
    border-color: var(--color-primary-500);
    box-shadow: 0 0 0 3px var(--color-primary-100);
  }
  
  &:disabled {
    opacity: 0.5;
    cursor: not-allowed;
    background-color: var(--color-bg-secondary);
  }
}

/* Input with icon */
.input-wrapper {
  position: relative;
  display: flex;
  align-items: center;
}

.input-wrapper__icon {
  position: absolute;
  left: var(--spacing-3);
  color: var(--color-text-tertiary);
  pointer-events: none;
}

.input-wrapper__icon--right {
  left: auto;
  right: var(--spacing-3);
}

.input-wrapper .form-input {
  padding-left: var(--spacing-10);
}

.input-wrapper--icon-right .form-input {
  padding-left: var(--spacing-3);
  padding-right: var(--spacing-10);
}

/* Input sizes */
.form-input--sm {
  --input-height: var(--spacing-8);
  --input-padding: var(--spacing-2-5);
  font-size: var(--font-size-xs);
}

.form-input--lg {
  --input-height: var(--spacing-12);
  --input-padding: var(--spacing-4);
  font-size: var(--font-size-base);
}

/* Textarea */
.form-textarea {
  min-height: calc(var(--spacing-10) * 3);
  padding-block: var(--spacing-3);
  resize: vertical;
}

/* Error state */
.form-input--error {
  border-color: var(--color-error-500);
  
  &:focus {
    border-color: var(--color-error-500);
    box-shadow: 0 0 0 3px var(--color-error-100);
  }
}

.form-error {
  font-size: var(--font-size-xs);
  color: var(--color-error-600);
}

/* Success state */
.form-input--success {
  border-color: var(--color-success-500);
  
  &:focus {
    border-color: var(--color-success-500);
    box-shadow: 0 0 0 3px var(--color-success-100);
  }
}

.form-hint {
  font-size: var(--font-size-xs);
  color: var(--color-text-secondary);
}

Container Queries: The Future of Responsive Components

Container queries allow components to respond to their container's size, not the viewport:

/* Modern container query patterns */

.component-container {
  container-type: inline-size;
  container-name: card;
}

/* Container query for card layout */
@container card (min-width: 400px) {
  .responsive-card {
    display: grid;
    grid-template-columns: 200px 1fr;
    
    & .card__image {
      aspect-ratio: 1;
    }
  }
}

@container card (min-width: 600px) {
  .responsive-card {
    grid-template-columns: 250px 1fr;
    
    & .card__body {
      padding: var(--spacing-8);
    }
  }
}

/* Container query for typography */
@container (min-width: 300px) {
  .container-title {
    font-size: var(--font-size-xl);
  }
}

@container (min-width: 500px) {
  .container-title {
    font-size: var(--font-size-2xl);
  }
}

The () Selector: Parent Selection Finally

The :has() selector enables previously impossible patterns:

/* Style parent based on child state */
.form-group:has(.form-input:focus) {
  & .form-label {
    color: var(--color-primary-600);
  }
}

.form-group:has(.form-input--error) {
  & .form-label {
    color: var(--color-error-600);
  }
}

/* Card with image styling */
.card:has(.card__image) {
  & .card__body {
    padding-top: 0;
  }
}

/* Empty state handling */
.list:has(> :first-child) {
  /* Has items - show normally */
}

.list:not(:has(> *)) {
  /* Empty list - show empty state */
  &::after {
    content: 'No items to display';
    color: var(--color-text-secondary);
    text-align: center;
    padding: var(--spacing-8);
  }
}

/* Navigation with active item */
.nav:has(.nav-item--active) {
  --nav-indicator-visible: 1;
}

/* Form validation */
.form:has(:invalid) {
  & .btn[type="submit"] {
    opacity: 0.5;
    pointer-events: none;
  }
}

Theme System with CSS Custom Properties

/* themes/light.css */
:root,
[data-theme="light"] {
  color-scheme: light;
  
  --color-text-primary: var(--color-neutral-900);
  --color-text-secondary: var(--color-neutral-600);
  --color-text-tertiary: var(--color-neutral-500);
  
  --color-bg-primary: var(--color-white);
  --color-bg-secondary: var(--color-neutral-50);
  --color-bg-tertiary: var(--color-neutral-100);
  
  --color-border-default: var(--color-neutral-200);
  --color-border-strong: var(--color-neutral-300);
}

/* themes/dark.css */
[data-theme="dark"] {
  color-scheme: dark;
  
  --color-text-primary: var(--color-neutral-50);
  --color-text-secondary: var(--color-neutral-400);
  --color-text-tertiary: var(--color-neutral-500);
  
  --color-bg-primary: var(--color-neutral-900);
  --color-bg-secondary: var(--color-neutral-800);
  --color-bg-tertiary: var(--color-neutral-700);
  
  --color-border-default: var(--color-neutral-700);
  --color-border-strong: var(--color-neutral-600);
  
  /* Adjust shadows for dark mode */
  --shadow-sm: 
    0 1px 3px 0 rgba(0, 0, 0, 0.3),
    0 1px 2px -1px rgba(0, 0, 0, 0.3);
  
  --shadow-md: 
    0 4px 6px -1px rgba(0, 0, 0, 0.3),
    0 2px 4px -2px rgba(0, 0, 0, 0.3);
  
  --shadow-lg: 
    0 10px 15px -3px rgba(0, 0, 0, 0.3),
    0 4px 6px -4px rgba(0, 0, 0, 0.3);
}

/* System preference detection */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    color-scheme: dark;
    
    --color-text-primary: var(--color-neutral-50);
    --color-text-secondary: var(--color-neutral-400);
    --color-text-tertiary: var(--color-neutral-500);
    
    --color-bg-primary: var(--color-neutral-900);
    --color-bg-secondary: var(--color-neutral-800);
    --color-bg-tertiary: var(--color-neutral-700);
    
    --color-border-default: var(--color-neutral-700);
    --color-border-strong: var(--color-neutral-600);
  }
}

Theme switching JavaScript:

// Theme manager
class ThemeManager {
  constructor() {
    this.STORAGE_KEY = 'theme-preference';
    this.init();
  }
  
  init() {
    const savedTheme = localStorage.getItem(this.STORAGE_KEY);
    if (savedTheme) {
      this.setTheme(savedTheme);
    }
    
    // Watch for system preference changes
    window.matchMedia('(prefers-color-scheme: dark)')
      .addEventListener('change', (e) => {
        if (!localStorage.getItem(this.STORAGE_KEY)) {
          // Only auto-switch if no manual preference
          this.setTheme(e.matches  'dark' : 'light');
        }
      });
  }
  
  setTheme(theme) {
    document.documentElement.setAttribute('data-theme', theme);
    localStorage.setItem(this.STORAGE_KEY, theme);
  }
  
  toggle() {
    const current = document.documentElement.getAttribute('data-theme');
    const next = current === 'dark'  'light' : 'dark';
    this.setTheme(next);
    return next;
  }
  
  getTheme() {
    return document.documentElement.getAttribute('data-theme') || 
           (window.matchMedia('(prefers-color-scheme: dark)').matches  'dark' : 'light');
  }
}

const themeManager = new ThemeManager();

Performance Optimization

Content Visibility for Large Lists

/* Improve rendering performance for long lists */
.virtual-list-item {
  content-visibility: auto;
  contain-intrinsic-size: 0 80px; /* Estimated height */
}

/* Contain layout and paint for performance */
.performance-optimized {
  contain: layout style paint;
}

/* Will-change for animations */
.animated-element {
  will-change: transform, opacity;
}

/* Remove will-change after animation */
.animated-element:not(:hover, :focus, .is-animating) {
  will-change: auto;
}

Critical CSS Pattern

/* Critical CSS - inline in <head> */
:root {
  --color-bg-primary: #ffffff;
  --color-text-primary: #171717;
}

body {
  margin: 0;
  font-family: system-ui, sans-serif;
  background: var(--color-bg-primary);
  color: var(--color-text-primary);
}

/* Above-the-fold layout */
.header {
  height: 64px;
  display: flex;
  align-items: center;
}

.hero {
  min-height: 50vh;
  display: flex;
  align-items: center;
}

Utility Class Generation

/* base/utilities.css */

/* Display utilities */
.hidden { display: none; }
.block { display: block; }
.inline { display: inline; }
.inline-block { display: inline-block; }
.flex { display: flex; }
.inline-flex { display: inline-flex; }
.grid { display: grid; }

/* Flexbox utilities */
.flex-row { flex-direction: row; }
.flex-col { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }
.flex-nowrap { flex-wrap: nowrap; }

.items-start { align-items: flex-start; }
.items-center { align-items: center; }
.items-end { align-items: flex-end; }
.items-stretch { align-items: stretch; }

.justify-start { justify-content: flex-start; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.justify-between { justify-content: space-between; }
.justify-around { justify-content: space-around; }

.flex-1 { flex: 1 1 0%; }
.flex-auto { flex: 1 1 auto; }
.flex-none { flex: none; }

/* Gap utilities */
.gap-1 { gap: var(--spacing-1); }
.gap-2 { gap: var(--spacing-2); }
.gap-3 { gap: var(--spacing-3); }
.gap-4 { gap: var(--spacing-4); }
.gap-5 { gap: var(--spacing-5); }
.gap-6 { gap: var(--spacing-6); }
.gap-8 { gap: var(--spacing-8); }

/* Text utilities */
.text-left { text-align: left; }
.text-center { text-align: center; }
.text-right { text-align: right; }

.text-xs { font-size: var(--font-size-xs); }
.text-sm { font-size: var(--font-size-sm); }
.text-base { font-size: var(--font-size-base); }
.text-lg { font-size: var(--font-size-lg); }
.text-xl { font-size: var(--font-size-xl); }
.text-2xl { font-size: var(--font-size-2xl); }
.text-3xl { font-size: var(--font-size-3xl); }

.font-normal { font-weight: var(--font-weight-normal); }
.font-medium { font-weight: var(--font-weight-medium); }
.font-semibold { font-weight: var(--font-weight-semibold); }
.font-bold { font-weight: var(--font-weight-bold); }

/* Visibility utilities */
.visible { visibility: visible; }
.invisible { visibility: hidden; }

.opacity-0 { opacity: 0; }
.opacity-50 { opacity: 0.5; }
.opacity-100 { opacity: 1; }

/* Screen reader only */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.not-sr-only {
  position: static;
  width: auto;
  height: auto;
  padding: 0;
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
}

Conclusion

Building a modern CSS architecture requires thoughtful planning and consistent patterns. The design system we've built provides:

  1. Scalability: Design tokens make global changes trivial
  2. Consistency: Shared primitives ensure visual harmony
  3. Maintainability: Clear organization and naming conventions
  4. Performance: Modern CSS features and optimization techniques
  5. Accessibility: Built-in focus states and reduced motion support
  6. Theming: Seamless light/dark mode support

Key Takeaways

  • Start with design tokens as your single source of truth
  • Use CSS custom properties for runtime theming
  • Leverage modern CSS features like container queries and :has()
  • Build components with clear, predictable APIs
  • Optimize for performance from the start
  • Always consider accessibility

This architecture will serve as a solid foundation for any modern web application, from small projects to enterprise-scale systems.


This tutorial is part of the PlayHve Frontend Development series. Explore more advanced CSS techniques in our upcoming tutorials.

Written by