What Are CSS Custom Properties
CSS custom properties, commonly known as CSS variables, are native CSS features that enable developers to create dynamic, maintainable, and themable component systems. Unlike preprocessor variables that are static and replaced at compile time, CSS custom properties live in the browser and can be changed dynamically based on user interaction, device preferences, or application state.
Key characteristics of CSS custom properties:
- Defined using two dashes as a prefix:
--property-name - Accessed using the var() function:
color: var(--property-name) - Live in the browser's CSSOM and can be modified at runtime
- Follow CSS cascade and inheritance rules
- Can be manipulated through JavaScript
These capabilities make custom properties essential for modern web development, enabling component architectures that adapt to different contexts without requiring separate stylesheets or framework-specific solutions. For related techniques, explore our guide on the power of CSS :has() selector for advanced component targeting.
1:root {2 --primary-color: #3498db;3 --spacing-unit: 1rem;4 --font-size-base: 1rem;5}6 7.button {8 background-color: var(--primary-color);9 padding: var(--spacing-unit) calc(var(--spacing-unit) * 2);10 font-size: var(--font-size-base);11}Key benefits for modern component development
Runtime Flexibility
Modify component appearance dynamically based on user interaction, device preferences, or application state without page reloads.
Theming Support
Implement dark mode, high contrast, or brand themes by redefining variable values in scoped selectors.
Maintainable Architecture
Centralize design decisions in tokens, enabling consistent updates across entire component libraries.
JavaScript Integration
Read and write custom property values from JavaScript for interactive customization and dynamic effects.
1.button {2 /* Base customizable properties */3 --button-background: var(--color-primary);4 --button-text: #ffffff;5 --button-border: none;6 --button-border-radius: 0.5rem;7 --button-padding: 0.75rem 1.5rem;8 --button-font-size: 1rem;9 --button-transition: all 0.2s ease;10 11 background: var(--button-background);12 color: var(--button-text);13 border: var(--button-border);14 border-radius: var(--button-border-radius);15 padding: var(--button-padding);16 font-size: var(--button-font-size);17 transition: var(--button-transition);18}19 20/* Variant overrides */21.button--outline {22 --button-background: transparent;23 --button-border: 2px solid var(--color-primary);24 --button-text: var(--color-primary);25}1:root {2 /* Primitive tokens - raw design values */3 --color-blue-500: #3498db;4 --color-blue-600: #2980b9;5 --color-gray-100: #f5f5f5;6 --color-gray-900: #1a1a1a;7 --spacing-1: 0.25rem;8 --spacing-2: 0.5rem;9 --spacing-4: 1rem;10 11 /* Semantic tokens - contextual usage */12 --color-primary: var(--color-blue-500);13 --color-primary-hover: var(--color-blue-600);14 --color-surface: var(--color-gray-100);15 --color-text: var(--color-gray-900);16 --spacing-section: var(--spacing-4);17}18 19/* Theme overrides */20[data-theme="dark"] {21 --color-surface: var(--color-gray-900);22 --color-text: var(--color-gray-100);23}1// Reading a custom property value2const element = document.querySelector('.my-component');3const currentColor = getComputedStyle(element)4 .getPropertyValue('--component-color');5 6// Setting a custom property value7element.style.setProperty('--component-color', '#ff6b6b');8 9// Setting with CSS custom property reference10element.style.setProperty(11 '--component-background',12 'var(--theme-accent)'13);14 15// Theme switching example16function setTheme(themeName) {17 document.documentElement.setAttribute('data-theme', themeName);18}1.card {2 --card-elevation: 0;3 --card-scale: 1;4 5 transform: scale(var(--card-scale));6 box-shadow: 0 calc(var(--card-elevation) * 4px) 7 calc(var(--card-elevation) * 12px) rgba(0, 0, 0, 0.15);8 transition: all 0.3s ease;9}10 11.card:hover {12 --card-elevation: 2;13 --card-scale: 1.02;14}15 16/* JavaScript can also update these values */17/* document.querySelector('.card').style.setProperty('--card-elevation', '3'); */Frequently Asked Questions
How are CSS custom properties different from Sass variables?
Sass variables are compile-time only and don't exist in the final CSS, while CSS custom properties live in the browser and can be modified at runtime, enabling dynamic theming and JavaScript manipulation.
Can custom properties improve performance?
Yes, when used appropriately. Custom properties can reduce repeated values, enable efficient theme switching without repaints, and work with browser optimization for transform and opacity animations.
How do I implement dark mode with custom properties?
Define theme-specific values within scoped selectors (like [data-theme="dark"]). Adding the attribute to the document element causes all components using those variables to automatically update.
Should I use design tokens or raw values for custom properties?
Use design tokens as the foundation. Raw values should be tokenized for consistency, with semantic tokens referencing primitives to enable flexible theming and easy updates.