Introduction to CSS Variables
CSS custom properties (variables) allow you to store values that can be reused throughout your stylesheet. They make CSS more maintainable, enable theming, and can be updated with JavaScript.
Basic CSS Variables
css
/* Define variables in :root for global scope */
:root {
  --primary-color: #3498db;
  --secondary-color: #e74c3c;
  --font-size-base: 16px;
  --spacing-unit: 8px;
  --border-radius: 4px;
}
/* Use variables with var() function */
.button {
  background: var(--primary-color);
  color: white;
  font-size: var(--font-size-base);
  padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);
  border-radius: var(--border-radius);
  border: none;
  cursor: pointer;
}
.button:hover {
  background: var(--secondary-color);
}
Variable Fallbacks
css
/* Provide fallback values */
.element {
  color: var(--text-color, #333); /* Falls back to #333 if --text-color is undefined */
  background: var(--bg-color, var(--fallback-bg, white)); /* Multiple fallbacks */
}
Local Scope Variables
css
/* Variables can be scoped to specific elements */
.card {
  --card-padding: 20px;
  --card-bg: #f9f9f9;
  
  background: var(--card-bg);
  padding: var(--card-padding);
}
.card.featured {
  --card-bg: #e8f4f8; /* Override for featured cards */
  --card-padding: 30px;
}
The calc() Function
The calc() function performs calculations with mixed units:
css
/* Basic calculations */
.container {
  width: calc(100% - 40px); /* Full width minus padding */
  height: calc(100vh - 60px); /* Full height minus header */
  margin: calc(var(--spacing-unit) * 2) auto;
}
/* Complex calculations */
.grid-item {
  width: calc((100% - 40px) / 3); /* 3 columns with gaps */
  margin-right: calc(var(--gap) / 2);
}
/* Math operations in calc() */
.element {
  font-size: calc(16px + 2vw); /* Responsive font size */
  padding: calc(var(--base-padding) * 1.5);
  top: calc(50% - var(--element-height) / 2); /* Center vertically */
}
Practical Examples
Color System with Variables
css
:root {
  /* Base colors */
  --color-blue: #3498db;
  --color-red: #e74c3c;
  --color-green: #2ecc71;
  
  /* Semantic colors using base colors */
  --color-primary: var(--color-blue);
  --color-danger: var(--color-red);
  --color-success: var(--color-green);
  
  /* Variants */
  --color-primary-light: #5dade2;
  --color-primary-dark: #2980b9;
}
.btn-primary { background: var(--color-primary); }
.btn-danger { background: var(--color-danger); }
.text-success { color: var(--color-success); }
Spacing System
css
:root {
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 16px;
  --space-4: 24px;
  --space-5: 32px;
  --space-6: 48px;
}
.mb-1 { margin-bottom: var(--space-1); }
.mb-2 { margin-bottom: var(--space-2); }
.p-3 { padding: var(--space-3); }
.gap-4 { gap: var(--space-4); }
Responsive Typography
css
:root {
  --font-scale: 1.2;
  --font-size-sm: calc(var(--font-size-base) / var(--font-scale));
  --font-size-base: 16px;
  --font-size-lg: calc(var(--font-size-base) * var(--font-scale));
  --font-size-xl: calc(var(--font-size-lg) * var(--font-scale));
  --font-size-xxl: calc(var(--font-size-xl) * var(--font-scale));
}
h1 { font-size: var(--font-size-xxl); }
h2 { font-size: var(--font-size-xl); }
h3 { font-size: var(--font-size-lg); }
p { font-size: var(--font-size-base); }
small { font-size: var(--font-size-sm); }
Complete Theme System Example
html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS Variables Theme System</title>
  <style>
    :root {
      /* Light theme (default) */
      --bg-primary: #ffffff;
      --bg-secondary: #f8f9fa;
      --text-primary: #212529;
      --text-secondary: #6c757d;
      --accent: #007bff;
      --border: #dee2e6;
      
      /* Spacing */
      --space-xs: 4px;
      --space-sm: 8px;
      --space-md: 16px;
      --space-lg: 24px;
      --space-xl: 32px;
      
      /* Sizing */
      --border-radius: 8px;
      --font-size-base: 16px;
      --line-height: 1.5;
      
      /* Transitions */
      --transition-fast: 0.2s ease;
      --transition-normal: 0.3s ease;
    }
    
    /* Dark theme */
    [data-theme="dark"] {
      --bg-primary: #121212;
      --bg-secondary: #1e1e1e;
      --text-primary: #ffffff;
      --text-secondary: #b0b0b0;
      --accent: #4dabf7;
      --border: #333;
    }
    
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    
    body {
      background: var(--bg-primary);
      color: var(--text-primary);
      font-family: Arial, sans-serif;
      font-size: var(--font-size-base);
      line-height: var(--line-height);
      transition: background var(--transition-normal), color var(--transition-normal);
    }
    
    .container {
      max-width: 800px;
      margin: 0 auto;
      padding: var(--space-lg);
    }
    
    .header {
      background: var(--bg-secondary);
      padding: var(--space-lg);
      border-radius: var(--border-radius);
      margin-bottom: var(--space-lg);
      border: 1px solid var(--border);
      display: flex;
      justify-content: space-between;
      align-items: center;
    }
    
    .theme-toggle {
      background: var(--accent);
      color: white;
      border: none;
      padding: var(--space-sm) var(--space-md);
      border-radius: calc(var(--border-radius) / 2);
      cursor: pointer;
      font-size: calc(var(--font-size-base) * 0.9);
      transition: transform var(--transition-fast);
    }
    
    .theme-toggle:hover {
      transform: scale(1.05);
    }
    
    .card {
      background: var(--bg-secondary);
      border: 1px solid var(--border);
      border-radius: var(--border-radius);
      padding: var(--space-lg);
      margin-bottom: var(--space-md);
      transition: all var(--transition-normal);
    }
    
    .card:hover {
      transform: translateY(calc(var(--space-xs) * -1));
      box-shadow: 0 calc(var(--space-sm)) calc(var(--space-lg)) rgba(0,0,0,0.1);
    }
    
    .card h3 {
      color: var(--accent);
      margin-bottom: var(--space-sm);
      font-size: calc(var(--font-size-base) * 1.25);
    }
    
    .card p {
      color: var(--text-secondary);
      margin-bottom: var(--space-md);
    }
    
    .button {
      background: var(--accent);
      color: white;
      border: none;
      padding: calc(var(--space-sm) * 1.5) var(--space-md);
      border-radius: calc(var(--border-radius) / 2);
      cursor: pointer;
      font-size: var(--font-size-base);
      transition: all var(--transition-fast);
      text-decoration: none;
      display: inline-block;
    }
    
    .button:hover {
      background: color-mix(in srgb, var(--accent) 80%, black);
      transform: translateY(calc(var(--space-xs) * -0.5));
    }
    
    .stats {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: var(--space-md);
      margin-top: var(--space-lg);
    }
    
    .stat {
      background: var(--bg-secondary);
      padding: var(--space-md);
      border-radius: var(--border-radius);
      text-align: center;
      border: 1px solid var(--border);
    }
    
    .stat-number {
      font-size: calc(var(--font-size-base) * 2);
      font-weight: bold;
      color: var(--accent);
      display: block;
    }
    
    .stat-label {
      color: var(--text-secondary);
      font-size: calc(var(--font-size-base) * 0.9);
      margin-top: var(--space-xs);
    }
  </style>
</head>
<body>
  <div class="container">
    <header class="header">
      <h1>CSS Variables Demo</h1>
      <button class="theme-toggle" onclick="toggleTheme()">🌙 Dark Theme</button>
    </header>
    
    <main>
      <div class="card">
        <h3>What are CSS Variables?</h3>
        <p>CSS custom properties allow you to store values that can be reused throughout your stylesheet, making maintenance easier and enabling features like theming.</p>
        <a href="#" class="button">Learn More</a>
      </div>
      
      <div class="card">
        <h3>Dynamic Calculations</h3>
        <p>The calc() function lets you perform calculations with different units, creating responsive and flexible layouts.</p>
        <a href="#" class="button">Explore calc()</a>
      </div>
      
      <div class="stats">
        <div class="stat">
          <span class="stat-number">100%</span>
          <span class="stat-label">Browser Support</span>
        </div>
        <div class="stat">
          <span class="stat-number">50%</span>
          <span class="stat-label">Less CSS Code</span>
        </div>
        <div class="stat">
          <span class="stat-number">∞</span>
          <span class="stat-label">Possibilities</span>
        </div>
      </div>
    </main>
  </div>
  
  <script>
    function toggleTheme() {
      const body = document.body;
      const button = document.querySelector('.theme-toggle');
      
      if (body.getAttribute('data-theme') === 'dark') {
        body.removeAttribute('data-theme');
        button.textContent = '🌙 Dark Theme';
      } else {
        body.setAttribute('data-theme', 'dark');
        button.textContent = '☀️ Light Theme';
      }
    }
    
    // You can also update CSS variables with JavaScript
    function updateAccentColor(color) {
      document.documentElement.style.setProperty('--accent', color);
    }
  </script>
</body>
</html>
Advanced calc() Techniques
css
/* Responsive font sizes */
.responsive-text {
  font-size: calc(16px + (24 - 16) * ((100vw - 320px) / (1200 - 320)));
  /* Min 16px at 320px viewport, max 24px at 1200px viewport */
}
/* Perfect centering */
.centered {
  position: absolute;
  top: calc(50% - var(--element-height) / 2);
  left: calc(50% - var(--element-width) / 2);
}
/* Grid with gaps */
.grid-3-col {
  width: calc((100% - 40px) / 3); /* 3 columns, 20px gap each side */
  margin-right: 20px;
}
.grid-3-col:nth-child(3n) {
  margin-right: 0; /* Remove margin from last column */
}
JavaScript Integration
javascript
// Get CSS variable value
const primaryColor = getComputedStyle(document.documentElement)
  .getPropertyValue('--primary-color');
// Set CSS variable value
document.documentElement.style.setProperty('--primary-color', '#ff6b6b');
// Remove CSS variable
document.documentElement.style.removeProperty('--primary-color');
// Check if CSS variables are supported
if (CSS.supports('--test', 'value')) {
  // CSS variables are supported
  console.log('CSS variables supported!');
}
Best Practices
- Use meaningful names - --primary-color not --blue
- Group related variables - Keep spacing, colors, typography together
- Provide fallbacks - Always include fallback values
- Use :root for globals - Define global variables in :root
- Scope appropriately - Use local scope for component-specific values
- Document your system - Comment your variable usage