Skip to main content

What are CSS Variables?

CSS Variables (officially called Custom Properties) allow you to store values that you can reuse throughout your stylesheet. Benefits:
  • Maintainability - Change one value, updates everywhere
  • Readability - Semantic names like --color-primary instead of #FFE600
  • Theming - Easy to implement dark mode and themes
  • Dynamic - Can be changed with JavaScript
  • Inheritance - Variables cascade and can be scoped

Defining Variables

Syntax

/* Define */
--variable-name: value;

/* Use */
property: var(--variable-name);

Global Variables with :root

:root is a pseudo-class that selects the <html> element - perfect for global variables.
:root {
  --color-primary: #FFE600;
  --spacing-md: 16px;
  --font-size-base: 1rem;
}

body {
  font-size: var(--font-size-base);
}

.button {
  background-color: var(--color-primary);
  padding: var(--spacing-md);
}
Use :root instead of html for global variables - it has higher specificity and is a common convention.

Naming Conventions

Use descriptive, semantic names:
--yellow: #FFE600;
--16: 16px;
--big: 24px;

Common Prefixes

  • --color- for colors
  • --font- for typography
  • --spacing- for spacing
  • --border- for borders
  • --shadow- for shadows
  • --transition- for animations

Real Variables from the Project

Color System

:root {
  /* Brand colors - Mercado Libre style */
  --color-primary: #FFE600;           /* Yellow */
  --color-primary-dark: #F5D300;      /* Yellow hover */
  --color-secondary: #3483FA;         /* Blue */
  --color-secondary-dark: #2968C8;    /* Blue hover */
  
  /* State colors */
  --color-success: #00A650;           /* Green */
  --color-error: #F23D4F;             /* Red */
  --color-warning: #FF7733;           /* Orange */
  
  /* Neutral colors */
  --color-white: #FFFFFF;
  --color-black: #333333;
  --color-gray-100: #F5F5F5;          /* Lightest */
  --color-gray-200: #EEEEEE;
  --color-gray-300: #CCCCCC;
  --color-gray-400: #999999;          /* Medium */
  --color-gray-500: #666666;
  --color-gray-600: #333333;          /* Darkest */
}
Use numbered scales (100-600) for colors that have multiple shades. Lower numbers = lighter.

Typography System

:root {
  /* Font family */
  --font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 
                      Roboto, Oxygen, Ubuntu, sans-serif;
  
  /* Font sizes (rem units for accessibility) */
  --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: 2rem;              /* 32px */
}

Spacing Scale

:root {
  /* Based on 4px scale for visual rhythm */
  --spacing-xs: 0.25rem;              /* 4px */
  --spacing-sm: 0.5rem;               /* 8px */
  --spacing-md: 1rem;                 /* 16px */
  --spacing-lg: 1.5rem;               /* 24px */
  --spacing-xl: 2rem;                 /* 32px */
  --spacing-2xl: 3rem;                /* 48px */
}
Using a consistent spacing scale (multiples of 4 or 8) creates visual harmony and makes designs feel more polished.

Border & Radius

:root {
  --border-radius-sm: 4px;
  --border-radius-md: 8px;
  --border-radius-lg: 16px;
  --border-radius-full: 9999px;       /* Perfect circle/pill */
}

Shadows

:root {
  /* Box shadow: offset-x offset-y blur spread color */
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15);
}

Transitions

:root {
  --transition-fast: 150ms ease;
  --transition-base: 300ms ease;
  --transition-slow: 500ms ease;
}

Layout Dimensions

:root {
  --container-max-width: 1200px;
  --header-height: 120px;
}

Using Variables

Basic Usage

.button {
  background-color: var(--color-primary);
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
}

.button:hover {
  background-color: var(--color-primary-dark);
}

Fallback Values

