CSS Custom Properties (Variables): Complete Guide

Hey there, CSS explorer! 👋 Ready to make your stylesheets more dynamic and maintainable? Today, we’re diving into CSS Custom Properties (also known as CSS Variables). Get ready to write smarter, more flexible CSS that’s a joy to maintain!

Key Takeaways

  • CSS Custom Properties allow you to create reusable variables in your stylesheets, making code maintenance easier and more dynamic.
  • They start with -- and are accessed using the var() function, making them easy to implement throughout your code base.
  • You can define them globally using :root for site-wide use, or locally within specific components for more targeted styling.
  • Theme switching becomes simple – just change the variables’ values to completely transform your site’s appearance, perfect for implementing light/dark modes.
  • JavaScript can interact with Custom Properties, letting you create dynamic, interactive styling that responds to user actions or preferences.

What Are CSS Custom Properties?

Think of CSS Custom Properties as variables you can use throughout your stylesheets. They start with -- and are accessed using the var() function. Here’s a simple example:

:root {
--primary-color: #3498db;
--spacing-unit: 1rem;
--border-radius: 4px;
}

.button {
background-color: var(--primary-color);
padding: var(--spacing-unit);
border-radius: var(--border-radius);
}

Why Use Custom Properties?

  1. Easy Theme Switching
  2. More Maintainable Code
  3. Dynamic Changes with JavaScript
  4. Contextual Values

Basic Syntax and Usage

Declaring Custom Properties

/* Global scope */
:root {
--main-color: #333;
--header-height: 60px;
--content-width: 1200px;
}

/* Local scope */
.card {
--card-padding: 1.5rem;
--card-bg: #f8f9fa;
}

Using Custom Properties

.element {
/* Basic usage */
color: var(--main-color);

/* With fallback value */
padding: var(--element-padding, 1rem);

/* Multiple variables */
margin: var(--spacing-y) var(--spacing-x);
}

Real-World Example: Theme System

/* Define theme variables */
:root {
/* Colors */
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-text: #333;
--color-background: #fff;

/* Typography */
--font-size-base: 16px;
--font-size-h1: 2.5rem;
--font-size-h2: 2rem;
--font-family-main: 'Arial', sans-serif;

/* Spacing */
--spacing-small: 0.5rem;
--spacing-medium: 1rem;
--spacing-large: 2rem;

/* Layout */
--container-width: 1200px;
--border-radius: 4px;
}

/* Dark theme */
[data-theme="dark"] {
--color-primary: #5dade2;
--color-secondary: #52be80;
--color-text: #f5f5f5;
--color-background: #1a1a1a;
}

/* Using the variables */
body {
font-family: var(--font-family-main);
font-size: var(--font-size-base);
color: var(--color-text);
background-color: var(--color-background);
}

.container {
max-width: var(--container-width);
padding: var(--spacing-medium);
margin: 0 auto;
}

.button {
background-color: var(--color-primary);
padding: var(--spacing-small) var(--spacing-medium);
border-radius: var(--border-radius);
color: white;
}

Advanced Techniques

1. Calculated Values

:root {
--spacing-unit: 8px;
}

.element {
/* Using calc() with custom properties */
padding: calc(var(--spacing-unit) * 2);
margin-bottom: calc(var(--spacing-unit) * 4);
}

2. Complex Values

:root {
--shadow-color: rgba(0, 0, 0, 0.1);
--shadow-offset: 0 2px 4px;
}

.card {
/* Combining multiple values */
box-shadow: var(--shadow-offset) var(--shadow-color);
}

3. Responsive Values

:root {
--content-padding: 1rem;
}

@media (min-width: 768px) {
:root {
--content-padding: 2rem;
}
}

.content {
padding: var(--content-padding);
}

Working with JavaScript

Reading Custom Properties

// Get the value of a custom property
const rootStyles = getComputedStyle(document.documentElement);
const primaryColor = rootStyles.getPropertyValue('--primary-color');

Setting Custom Properties

// Set a custom property value
document.documentElement.style.setProperty('--primary-color', '#ff0000');

Theme Switching Example

/* Theme definitions */
:root {
/* Light theme (default) */
--color-bg: #ffffff;
--color-text: #333333;
--color-primary: #3498db;
--color-secondary: #2ecc71;
--color-accent: #e74c3c;
}

[data-theme="dark"] {
--color-bg: #1a1a1a;
--color-text: #f5f5f5;
--color-primary: #5dade2;
--color-secondary: #52be80;
--color-accent: #ef5350;
}
// Theme toggle function
function toggleTheme() {
const root = document.documentElement;
const currentTheme = root.getAttribute('data-theme');
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', newTheme);
}

Component-Based Architecture

/* Component variables */
.card {
--card-padding: var(--spacing-medium);
--card-bg: var(--color-background);
--card-border: 1px solid rgba(0, 0, 0, 0.1);

padding: var(--card-padding);
background: var(--card-bg);
border: var(--card-border);
}

/* Component variants */
.card--compact {
--card-padding: var(--spacing-small);
}

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

Best Practices

  1. Naming Conventions
/* Use meaningful, structured names */
:root {
--color-primary-100: #ebf5fb;
--color-primary-500: #3498db;
--color-primary-900: #1a5276;

--spacing-xs: 0.25rem;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
--spacing-xl: 4rem;
}
  1. Organization
:root {
/* Colors */
--color-brand: #3498db;
--color-text: #333;

/* Typography */
--font-size-base: 16px;
--line-height: 1.5;

/* Layout */
--container-width: 1200px;
--grid-gap: 2rem;

/* Animation */
--transition-fast: 0.2s;
--transition-slow: 0.5s;
}
  1. Scoping
/* Global variables */
:root {
--spacing-unit: 8px;
}

/* Component-specific variables */
.modal {
--modal-width: 600px;
--modal-padding: calc(var(--spacing-unit) * 3);
}

Practice Exercise: Create a Button System

Try creating this flexible button system:

:root {
/* Base variables */
--button-padding-y: 0.5rem;
--button-padding-x: 1rem;
--button-border-radius: 4px;
--button-transition: all 0.3s ease;

/* Color variations */
--button-primary-bg: #3498db;
--button-success-bg: #2ecc71;
--button-danger-bg: #e74c3c;
}

.button {
padding: var(--button-padding-y) var(--button-padding-x);
border-radius: var(--button-border-radius);
transition: var(--button-transition);
border: none;
color: white;
}

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

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

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

/* Hover states */
.button:hover {
filter: brightness(1.1);
transform: translateY(-1px);
}

What’s Next?

Now that you’ve mastered CSS Custom Properties, you can explore:

  • CSS Modules and CSS-in-JS
  • Advanced Theming Systems
  • Dynamic Color Schemes
  • Component Libraries

Remember, CSS Custom Properties are incredibly powerful, but with great power comes great responsibility! Keep your naming consistent, document your variables, and think about scoping. Your future self (and your team) will thank you!

Got questions about CSS Custom Properties? Drop them in the comments below! Happy coding!