Provide a fallback if variable isn’t defined:
.element {
  color: var(--color-text, #333);  /* Uses #333 if --color-text not defined */
}

Nested Variables

Variables can reference other variables:
:root {
  --base-size: 16px;
  --spacing-1x: var(--base-size);        /* 16px */
  --spacing-2x: calc(var(--base-size) * 2);  /* 32px */
}

Real-World Examples

Header with Variables

.header {
  background: linear-gradient(
    to bottom, 
    var(--color-primary), 
    var(--color-primary-dark)
  );
  box-shadow: var(--shadow-sm);
}

.header__container {
  max-width: var(--container-max-width);
  padding: var(--spacing-md) var(--spacing-lg);
  gap: var(--spacing-md);
}

.header__logo-text {
  font-size: var(--font-size-2xl);
  color: var(--color-secondary);
}

.header__nav-link {
  padding: var(--spacing-xs) var(--spacing-sm);
  font-size: var(--font-size-sm);
  color: var(--color-gray-600);
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
}

Product Card with Variables

.product-card {
  background-color: var(--color-white);
  border-radius: var(--border-radius-md);
  box-shadow: var(--shadow-sm);
  transition: transform var(--transition-base),
              box-shadow var(--transition-base);
}

.product-card:hover {
  box-shadow: var(--shadow-lg);
}

.product-card__content {
  padding: var(--spacing-md);
}

.product-card__category {
  padding: var(--spacing-xs) var(--spacing-sm);
  background-color: var(--color-gray-100);
  color: var(--color-gray-500);
  font-size: var(--font-size-xs);
  border-radius: var(--border-radius-sm);
  margin-bottom: var(--spacing-sm);
}

.product-card__price {
  font-size: var(--font-size-xl);
  color: var(--color-gray-600);
  margin-bottom: var(--spacing-md);
}

.product-card__shipping {
  font-size: var(--font-size-xs);
  color: var(--color-success);
}

Scoped Variables

Variables can be scoped to specific elements:
:root {
  --button-bg: var(--color-secondary);
}

.button {
  background-color: var(--button-bg);
}

/* Override for danger buttons */
.button--danger {
  --button-bg: var(--color-error);
  /* Now this button uses red */
}

/* Override for success buttons */
.button--success {
  --button-bg: var(--color-success);
  /* Now this button uses green */
}

Calc() with Variables

Combine variables with calculations:
:root {
  --spacing-base: 8px;
  --spacing-half: calc(var(--spacing-base) / 2);    /* 4px */
  --spacing-double: calc(var(--spacing-base) * 2);  /* 16px */
  --spacing-triple: calc(var(--spacing-base) * 3);  /* 24px */
}

.element {
  margin: var(--spacing-double);
  padding: var(--spacing-half) var(--spacing-base);
}

Dark Mode with Variables

Easily implement dark mode by changing variable values:
:root {
  /* Light mode (default) */
  --color-bg: #FFFFFF;
  --color-text: #333333;
  --color-border: #EEEEEE;
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
  :root {
    --color-bg: #1a1a1a;
    --color-text: #f0f0f0;
    --color-border: #333333;
  }
}

/* Or with class toggle */
.dark-mode {
  --color-bg: #1a1a1a;
  --color-text: #f0f0f0;
  --color-border: #333333;
}

/* All components automatically update! */
body {
  background-color: var(--color-bg);
  color: var(--color-text);
}

JavaScript Integration

Change CSS variables with JavaScript:
// Get variable value
const root = document.documentElement;
const primaryColor = getComputedStyle(root)
  .getPropertyValue('--color-primary');

// Set variable value  
root.style.setProperty('--color-primary', '#FF0000');

// Example: Dynamic theme
function setTheme(theme) {
  if (theme === 'dark') {
    root.style.setProperty('--color-bg', '#1a1a1a');
    root.style.setProperty('--color-text', '#f0f0f0');
  } else {
    root.style.setProperty('--color-bg', '#FFFFFF');
    root.style.setProperty('--color-text', '#333333');
  }
}

Variables vs Preprocessor Variables

FeatureCSS VariablesSass/Less Variables
Browser SupportModern browsersCompile to CSS
DynamicYes, can change at runtimeNo, fixed at compile
JavaScript AccessYesNo
InheritanceYes, cascadesNo
ScopeCan be scopedFile/block scope
Calc()Works with calc()Limited
CSS Variables are native and dynamic. Preprocessor variables (Sass/Less) are compile-time and more powerful for complex logic, but can’t change at runtime.

Common Patterns

Component Variations

.card {
  --card-bg: var(--color-white);
  --card-border: var(--color-gray-200);
  
  background-color: var(--card-bg);
  border: 1px solid var(--card-border);
}

.card--dark {
  --card-bg: var(--color-gray-600);
  --card-border: var(--color-gray-500);
}

.card--primary {
  --card-bg: var(--color-primary);
  --card-border: var(--color-primary-dark);
}

Responsive Spacing

:root {
  --section-padding: var(--spacing-xl);
}

@media (max-width: 768px) {
  :root {
    --section-padding: var(--spacing-md);
  }
}

.section {
  padding: var(--section-padding);
  /* Automatically adjusts on mobile */
}

Color Variations

:root {
  --primary-h: 52;   /* Hue */
  --primary-s: 100%; /* Saturation */
  --primary-l: 50%;  /* Lightness */
  
  --color-primary: hsl(var(--primary-h), var(--primary-s), var(--primary-l));
  --color-primary-light: hsl(var(--primary-h), var(--primary-s), 70%);
  --color-primary-dark: hsl(var(--primary-h), var(--primary-s), 40%);
}

Best Practices

Use semantic names that describe purpose, not appearance
Create a consistent scale (colors, spacing, typography)
Define global variables in :root
Use fallback values for critical variables
Group related variables together in comments
Don’t overuse variables - only create them for values you’ll reuse
Avoid deeply nested variable references - can be hard to debug

Organization Tips

:root {
  /* ========================================
   * COLORS
   * ======================================== */
  --color-primary: #FFE600;
  --color-secondary: #3483FA;
  /* ... */
  
  /* ========================================
   * TYPOGRAPHY
   * ======================================== */
  --font-family-base: sans-serif;
  --font-size-base: 1rem;
  /* ... */
  
  /* ========================================
   * SPACING
   * ======================================== */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  /* ... */
  
  /* ========================================
   * LAYOUT
   * ======================================== */
  --container-max-width: 1200px;
  --header-height: 120px;
  /* ... */
}

Browser Support

CSS Variables are supported in all modern browsers:
  • Chrome 49+
  • Firefox 31+
  • Safari 9.1+
  • Edge 15+
IE11 does not support CSS variables. Use fallbacks or PostCSS if you need IE11 support.

Fallback for Older Browsers

.button {
  background-color: #3483FA;  /* Fallback */
  background-color: var(--color-secondary);  /* Modern */
}

Complete Example: Design System

:root {
  /* Colors */
  --color-primary: #FFE600;
  --color-primary-dark: #F5D300;
  --color-secondary: #3483FA;
  --color-secondary-dark: #2968C8;
  --color-success: #00A650;
  --color-error: #F23D4F;
  --color-gray-100: #F5F5F5;
  --color-gray-600: #333333;
  --color-white: #FFFFFF;
  
  /* Typography */
  --font-family-base: -apple-system, BlinkMacSystemFont, sans-serif;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-xl: 1.25rem;
  
  /* Spacing */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  
  /* Borders */
  --border-radius-sm: 4px;
  --border-radius-md: 8px;
  
  /* Shadows */
  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  --shadow-lg: 0 10px 25px rgba(0, 0, 0, 0.15);
  
  /* Transitions */
  --transition-fast: 150ms ease;
  --transition-base: 300ms ease;
}

/* Usage throughout the app */
.button {
  padding: var(--spacing-sm) var(--spacing-lg);
  background-color: var(--color-secondary);
  color: var(--color-white);
  font-family: var(--font-family-base);
  font-size: var(--font-size-base);
  border-radius: var(--border-radius-sm);
  transition: background-color var(--transition-fast);
}

.button:hover {
  background-color: var(--color-secondary-dark);
}

.card {
  background-color: var(--color-white);
  padding: var(--spacing-lg);
  border-radius: var(--border-radius-md);
  box-shadow: var(--shadow-sm);
}

.card:hover {
  box-shadow: var(--shadow-lg);
}

Next Steps

Animations

Use variables in animations

Responsive Design

Make variables responsive

Build docs developers (and LLMs) love