Master CSS custom properties for dynamic, maintainable, and themeable stylesheets. Learn advanced variable techniques, dynamic updates, and real-world applications.
CSS custom properties (CSS variables) revolutionize how we write and maintain stylesheets. Unlike preprocessor variables, CSS custom properties are live values that can be changed at runtime, creating dynamic, interactive, and highly maintainable styling systems.
Modern web applications demand flexible theming, responsive design patterns, and component-based architectures. CSS custom properties provide the foundation for all of these advanced techniques, enabling you to create sophisticated design systems that adapt to user preferences, screen sizes, and interaction states.
In this comprehensive lesson, you'll master every aspect of CSS custom properties - from basic syntax to advanced inheritance patterns, dynamic theming systems, and performance optimization techniques. You'll build real-world examples that demonstrate how CSS variables transform static stylesheets into dynamic, intelligent design systems.
CSS custom properties are native CSS variables that cascade and inherit, providing dynamic styling capabilities that preprocessors cannot match. Understanding their syntax, scope, and inheritance patterns is crucial for building advanced styling systems.
Basic Syntax and Declaration:
1/* Global custom properties on :root */
2:root {
3 /* Color system */
4 --primary-hue: 240;
5 --primary-saturation: 100%;
6 --primary-lightness: 50%;
7 --primary-color: hsl(var(--primary-hue), var(--primary-saturation), var(--primary-lightness));
8
9 /* Typography scale */
10 --font-size-base: 16px;
11 --font-size-scale: 1.25;
12 --font-size-small: calc(var(--font-size-base) / var(--font-size-scale));
13 --font-size-large: calc(var(--font-size-base) * var(--font-size-scale));
14 --font-size-xl: calc(var(--font-size-large) * var(--font-size-scale));
15
16 /* Spacing system */
17 --space-unit: 0.5rem;
18 --space-xs: var(--space-unit);
19 --space-sm: calc(var(--space-unit) * 2);
20 --space-md: calc(var(--space-unit) * 4);
21 --space-lg: calc(var(--space-unit) * 8);
22 --space-xl: calc(var(--space-unit) * 16);
23}
24
25/* Component-specific properties */
26.card {
27 --card-padding: var(--space-md);
28 --card-border-radius: 8px;
29 --card-shadow-color: rgba(0, 0, 0, 0.1);
30 --card-background: white;
31
32 padding: var(--card-padding);
33 border-radius: var(--card-border-radius);
34 background: var(--card-background);
35 box-shadow: 0 4px 15px var(--card-shadow-color);
36}Using Custom Properties with var() Function:
1/* Basic usage with fallbacks */
2.element {
3 /* Single fallback */
4 color: var(--primary-color, #3b82f6);
5
6 /* Multiple fallback chain */
7 background: var(--theme-background, var(--fallback-background, white));
8
9 /* Fallback with custom property */
10 margin: var(--component-margin, var(--default-margin, 1rem));
11
12 /* Complex fallback with calculations */
13 padding: var(--custom-padding, calc(var(--space-unit, 0.5rem) * 2));
14}Scope and Inheritance Patterns:
1/* Global scope (inherited by all elements) */
2:root {
3 --global-color: #333;
4 --global-font: 'Inter', sans-serif;
5}
6
7/* Element scope (inherited by descendants) */
8.theme-container {
9 --theme-primary: #e11d48;
10 --theme-secondary: #0ea5e9;
11 --theme-background: #f8fafc;
12}
13
14/* Component scope (local to component) */
15.button {
16 --button-color: var(--theme-primary, #3b82f6);
17 --button-hover-color: var(--theme-secondary, #2563eb);
18
19 background: var(--button-color);
20}
21
22.button:hover {
23 background: var(--button-hover-color);
24}
25
26/* State-based scope */
27.button:disabled {
28 --button-color: #9ca3af;
29 --button-hover-color: #9ca3af;
30}Advanced Inheritance Control:
1/* Explicit inheritance control */
2.child-component {
3 /* Force inheritance even if parent doesn't define it */
4 --inherited-property: inherit;
5
6 /* Reset to initial value */
7 --reset-property: initial;
8
9 /* Remove custom property (use fallback) */
10 --removed-property: ;
11}
12
13/* Conditional inheritance */
14.conditional-theme {
15 /* Only inherit if parent has defined it */
16 --conditional-color: var(--parent-theme-color);
17}
18
19.conditional-theme:not(.has-parent-theme) {
20 /* Provide own default when parent doesn't have theme */
21 --conditional-color: #64748b;
22}Performance Considerations:
1/* Efficient custom property patterns */
2:root {
3 /* Group related properties */
4 --color-primary-h: 240;
5 --color-primary-s: 100%;
6 --color-primary-l: 50%;
7
8 /* Pre-calculate common values */
9 --color-primary-rgb: 59, 130, 246;
10 --color-primary-hsl: var(--color-primary-h), var(--color-primary-s), var(--color-primary-l);
11}
12
13/* Avoid excessive calculations in frequently used properties */
14.optimized-element {
15 /* Good: pre-calculated value */
16 background: hsl(var(--color-primary-hsl));
17
18 /* Better: direct color value for frequently used properties */
19 color: var(--color-primary, #3b82f6);
20
21 /* Avoid: complex calculations on every paint */
22 /* border-color: hsl(calc(var(--color-primary-h) + 30), var(--color-primary-s), calc(var(--color-primary-l) - 10%)); */
23}Best Practices:
--color-primary vs --blue)CSS custom properties enable powerful theming systems that can be changed at runtime, support user preferences, and adapt to different contexts. Building robust theming requires systematic architecture and smart inheritance patterns.
Comprehensive Theme Architecture:
1/* Base theme system with semantic tokens */
2:root {
3 /* Design tokens - the source of truth */
4 --color-gray-50: #f9fafb;
5 --color-gray-100: #f3f4f6;
6 --color-gray-500: #6b7280;
7 --color-gray-900: #111827;
8
9 --color-blue-400: #60a5fa;
10 --color-blue-500: #3b82f6;
11 --color-blue-600: #2563eb;
12
13 --color-red-400: #f87171;
14 --color-red-500: #ef4444;
15 --color-red-600: #dc2626;
16
17 /* Semantic color system */
18 --color-background: var(--color-gray-50);
19 --color-surface: white;
20 --color-primary: var(--color-blue-500);
21 --color-primary-hover: var(--color-blue-600);
22 --color-danger: var(--color-red-500);
23 --color-text: var(--color-gray-900);
24 --color-text-muted: var(--color-gray-500);
25
26 /* Interactive state colors */
27 --color-focus-ring: var(--color-blue-400);
28 --color-border: var(--color-gray-200);
29 --color-border-hover: var(--color-gray-300);
30
31 /* Shadow system */
32 --shadow-color: 0, 0, 0;
33 --shadow-opacity: 0.1;
34 --shadow-sm: 0 1px 2px rgba(var(--shadow-color), var(--shadow-opacity));
35 --shadow-md: 0 4px 6px rgba(var(--shadow-color), var(--shadow-opacity));
36 --shadow-lg: 0 10px 15px rgba(var(--shadow-color), var(--shadow-opacity));
37}
38
39/* Dark theme override */
40[data-theme="dark"] {
41 --color-background: var(--color-gray-900);
42 --color-surface: #1f2937;
43 --color-text: var(--color-gray-50);
44 --color-text-muted: var(--color-gray-400);
45 --color-border: #374151;
46 --color-border-hover: #4b5563;
47
48 --shadow-opacity: 0.3;
49}
50
51/* High contrast theme */
52[data-theme="high-contrast"] {
53 --color-background: black;
54 --color-surface: black;
55 --color-primary: #00ff00;
56 --color-text: white;
57 --color-border: white;
58 --shadow-opacity: 0;
59}Component Theme Integration:
1/* Button component with theme awareness */
2.btn {
3 --btn-background: var(--color-primary);
4 --btn-color: white;
5 --btn-border: var(--color-primary);
6 --btn-shadow: var(--shadow-sm);
7
8 /* Hover state inherits theme */
9 --btn-hover-background: var(--color-primary-hover);
10 --btn-hover-transform: translateY(-1px);
11 --btn-hover-shadow: var(--shadow-md);
12
13 background: var(--btn-background);
14 color: var(--btn-color);
15 border: 1px solid var(--btn-border);
16 box-shadow: var(--btn-shadow);
17
18 transition: all 0.2s ease-out;
19}
20
21.btn:hover {
22 background: var(--btn-hover-background);
23 transform: var(--btn-hover-transform);
24 box-shadow: var(--btn-hover-shadow);
25}
26
27/* Variant overrides */
28.btn--secondary {
29 --btn-background: transparent;
30 --btn-color: var(--color-primary);
31 --btn-border: var(--color-primary);
32 --btn-hover-background: var(--color-primary);
33 --btn-hover-color: white;
34}
35
36.btn--danger {
37 --btn-background: var(--color-danger);
38 --btn-border: var(--color-danger);
39 --btn-hover-background: var(--color-red-600);
40}Runtime Theme Switching:
1/* Smooth theme transitions */
2* {
3 transition:
4 background-color 0.3s ease-out,
5 color 0.3s ease-out,
6 border-color 0.3s ease-out,
7 box-shadow 0.3s ease-out;
8}
9
10/* Disable transitions during theme change to avoid flash */
11.theme-transitioning * {
12 transition: none !important;
13}JavaScript Theme Management:
1// Theme management system
2class ThemeManager {
3 constructor() {
4 this.currentTheme = localStorage.getItem('theme') || 'light';
5 this.applyTheme(this.currentTheme);
6 this.watchSystemTheme();
7 }
8
9 applyTheme(theme) {
10 document.documentElement.dataset.theme = theme;
11 localStorage.setItem('theme', theme);
12 this.currentTheme = theme;
13 }
14
15 toggleTheme() {
16 const newTheme = this.currentTheme === 'light' ? 'dark' : 'light';
17 this.applyTheme(newTheme);
18 }
19
20 watchSystemTheme() {
21 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
22 mediaQuery.addListener((e) => {
23 if (!localStorage.getItem('theme')) {
24 this.applyTheme(e.matches ? 'dark' : 'light');
25 }
26 });
27 }
28
29 // Update CSS custom properties at runtime
30 updateThemeProperty(property, value) {
31 document.documentElement.style.setProperty(`--\${property}`, value);
32 }
33
34 // Get current theme property value
35 getThemeProperty(property) {
36 return getComputedStyle(document.documentElement)
37 .getPropertyValue(`--\${property}`);
38 }
39}Advanced Theme Patterns:
1/* Context-aware theming */
2.theme-context {
3 /* Brand theme context */
4 --theme-brand-primary: var(--color-blue-500);
5 --theme-brand-secondary: var(--color-blue-100);
6}
7
8.theme-context.brand-marketing {
9 --theme-brand-primary: var(--color-purple-500);
10 --theme-brand-secondary: var(--color-purple-100);
11}
12
13.theme-context.brand-enterprise {
14 --theme-brand-primary: var(--color-gray-900);
15 --theme-brand-secondary: var(--color-gray-100);
16}
17
18/* Responsive theme properties */
19@media (max-width: 768px) {
20 :root {
21 --space-unit: 0.375rem; /* Smaller spacing on mobile */
22 --font-size-base: 14px; /* Smaller base font size */
23 }
24}
25
26/* User preference integration */
27@media (prefers-reduced-motion: reduce) {
28 :root {
29 --animation-duration: 0.001s;
30 --transition-timing: linear;
31 }
32}
33
34@media (prefers-contrast: high) {
35 :root {
36 --color-border-width: 2px;
37 --shadow-opacity: 0; /* Remove shadows for high contrast */
38 }
39}Theme Testing and Debugging:
1/* Development theme debugging */
2.debug-theme {
3 /* Visual indicator of current theme */
4 --debug-indicator: '';
5}
6
7[data-theme="light"] .debug-theme {
8 --debug-indicator: '☀️ Light';
9}
10
11[data-theme="dark"] .debug-theme {
12 --debug-indicator: '🌙 Dark';
13}
14
15.debug-theme::before {
16 content: var(--debug-indicator);
17 position: fixed;
18 top: 10px;
19 right: 10px;
20 background: var(--color-primary);
21 color: white;
22 padding: 0.5rem;
23 border-radius: 4px;
24 font-size: 12px;
25 z-index: 9999;
26}This systematic approach to theming creates maintainable, scalable, and user-friendly interfaces that adapt to preferences and contexts while maintaining consistent design standards.
Design tokens are the building blocks of consistent design systems. CSS custom properties provide the perfect implementation mechanism for tokens that need to be shared across platforms, updated dynamically, and maintained centrally.
Systematic Token Architecture:
1/* Foundation tokens - the atomic values */
2:root {
3 /* Color palette - HSL for better manipulation */
4 --token-color-gray-h: 220;
5 --token-color-gray-s: 14%;
6 --token-color-gray-050-l: 98%;
7 --token-color-gray-100-l: 96%;
8 --token-color-gray-200-l: 93%;
9 --token-color-gray-300-l: 86%;
10 --token-color-gray-400-l: 70%;
11 --token-color-gray-500-l: 51%;
12 --token-color-gray-600-l: 39%;
13 --token-color-gray-700-l: 28%;
14 --token-color-gray-800-l: 18%;
15 --token-color-gray-900-l: 9%;
16
17 /* Generated color values */
18 --token-color-gray-050: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-050-l));
19 --token-color-gray-100: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-100-l));
20 --token-color-gray-200: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-200-l));
21 --token-color-gray-300: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-300-l));
22 --token-color-gray-400: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-400-l));
23 --token-color-gray-500: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-500-l));
24 --token-color-gray-600: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-600-l));
25 --token-color-gray-700: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-700-l));
26 --token-color-gray-800: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-800-l));
27 --token-color-gray-900: hsl(var(--token-color-gray-h), var(--token-color-gray-s), var(--token-color-gray-900-l));
28
29 /* Typography scale using perfect fourth (1.333) */
30 --token-font-size-root: 16px;
31 --token-font-size-ratio: 1.333;
32 --token-font-size-xs: calc(var(--token-font-size-root) / var(--token-font-size-ratio) / var(--token-font-size-ratio));
33 --token-font-size-sm: calc(var(--token-font-size-root) / var(--token-font-size-ratio));
34 --token-font-size-base: var(--token-font-size-root);
35 --token-font-size-lg: calc(var(--token-font-size-root) * var(--token-font-size-ratio));
36 --token-font-size-xl: calc(var(--token-font-size-lg) * var(--token-font-size-ratio));
37 --token-font-size-2xl: calc(var(--token-font-size-xl) * var(--token-font-size-ratio));
38 --token-font-size-3xl: calc(var(--token-font-size-2xl) * var(--token-font-size-ratio));
39
40 /* Spacing scale using golden ratio (1.618) */
41 --token-space-unit: 0.5rem;
42 --token-space-ratio: 1.618;
43 --token-space-2xs: var(--token-space-unit);
44 --token-space-xs: calc(var(--token-space-unit) * var(--token-space-ratio));
45 --token-space-sm: calc(var(--token-space-xs) * var(--token-space-ratio));
46 --token-space-md: calc(var(--token-space-sm) * var(--token-space-ratio));
47 --token-space-lg: calc(var(--token-space-md) * var(--token-space-ratio));
48 --token-space-xl: calc(var(--token-space-lg) * var(--token-space-ratio));
49 --token-space-2xl: calc(var(--token-space-xl) * var(--token-space-ratio));
50
51 /* Timing scale for consistent animations */
52 --token-duration-instant: 0ms;
53 --token-duration-immediate: 100ms;
54 --token-duration-quick: 200ms;
55 --token-duration-moderate: 300ms;
56 --token-duration-deliberate: 500ms;
57 --token-duration-slow: 800ms;
58
59 /* Easing functions for different interaction types */
60 --token-easing-linear: linear;
61 --token-easing-ease-out: cubic-bezier(0, 0, 0.2, 1);
62 --token-easing-ease-in: cubic-bezier(0.4, 0, 1, 1);
63 --token-easing-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
64 --token-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
65}Semantic Token Layer:
1/* Semantic tokens - give meaning to foundation tokens */
2:root {
3 /* Surface colors */
4 --token-surface-background: var(--token-color-gray-050);
5 --token-surface-primary: white;
6 --token-surface-secondary: var(--token-color-gray-100);
7 --token-surface-tertiary: var(--token-color-gray-200);
8
9 /* Text colors */
10 --token-text-primary: var(--token-color-gray-900);
11 --token-text-secondary: var(--token-color-gray-700);
12 --token-text-tertiary: var(--token-color-gray-500);
13 --token-text-placeholder: var(--token-color-gray-400);
14
15 /* Interactive colors */
16 --token-interactive-primary: #3b82f6;
17 --token-interactive-primary-hover: #2563eb;
18 --token-interactive-secondary: var(--token-color-gray-600);
19 --token-interactive-danger: #ef4444;
20 --token-interactive-success: #10b981;
21
22 /* Border colors */
23 --token-border-primary: var(--token-color-gray-300);
24 --token-border-secondary: var(--token-color-gray-200);
25 --token-border-focus: var(--token-interactive-primary);
26
27 /* Shadow tokens */
28 --token-shadow-color: var(--token-color-gray-900);
29 --token-shadow-opacity-subtle: 0.05;
30 --token-shadow-opacity-moderate: 0.1;
31 --token-shadow-opacity-strong: 0.15;
32
33 --token-shadow-sm: 0 1px 2px rgba(from var(--token-shadow-color) r g b / var(--token-shadow-opacity-subtle));
34 --token-shadow-md: 0 4px 6px rgba(from var(--token-shadow-color) r g b / var(--token-shadow-opacity-moderate));
35 --token-shadow-lg: 0 10px 15px rgba(from var(--token-shadow-color) r g b / var(--token-shadow-opacity-strong));
36}Component Token Layer:
1/* Component-specific tokens */
2:root {
3 /* Button tokens */
4 --token-button-height-sm: 2rem;
5 --token-button-height-md: 2.5rem;
6 --token-button-height-lg: 3rem;
7 --token-button-padding-x: var(--token-space-md);
8 --token-button-border-radius: 0.5rem;
9 --token-button-font-weight: 600;
10 --token-button-transition: all var(--token-duration-quick) var(--token-easing-ease-out);
11
12 /* Card tokens */
13 --token-card-padding: var(--token-space-lg);
14 --token-card-border-radius: 1rem;
15 --token-card-background: var(--token-surface-primary);
16 --token-card-border: 1px solid var(--token-border-secondary);
17 --token-card-shadow: var(--token-shadow-md);
18 --token-card-shadow-hover: var(--token-shadow-lg);
19
20 /* Input tokens */
21 --token-input-height: var(--token-button-height-md);
22 --token-input-padding: var(--token-space-sm) var(--token-space-md);
23 --token-input-border: 1px solid var(--token-border-primary);
24 --token-input-border-radius: 0.5rem;
25 --token-input-background: var(--token-surface-primary);
26 --token-input-focus-ring: 0 0 0 3px rgba(from var(--token-interactive-primary) r g b / 0.1);
27}Responsive Token System:
1/* Mobile-first responsive tokens */
2:root {
3 /* Base mobile tokens */
4 --token-container-padding: var(--token-space-md);
5 --token-section-spacing: var(--token-space-xl);
6 --token-heading-size-ratio: 1.2;
7}
8
9/* Tablet tokens */
10@media (min-width: 640px) {
11 :root {
12 --token-container-padding: var(--token-space-lg);
13 --token-section-spacing: var(--token-space-2xl);
14 --token-heading-size-ratio: 1.3;
15 }
16}
17
18/* Desktop tokens */
19@media (min-width: 1024px) {
20 :root {
21 --token-container-padding: var(--token-space-xl);
22 --token-heading-size-ratio: 1.333;
23 }
24}
25
26/* Large screen optimizations */
27@media (min-width: 1280px) {
28 :root {
29 --token-font-size-root: 18px; /* Larger base font for readability */
30 }
31}Token Usage in Components:
1/* Button component using design tokens */
2.btn {
3 /* Use semantic and component tokens */
4 height: var(--token-button-height-md);
5 padding: 0 var(--token-button-padding-x);
6 border-radius: var(--token-button-border-radius);
7 font-weight: var(--token-button-font-weight);
8 font-size: var(--token-font-size-base);
9
10 background: var(--token-interactive-primary);
11 color: white;
12 border: none;
13
14 transition: var(--token-button-transition);
15 cursor: pointer;
16}
17
18.btn:hover {
19 background: var(--token-interactive-primary-hover);
20 transform: translateY(-1px);
21}
22
23/* Variants override specific tokens */
24.btn--secondary {
25 background: transparent;
26 color: var(--token-interactive-primary);
27 border: 1px solid var(--token-border-primary);
28}
29
30.btn--small {
31 height: var(--token-button-height-sm);
32 font-size: var(--token-font-size-sm);
33}
34
35.btn--large {
36 height: var(--token-button-height-lg);
37 font-size: var(--token-font-size-lg);
38}Token Documentation System:
1/* Self-documenting token system */
2:root {
3 /* Color tokens with usage comments */
4 --token-interactive-primary: #3b82f6; /* Primary actions, links, focus states */
5 --token-interactive-secondary: #6b7280; /* Secondary actions, less prominent interactions */
6 --token-interactive-danger: #ef4444; /* Destructive actions, error states */
7 --token-interactive-success: #10b981; /* Success states, positive feedback */
8
9 /* Typography tokens with scale information */
10 --token-font-size-xs: 0.75rem; /* 12px - Fine print, captions */
11 --token-font-size-sm: 0.875rem; /* 14px - Small text, labels */
12 --token-font-size-base: 1rem; /* 16px - Body text, default */
13 --token-font-size-lg: 1.125rem; /* 18px - Emphasized text */
14 --token-font-size-xl: 1.25rem; /* 20px - Small headings */
15 --token-font-size-2xl: 1.5rem; /* 24px - Medium headings */
16 --token-font-size-3xl: 1.875rem; /* 30px - Large headings */
17}Token Generation and Tooling:
1// JavaScript token generation utility
2class TokenGenerator {
3 static generateColorScale(hue, saturation, steps = 10) {
4 const tokens = {};
5 for (let i = 0; i < steps; i++) {
6 const lightness = 95 - (i * 10); // From 95% to 5%
7 const value = Math.max(5, Math.min(95, lightness));
8 tokens[`--token-color-\${hue}-\${i * 100 + 50}`] =
9 `hsl(\${hue}, \${saturation}%, \${value}%)`;
10 }
11 return tokens;
12 }
13
14 static generateSpacingScale(baseUnit = 0.5, ratio = 1.618, steps = 8) {
15 const tokens = {};
16 const sizes = ['2xs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'];
17
18 for (let i = 0; i < steps; i++) {
19 const value = baseUnit * Math.pow(ratio, i);
20 tokens[`--token-space-\${sizes[i]}`] = `\${value}rem`;
21 }
22 return tokens;
23 }
24}This systematic approach to design tokens creates a maintainable, scalable foundation for complex design systems while leveraging CSS custom properties for maximum flexibility and performance.
Advanced CSS variable techniques enable sophisticated styling patterns, runtime calculations, and performance optimizations that transform how we architect stylesheets. Understanding these techniques is essential for building scalable, maintainable systems.
Dynamic Calculations and Computed Values:
1/* Mathematical relationships using CSS variables */
2:root {
3 /* Base values for calculations */
4 --layout-max-width: 1200px;
5 --layout-gutter: 2rem;
6 --layout-columns: 12;
7
8 /* Dynamic grid system */
9 --layout-content-width: calc(var(--layout-max-width) - (var(--layout-gutter) * 2));
10 --layout-column-width: calc(var(--layout-content-width) / var(--layout-columns));
11 --layout-column-gap: calc(var(--layout-gutter) / 2);
12
13 /* Fluid typography using viewport units */
14 --fluid-min-size: 16px;
15 --fluid-max-size: 24px;
16 --fluid-min-viewport: 320px;
17 --fluid-max-viewport: 1200px;
18 --fluid-size: calc(
19 var(--fluid-min-size) +
20 (var(--fluid-max-size) - var(--fluid-min-size)) *
21 ((100vw - var(--fluid-min-viewport)) / (var(--fluid-max-viewport) - var(--fluid-min-viewport)))
22 );
23
24 /* Aspect ratio calculations */
25 --aspect-ratio-width: 16;
26 --aspect-ratio-height: 9;
27 --aspect-ratio-percent: calc((var(--aspect-ratio-height) / var(--aspect-ratio-width)) * 100%);
28}
29
30/* Grid system using calculated columns */
31.grid-container {
32 max-width: var(--layout-max-width);
33 margin: 0 auto;
34 padding: 0 var(--layout-gutter);
35}
36
37.grid-row {
38 display: flex;
39 margin: 0 calc(var(--layout-column-gap) * -1);
40}
41
42.grid-col {
43 padding: 0 var(--layout-column-gap);
44}
45
46/* Dynamic column widths */
47.grid-col-1 { flex: 0 0 calc((var(--layout-column-width) * 1) + (var(--layout-column-gap) * 2)); }
48.grid-col-2 { flex: 0 0 calc((var(--layout-column-width) * 2) + (var(--layout-column-gap) * 2)); }
49.grid-col-3 { flex: 0 0 calc((var(--layout-column-width) * 3) + (var(--layout-column-gap) * 2)); }
50/* ... and so on */
51
52/* Fluid typography implementation */
53.fluid-text {
54 font-size: clamp(var(--fluid-min-size), var(--fluid-size), var(--fluid-max-size));
55}
56
57/* Aspect ratio container */
58.aspect-ratio-container {
59 position: relative;
60 width: 100%;
61 padding-bottom: var(--aspect-ratio-percent);
62}
63
64.aspect-ratio-content {
65 position: absolute;
66 top: 0;
67 left: 0;
68 width: 100%;
69 height: 100%;
70}State Management with CSS Variables:
1/* Complex state management using CSS variables */
2.interactive-component {
3 /* State variables */
4 --is-loading: 0;
5 --is-disabled: 0;
6 --is-error: 0;
7 --is-success: 0;
8
9 /* Computed styles based on state */
10 --opacity: calc(1 - (var(--is-loading) * 0.5) - (var(--is-disabled) * 0.3));
11 --cursor: var(--is-disabled) == 1 ? 'not-allowed' : 'pointer';
12 --background-color: hsl(
13 calc(220 + (var(--is-error) * 140) - (var(--is-success) * 100)),
14 calc(100% * (1 - var(--is-disabled) * 0.8)),
15 calc(50% + (var(--is-disabled) * 20%))
16 );
17
18 opacity: var(--opacity);
19 cursor: var(--cursor);
20 background: var(--background-color);
21 transition: all 0.2s ease-out;
22}
23
24/* State modifiers */
25.interactive-component[data-loading="true"] { --is-loading: 1; }
26.interactive-component[data-disabled="true"] { --is-disabled: 1; }
27.interactive-component[data-error="true"] { --is-error: 1; }
28.interactive-component[data-success="true"] { --is-success: 1; }
29
30/* Animation states using variables */
31.animated-element {
32 --animation-play-state: paused;
33 --animation-direction: normal;
34 --animation-speed: 1;
35
36 animation:
37 slideIn calc(0.5s / var(--animation-speed)) ease-out
38 var(--animation-direction)
39 var(--animation-play-state);
40}
41
42.animated-element[data-animate="true"] { --animation-play-state: running; }
43.animated-element[data-reverse="true"] { --animation-direction: reverse; }
44.animated-element[data-fast="true"] { --animation-speed: 2; }Performance Optimization Techniques:
1/* Efficient variable architecture for performance */
2:root {
3 /* Pre-calculate expensive values */
4 --color-primary-rgb: 59, 130, 246;
5 --color-primary-alpha-10: rgba(var(--color-primary-rgb), 0.1);
6 --color-primary-alpha-20: rgba(var(--color-primary-rgb), 0.2);
7 --color-primary-alpha-50: rgba(var(--color-primary-rgb), 0.5);
8
9 /* Avoid recalculation in frequently used properties */
10 --shadow-base: 0 1px 3px rgba(0, 0, 0, 0.1);
11 --shadow-elevated: 0 4px 6px rgba(0, 0, 0, 0.1);
12 --shadow-overlay: 0 20px 25px rgba(0, 0, 0, 0.1);
13
14 /* Group related properties for cache efficiency */
15 --spacing-xs: 0.25rem;
16 --spacing-sm: 0.5rem;
17 --spacing-md: 1rem;
18 --spacing-lg: 1.5rem;
19 --spacing-xl: 2rem;
20}
21
22/* Efficient component patterns */
23.optimized-button {
24 /* Use pre-calculated values */
25 background: rgb(var(--color-primary-rgb));
26 box-shadow: var(--shadow-base);
27
28 /* Minimize calculations */
29 padding: var(--spacing-sm) var(--spacing-md);
30
31 /* Avoid complex calc() in frequently triggered properties */
32 transition: transform 0.2s ease-out;
33}
34
35.optimized-button:hover {
36 /* Simple transform for hardware acceleration */
37 transform: translateY(-1px);
38 box-shadow: var(--shadow-elevated);
39}CSS Variable Inheritance Control:
1/* Advanced inheritance patterns */
2.theme-boundary {
3 /* Create isolation boundary */
4 --theme-context: 'isolated';
5
6 /* Reset inherited variables */
7 --inherited-color: initial;
8 --inherited-font: initial;
9
10 /* Establish new context */
11 --local-primary: #e11d48;
12 --local-secondary: #0ea5e9;
13}
14
15/* Conditional inheritance */
16.conditional-theme {
17 /* Use parent theme if available, otherwise use local default */
18 --resolved-color: var(--parent-theme-color, var(--local-default-color, #64748b));
19}
20
21/* Scope-aware property resolution */
22.scoped-component {
23 /* Try component-specific, then theme, then global, then fallback */
24 --resolved-spacing: var(
25 --component-spacing,
26 var(--theme-spacing,
27 var(--global-spacing, 1rem)
28 )
29 );
30}Runtime Variable Management:
1// Advanced CSS variable manipulation
2class CSSVariableManager {
3 constructor(scope = document.documentElement) {
4 this.scope = scope;
5 this.observers = new Map();
6 }
7
8 // Set variable with type checking and validation
9 setVariable(name, value, validate = true) {
10 const propertyName = name.startsWith('--') ? name : `--\${name}`;
11
12 if (validate) {
13 this.validateVariable(propertyName, value);
14 }
15
16 this.scope.style.setProperty(propertyName, value);
17 this.notifyObservers(propertyName, value);
18 }
19
20 // Get computed variable value
21 getVariable(name) {
22 const propertyName = name.startsWith('--') ? name : `--\${name}`;
23 return getComputedStyle(this.scope).getPropertyValue(propertyName).trim();
24 }
25
26 // Batch update for performance
27 updateVariables(variables) {
28 // Use DocumentFragment to minimize repaints
29 Object.entries(variables).forEach(([name, value]) => {
30 const propertyName = name.startsWith('--') ? name : `--\${name}`;
31 this.scope.style.setProperty(propertyName, value);
32 });
33
34 // Single repaint trigger
35 this.scope.offsetHeight;
36 }
37
38 // Watch for variable changes
39 observeVariable(name, callback) {
40 const propertyName = name.startsWith('--') ? name : `--\${name}`;
41 if (!this.observers.has(propertyName)) {
42 this.observers.set(propertyName, new Set());
43 }
44 this.observers.get(propertyName).add(callback);
45 }
46
47 // Remove variable observer
48 unobserveVariable(name, callback) {
49 const propertyName = name.startsWith('--') ? name : `--\${name}`;
50 if (this.observers.has(propertyName)) {
51 this.observers.get(propertyName).delete(callback);
52 }
53 }
54
55 // Notify observers of changes
56 notifyObservers(propertyName, value) {
57 if (this.observers.has(propertyName)) {
58 this.observers.get(propertyName).forEach(callback => {
59 callback(value, propertyName);
60 });
61 }
62 }
63
64 // Validate variable values
65 validateVariable(name, value) {
66 // Type validation based on property name conventions
67 if (name.includes('color') && !this.isValidColor(value)) {
68 throw new Error(`Invalid color value for \${name}: \${value}`);
69 }
70
71 if (name.includes('size') && !this.isValidSize(value)) {
72 throw new Error(`Invalid size value for \${name}: \${value}`);
73 }
74 }
75
76 isValidColor(value) {
77 // Basic color validation
78 const tempElement = document.createElement('div');
79 tempElement.style.color = value;
80 return tempElement.style.color !== '';
81 }
82
83 isValidSize(value) {
84 // Basic size validation
85 return /^\d+(\.\d+)?(px|rem|em|%|vh|vw)$/.test(value);
86 }
87}
88
89// Usage example
90const varManager = new CSSVariableManager();
91
92// Set theme colors with validation
93varManager.setVariable('theme-primary', '#3b82f6');
94varManager.setVariable('theme-spacing', '1rem');
95
96// Watch for changes
97varManager.observeVariable('theme-primary', (newColor) => {
98 console.log(`Theme primary color changed to: \${newColor}`);
99});
100
101// Batch update for performance
102varManager.updateVariables({
103 'theme-primary': '#e11d48',
104 'theme-secondary': '#0ea5e9',
105 'theme-background': '#f8fafc'
106});Browser Support and Fallback Strategies:
1/* Progressive enhancement with CSS variables */
2.enhanced-component {
3 /* Fallback for older browsers */
4 background: #3b82f6;
5 color: white;
6 padding: 1rem;
7
8 /* Enhanced with CSS variables */
9 background: var(--theme-primary, #3b82f6);
10 color: var(--theme-text, white);
11 padding: var(--component-padding, 1rem);
12}
13
14/* Feature detection using @supports */
15@supports (--custom-property: value) {
16 .variable-enhanced {
17 /* Use advanced variable features only when supported */
18 --dynamic-size: calc(var(--base-size, 1rem) * var(--scale-factor, 1));
19 font-size: var(--dynamic-size);
20 }
21}
22
23@supports not (--custom-property: value) {
24 .variable-enhanced {
25 /* Fallback implementation */
26 font-size: 1rem;
27 }
28}These advanced techniques unlock the full potential of CSS custom properties, enabling sophisticated styling architectures that are maintainable, performant, and adaptable to complex application requirements.
A comprehensive implementation of CSS custom properties showcasing dynamic theming, design tokens, runtime updates, and advanced variable techniques.
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <meta charset="UTF-8">
5 <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 <title>CSS Custom Properties & Variables Mastery</title>
7 <style>
8 /* =================
9 FOUNDATION DESIGN TOKENS
10 ================= */
11 :root {
12 /* Color Foundation - HSL for better manipulation */
13 --token-color-blue-h: 220;
14 --token-color-blue-s: 100%;
15 --token-color-purple-h: 270;
16 --token-color-purple-s: 95%;
17 --token-color-green-h: 142;
18 --token-color-green-s: 76%;
19 --token-color-red-h: 0;
20 --token-color-red-s: 84%;
21
22 /* Lightness scale for systematic color generation */
23 --token-lightness-50: 97%;
24 --token-lightness-100: 94%;
25 --token-lightness-200: 89%;
26 --token-lightness-300: 78%;
27 --token-lightness-400: 62%;
28 --token-lightness-500: 50%;
29 --token-lightness-600: 38%;
30 --token-lightness-700: 26%;
31 --token-lightness-800: 15%;
32 --token-lightness-900: 8%;
33
34 /* Typography Scale - Perfect Fourth (1.333) */
35 --token-font-size-root: 16px;
36 --token-font-size-ratio: 1.333;
37 --token-font-size-xs: calc(var(--token-font-size-root) / var(--token-font-size-ratio) / var(--token-font-size-ratio));
38 --token-font-size-sm: calc(var(--token-font-size-root) / var(--token-font-size-ratio));
39 --token-font-size-base: var(--token-font-size-root);
40 --token-font-size-lg: calc(var(--token-font-size-root) * var(--token-font-size-ratio));
41 --token-font-size-xl: calc(var(--token-font-size-lg) * var(--token-font-size-ratio));
42 --token-font-size-2xl: calc(var(--token-font-size-xl) * var(--token-font-size-ratio));
43 --token-font-size-3xl: calc(var(--token-font-size-2xl) * var(--token-font-size-ratio));
44
45 /* Spacing Scale - Golden Ratio (1.618) */
46 --token-space-unit: 0.5rem;
47 --token-space-ratio: 1.618;
48 --token-space-2xs: var(--token-space-unit);
49 --token-space-xs: calc(var(--token-space-unit) * var(--token-space-ratio));
50 --token-space-sm: calc(var(--token-space-xs) * var(--token-space-ratio));
51 --token-space-md: calc(var(--token-space-sm) * var(--token-space-ratio));
52 --token-space-lg: calc(var(--token-space-md) * var(--token-space-ratio));
53 --token-space-xl: calc(var(--token-space-lg) * var(--token-space-ratio));
54 --token-space-2xl: calc(var(--token-space-xl) * var(--token-space-ratio));
55
56 /* Animation Tokens */
57 --token-duration-instant: 0ms;
58 --token-duration-quick: 150ms;
59 --token-duration-moderate: 300ms;
60 --token-duration-deliberate: 500ms;
61 --token-easing-ease-out: cubic-bezier(0, 0, 0.2, 1);
62 --token-easing-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
63 --token-easing-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
64 }
65
66 /* =================
67 SEMANTIC THEME SYSTEM
68 ================= */
69 :root {
70 /* Light theme (default) */
71 --theme-name: 'Light';
72 --theme-primary-h: var(--token-color-blue-h);
73 --theme-primary-s: var(--token-color-blue-s);
74 --theme-accent-h: var(--token-color-purple-h);
75 --theme-accent-s: var(--token-color-purple-s);
76
77 /* Computed theme colors */
78 --color-primary-50: hsl(var(--theme-primary-h), var(--theme-primary-s), var(--token-lightness-50));
79 --color-primary-100: hsl(var(--theme-primary-h), var(--theme-primary-s), var(--token-lightness-100));
80 --color-primary-500: hsl(var(--theme-primary-h), var(--theme-primary-s), var(--token-lightness-500));
81 --color-primary-600: hsl(var(--theme-primary-h), var(--theme-primary-s), var(--token-lightness-600));
82 --color-primary-700: hsl(var(--theme-primary-h), var(--theme-primary-s), var(--token-lightness-700));
83
84 --color-accent-100: hsl(var(--theme-accent-h), var(--theme-accent-s), var(--token-lightness-100));
85 --color-accent-500: hsl(var(--theme-accent-h), var(--theme-accent-s), var(--token-lightness-500));
86 --color-accent-600: hsl(var(--theme-accent-h), var(--theme-accent-s), var(--token-lightness-600));
87
88 /* Surface colors */
89 --color-background: #ffffff;
90 --color-surface-primary: #ffffff;
91 --color-surface-secondary: #f8fafc;
92 --color-surface-tertiary: #f1f5f9;
93
94 /* Text colors */
95 --color-text-primary: #0f172a;
96 --color-text-secondary: #475569;
97 --color-text-tertiary: #64748b;
98 --color-text-muted: #94a3b8;
99
100 /* Border & Shadow */
101 --color-border-primary: #e2e8f0;
102 --color-border-secondary: #cbd5e1;
103 --shadow-color: 0, 0, 0;
104 --shadow-opacity: 0.1;
105
106 /* Interactive states */
107 --color-interactive-primary: var(--color-primary-500);
108 --color-interactive-primary-hover: var(--color-primary-600);
109 --color-interactive-secondary: var(--color-text-secondary);
110 --color-focus-ring: var(--color-primary-500);
111 }
112
113 /* Dark Theme */
114 [data-theme="dark"] {
115 --theme-name: 'Dark';
116 --color-background: #0f172a;
117 --color-surface-primary: #1e293b;
118 --color-surface-secondary: #334155;
119 --color-surface-tertiary: #475569;
120
121 --color-text-primary: #f8fafc;
122 --color-text-secondary: #cbd5e1;
123 --color-text-tertiary: #94a3b8;
124 --color-text-muted: #64748b;
125
126 --color-border-primary: #475569;
127 --color-border-secondary: #334155;
128 --shadow-opacity: 0.3;
129 }
130
131 /* Cyberpunk Theme */
132 [data-theme="cyberpunk"] {
133 --theme-name: 'Cyberpunk';
134 --theme-primary-h: 315;
135 --theme-primary-s: 100%;
136 --theme-accent-h: 180;
137 --theme-accent-s: 100%;
138
139 --color-background: #0a0a0f;
140 --color-surface-primary: #1a1a2e;
141 --color-surface-secondary: #16213e;
142 --color-surface-tertiary: #0f3460;
143
144 --color-text-primary: #00ffff;
145 --color-text-secondary: #ff00ff;
146 --color-text-tertiary: #ffffff;
147 --color-text-muted: #888888;
148
149 --color-border-primary: #ff00ff;
150 --color-border-secondary: #00ffff;
151 --shadow-opacity: 0.5;
152 }
153
154 /* Nature Theme */
155 [data-theme="nature"] {
156 --theme-name: 'Nature';
157 --theme-primary-h: 142;
158 --theme-primary-s: 76%;
159 --theme-accent-h: 45;
160 --theme-accent-s: 93%;
161
162 --color-background: #f0fdf4;
163 --color-surface-primary: #ffffff;
164 --color-surface-secondary: #ecfdf5;
165 --color-surface-tertiary: #d1fae5;
166
167 --color-text-primary: #14532d;
168 --color-text-secondary: #166534;
169 --color-text-tertiary: #15803d;
170 --color-text-muted: #4ade80;
171 }
172
173 /* =================
174 COMPONENT TOKENS
175 ================= */
176 :root {
177 /* Button System */
178 --button-height-sm: 2rem;
179 --button-height-md: 2.5rem;
180 --button-height-lg: 3rem;
181 --button-padding-x: var(--token-space-md);
182 --button-border-radius: 0.75rem;
183 --button-font-weight: 600;
184 --button-transition: all var(--token-duration-quick) var(--token-easing-ease-out);
185 --button-focus-ring: 0 0 0 3px color-mix(in srgb, var(--color-focus-ring) 20%, transparent);
186
187 /* Card System */
188 --card-padding: var(--token-space-lg);
189 --card-border-radius: 1rem;
190 --card-background: var(--color-surface-primary);
191 --card-border: 1px solid var(--color-border-primary);
192 --card-shadow: 0 4px 6px color-mix(in srgb, black var(--shadow-opacity), transparent);
193 --card-hover-shadow: 0 10px 15px color-mix(in srgb, black calc(var(--shadow-opacity) * 1.5), transparent);
194 --card-hover-transform: translateY(-2px) scale(1.01);
195
196 /* Input System */
197 --input-height: var(--button-height-md);
198 --input-padding: var(--token-space-sm) var(--token-space-md);
199 --input-border: 1px solid var(--color-border-primary);
200 --input-border-radius: 0.5rem;
201 --input-background: var(--color-surface-primary);
202 --input-focus-border: var(--color-focus-ring);
203 --input-focus-ring: var(--button-focus-ring);
204 }
205
206 /* =================
207 BASE STYLES
208 ================= */
209 * {
210 margin: 0;
211 padding: 0;
212 box-sizing: border-box;
213 }
214
215 body {
216 font-family: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
217 font-size: var(--token-font-size-base);
218 line-height: 1.6;
219 background: var(--color-background);
220 color: var(--color-text-primary);
221 transition: background-color var(--token-duration-moderate) var(--token-easing-ease-out),
222 color var(--token-duration-moderate) var(--token-easing-ease-out);
223 min-height: 100vh;
224 }
225
226 .container {
227 max-width: 1200px;
228 margin: 0 auto;
229 padding: var(--token-space-lg);
230 }
231
232 /* =================
233 COMPONENT IMPLEMENTATIONS
234 ================= */
235
236 /* Header with Theme Indicator */
237 .header {
238 text-align: center;
239 margin-bottom: var(--token-space-2xl);
240 position: relative;
241 }
242
243 .header::before {
244 content: '🎨 ' var(--theme-name) ' Theme Active';
245 position: absolute;
246 top: -2rem;
247 right: 0;
248 font-size: var(--token-font-size-sm);
249 color: var(--color-text-muted);
250 padding: var(--token-space-2xs) var(--token-space-sm);
251 background: var(--color-surface-secondary);
252 border-radius: var(--button-border-radius);
253 border: var(--card-border);
254 }
255
256 .header h1 {
257 font-size: var(--token-font-size-3xl);
258 margin-bottom: var(--token-space-md);
259 background: linear-gradient(135deg, var(--color-interactive-primary), var(--color-accent-500));
260 background-clip: text;
261 -webkit-background-clip: text;
262 color: transparent;
263 font-weight: 800;
264 }
265
266 .header p {
267 font-size: var(--token-font-size-lg);
268 color: var(--color-text-secondary);
269 max-width: 600px;
270 margin: 0 auto;
271 }
272
273 /* Button System */
274 .btn {
275 height: var(--button-height-md);
276 padding: 0 var(--button-padding-x);
277 border-radius: var(--button-border-radius);
278 font-weight: var(--button-font-weight);
279 font-size: var(--token-font-size-base);
280 border: none;
281 cursor: pointer;
282 display: inline-flex;
283 align-items: center;
284 justify-content: center;
285 gap: var(--token-space-xs);
286 text-decoration: none;
287 transition: var(--button-transition);
288 position: relative;
289 overflow: hidden;
290 }
291
292 .btn:focus-visible {
293 outline: none;
294 box-shadow: var(--button-focus-ring);
295 }
296
297 .btn--primary {
298 background: var(--color-interactive-primary);
299 color: white;
300 }
301
302 .btn--primary:hover {
303 background: var(--color-interactive-primary-hover);
304 transform: translateY(-1px);
305 }
306
307 .btn--secondary {
308 background: transparent;
309 color: var(--color-interactive-primary);
310 border: 1px solid var(--color-border-primary);
311 }
312
313 .btn--secondary:hover {
314 background: var(--color-surface-secondary);
315 border-color: var(--color-interactive-primary);
316 }
317
318 .btn--accent {
319 background: var(--color-accent-500);
320 color: white;
321 }
322
323 .btn--accent:hover {
324 background: var(--color-accent-600);
325 }
326
327 /* Size variants */
328 .btn--small {
329 height: var(--button-height-sm);
330 font-size: var(--token-font-size-sm);
331 }
332
333 .btn--large {
334 height: var(--button-height-lg);
335 font-size: var(--token-font-size-lg);
336 }
337
338 /* Card System */
339 .card {
340 background: var(--card-background);
341 border: var(--card-border);
342 border-radius: var(--card-border-radius);
343 padding: var(--card-padding);
344 box-shadow: var(--card-shadow);
345 transition: transform var(--token-duration-moderate) var(--token-easing-ease-out),
346 box-shadow var(--token-duration-moderate) var(--token-easing-ease-out);
347 }
348
349 .card:hover {
350 transform: var(--card-hover-transform);
351 box-shadow: var(--card-hover-shadow);
352 }
353
354 .card h3 {
355 font-size: var(--token-font-size-xl);
356 margin-bottom: var(--token-space-sm);
357 color: var(--color-interactive-primary);
358 }
359
360 .card p {
361 color: var(--color-text-secondary);
362 line-height: 1.7;
363 }
364
365 /* Theme Controls */
366 .theme-controls {
367 display: flex;
368 flex-wrap: wrap;
369 gap: var(--token-space-sm);
370 margin-bottom: var(--token-space-xl);
371 justify-content: center;
372 }
373
374 /* Dynamic Color Demo */
375 .color-palette {
376 display: grid;
377 grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
378 gap: var(--token-space-md);
379 margin: var(--token-space-lg) 0;
380 }
381
382 .color-swatch {
383 aspect-ratio: 1;
384 border-radius: var(--button-border-radius);
385 display: flex;
386 align-items: center;
387 justify-content: center;
388 color: white;
389 font-weight: 600;
390 font-size: var(--token-font-size-sm);
391 text-shadow: 0 1px 3px rgba(0,0,0,0.5);
392 position: relative;
393 overflow: hidden;
394 }
395
396 .color-swatch::after {
397 content: attr(data-color);
398 position: absolute;
399 bottom: 0;
400 left: 0;
401 right: 0;
402 background: rgba(0,0,0,0.8);
403 padding: var(--token-space-2xs);
404 font-size: var(--token-font-size-xs);
405 text-align: center;
406 }
407
408 .swatch-primary-500 { background: var(--color-primary-500); }
409 .swatch-primary-600 { background: var(--color-primary-600); }
410 .swatch-accent-500 { background: var(--color-accent-500); }
411 .swatch-accent-600 { background: var(--color-accent-600); }
412
413 /* Variable Inspector */
414 .variable-inspector {
415 background: var(--color-surface-secondary);
416 border: var(--card-border);
417 border-radius: var(--card-border-radius);
418 padding: var(--token-space-md);
419 margin: var(--token-space-lg) 0;
420 font-family: 'Monaco', 'Menlo', monospace;
421 font-size: var(--token-font-size-sm);
422 }
423
424 .variable-list {
425 list-style: none;
426 }
427
428 .variable-list li {
429 display: flex;
430 justify-content: space-between;
431 padding: var(--token-space-2xs) 0;
432 border-bottom: 1px solid var(--color-border-secondary);
433 }
434
435 .variable-name {
436 color: var(--color-accent-500);
437 font-weight: 600;
438 }
439
440 .variable-value {
441 color: var(--color-text-secondary);
442 }
443
444 /* Grid Demo */
445 .demo-grid {
446 display: grid;
447 grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
448 gap: var(--token-space-lg);
449 margin: var(--token-space-xl) 0;
450 }
451
452 /* Custom Property Animation */
453 .animated-element {
454 --animation-progress: 0;
455 --rotation: calc(var(--animation-progress) * 360deg);
456 --scale: calc(1 + (var(--animation-progress) * 0.2));
457 --hue-shift: calc(var(--animation-progress) * 60);
458
459 width: 100px;
460 height: 100px;
461 background: hsl(calc(var(--theme-primary-h) + var(--hue-shift)), var(--theme-primary-s), var(--token-lightness-500));
462 border-radius: 50%;
463 margin: var(--token-space-lg) auto;
464 transform: rotate(var(--rotation)) scale(var(--scale));
465 transition: transform var(--token-duration-moderate) var(--token-easing-ease-out);
466 }
467
468 /* Interactive Range Slider for CSS Variables */
469 .variable-control {
470 margin: var(--token-space-md) 0;
471 display: flex;
472 align-items: center;
473 gap: var(--token-space-sm);
474 }
475
476 .variable-control label {
477 font-weight: 600;
478 min-width: 140px;
479 font-size: var(--token-font-size-sm);
480 }
481
482 .variable-control input[type="range"] {
483 flex: 1;
484 height: 6px;
485 border-radius: 3px;
486 background: var(--color-surface-tertiary);
487 outline: none;
488 appearance: none;
489 }
490
491 .variable-control input[type="range"]::-webkit-slider-thumb {
492 appearance: none;
493 width: 20px;
494 height: 20px;
495 border-radius: 50%;
496 background: var(--color-interactive-primary);
497 cursor: pointer;
498 box-shadow: 0 2px 4px rgba(0,0,0,0.2);
499 }
500
501 .variable-control .value-display {
502 font-family: 'Monaco', 'Menlo', monospace;
503 font-size: var(--token-font-size-sm);
504 color: var(--color-text-secondary);
505 min-width: 60px;
506 text-align: right;
507 }
508
509 /* Responsive Design */
510 @media (max-width: 768px) {
511 .container {
512 padding: var(--token-space-md);
513 }
514
515 .header h1 {
516 font-size: var(--token-font-size-2xl);
517 }
518
519 .theme-controls {
520 justify-content: center;
521 }
522
523 .btn {
524 font-size: var(--token-font-size-sm);
525 }
526
527 .demo-grid {
528 grid-template-columns: 1fr;
529 }
530 }
531
532 /* Smooth theme transitions */
533 * {
534 transition: background-color var(--token-duration-moderate) var(--token-easing-ease-out),
535 color var(--token-duration-moderate) var(--token-easing-ease-out),
536 border-color var(--token-duration-moderate) var(--token-easing-ease-out),
537 box-shadow var(--token-duration-moderate) var(--token-easing-ease-out);
538 }
539 </style>
540</head>
541<body>
542 <div class="container">
543 <!-- Header -->
544 <header class="header">
545 <h1>CSS Custom Properties Mastery</h1>
546 <p>Experience the power of CSS variables with dynamic themes, design tokens, and runtime manipulation</p>
547 </header>
548
549 <!-- Theme Controls -->
550 <section class="theme-controls">
551 <button class="btn btn--primary" onclick="setTheme('light')">☀️ Light Theme</button>
552 <button class="btn btn--secondary" onclick="setTheme('dark')">🌙 Dark Theme</button>
553 <button class="btn btn--accent" onclick="setTheme('cyberpunk')">🤖 Cyberpunk</button>
554 <button class="btn btn--primary" onclick="setTheme('nature')">🌿 Nature</button>
555 <button class="btn btn--secondary" onclick="generateRandomTheme()">🎲 Random Theme</button>
556 </section>
557
558 <!-- Color Palette Demo -->
559 <section class="card">
560 <h3>🎨 Dynamic Color Palette</h3>
561 <p>These colors automatically update based on the current theme using CSS custom properties and HSL calculations.</p>
562
563 <div class="color-palette">
564 <div class="color-swatch swatch-primary-500" data-color="Primary 500">Primary</div>
565 <div class="color-swatch swatch-primary-600" data-color="Primary 600">Primary Dark</div>
566 <div class="color-swatch swatch-accent-500" data-color="Accent 500">Accent</div>
567 <div class="color-swatch swatch-accent-600" data-color="Accent 600">Accent Dark</div>
568 </div>
569 </section>
570
571 <!-- Interactive Variable Controls -->
572 <section class="card">
573 <h3>🎛️ Runtime Variable Control</h3>
574 <p>Manipulate CSS custom properties in real-time to see how they affect the design system.</p>
575
576 <div class="variable-control">
577 <label for="primary-hue">Primary Hue:</label>
578 <input type="range" id="primary-hue" min="0" max="360" value="220" oninput="updateVariable('theme-primary-h', this.value)">
579 <span class="value-display" id="primary-hue-value">220°</span>
580 </div>
581
582 <div class="variable-control">
583 <label for="primary-saturation">Primary Saturation:</label>
584 <input type="range" id="primary-saturation" min="0" max="100" value="100" oninput="updateVariable('theme-primary-s', this.value + '%')">
585 <span class="value-display" id="primary-saturation-value">100%</span>
586 </div>
587
588 <div class="variable-control">
589 <label for="accent-hue">Accent Hue:</label>
590 <input type="range" id="accent-hue" min="0" max="360" value="270" oninput="updateVariable('theme-accent-h', this.value)">
591 <span class="value-display" id="accent-hue-value">270°</span>
592 </div>
593
594 <div class="variable-control">
595 <label for="animation-progress">Animation Progress:</label>
596 <input type="range" id="animation-progress" min="0" max="1" step="0.01" value="0" oninput="updateVariable('animation-progress', this.value)">
597 <span class="value-display" id="animation-progress-value">0</span>
598 </div>
599
600 <div class="animated-element"></div>
601 </section>
602
603 <!-- Variable Inspector -->
604 <section class="card">
605 <h3>🔍 CSS Variable Inspector</h3>
606 <p>Current values of key CSS custom properties in the design system.</p>
607
608 <div class="variable-inspector">
609 <ul class="variable-list" id="variable-list">
610 <!-- Variables will be populated by JavaScript -->
611 </ul>
612 </div>
613 </section>
614
615 <!-- Component Showcase -->
616 <section class="demo-grid">
617 <div class="card">
618 <h3>🎯 Design Tokens</h3>
619 <p>Systematic approach to design values using CSS custom properties for typography, spacing, and colors.</p>
620 <div style="margin-top: var(--token-space-md);">
621 <button class="btn btn--primary btn--small">Small</button>
622 <button class="btn btn--primary">Medium</button>
623 <button class="btn btn--primary btn--large">Large</button>
624 </div>
625 </div>
626
627 <div class="card">
628 <h3>🔄 Dynamic Theming</h3>
629 <p>Themes change instantly across all components using CSS custom property inheritance and cascading.</p>
630 <div style="margin-top: var(--token-space-md);">
631 <button class="btn btn--secondary">Secondary</button>
632 <button class="btn btn--accent">Accent Color</button>
633 </div>
634 </div>
635
636 <div class="card">
637 <h3>📐 Calculated Values</h3>
638 <p>CSS custom properties enable complex calculations for responsive design and systematic scales.</p>
639 <div style="margin-top: var(--token-space-md); display: flex; gap: var(--token-space-sm);">
640 <div style="width: var(--token-space-md); height: var(--token-space-md); background: var(--color-interactive-primary);"></div>
641 <div style="width: var(--token-space-lg); height: var(--token-space-lg); background: var(--color-accent-500);"></div>
642 <div style="width: var(--token-space-xl); height: var(--token-space-xl); background: var(--color-interactive-primary);"></div>
643 </div>
644 </div>
645
646 <div class="card">
647 <h3>🎨 Runtime Updates</h3>
648 <p>CSS variables can be modified with JavaScript for interactive experiences and user customization.</p>
649 <div style="margin-top: var(--token-space-md);">
650 <button class="btn btn--primary" onclick="pulseEffect()">Pulse Effect</button>
651 <button class="btn btn--secondary" onclick="colorCycle()">Color Cycle</button>
652 </div>
653 </div>
654 </section>
655
656 <!-- Performance Tips -->
657 <section class="card" style="margin-top: var(--token-space-xl);">
658 <h3>⚡ Performance & Best Practices</h3>
659 <ul style="color: var(--color-text-secondary); padding-left: var(--token-space-md); line-height: 1.8;">
660 <li><strong>Use semantic naming:</strong> --color-primary vs --blue-500 for better maintainability</li>
661 <li><strong>Group related properties:</strong> Organize variables by system (color, spacing, typography)</li>
662 <li><strong>Provide fallbacks:</strong> Always include fallback values in var() functions</li>
663 <li><strong>Pre-calculate values:</strong> Avoid complex calc() expressions in frequently-used properties</li>
664 <li><strong>Leverage inheritance:</strong> Use CSS cascading to minimize property redefinition</li>
665 <li><strong>Test across themes:</strong> Ensure all components work with different theme configurations</li>
666 </ul>
667 </section>
668 </div>
669
670 <script>
671 // CSS Variable Management System
672 class CSSVariableManager {
673 constructor() {
674 this.root = document.documentElement;
675 this.currentTheme = localStorage.getItem('theme') || 'light';
676 this.applyTheme(this.currentTheme);
677 this.setupVariableInspector();
678 this.setupEventListeners();
679 }
680
681 // Set CSS variable with validation
682 setVariable(name, value) {
683 const propertyName = name.startsWith('--') ? name : `--\${name}`;
684 this.root.style.setProperty(propertyName, value);
685 this.updateVariableInspector();
686 }
687
688 // Get CSS variable value
689 getVariable(name) {
690 const propertyName = name.startsWith('--') ? name : `--\${name}`;
691 return getComputedStyle(this.root).getPropertyValue(propertyName).trim();
692 }
693
694 // Apply theme
695 applyTheme(theme) {
696 this.root.dataset.theme = theme;
697 localStorage.setItem('theme', theme);
698 this.currentTheme = theme;
699 this.updateVariableInspector();
700
701 // Reset sliders to theme defaults
702 this.resetThemeControls();
703 }
704
705 // Reset theme control sliders
706 resetThemeControls() {
707 const primaryHue = this.getVariable('theme-primary-h') || '220';
708 const primarySat = this.getVariable('theme-primary-s') || '100%';
709 const accentHue = this.getVariable('theme-accent-h') || '270';
710
711 document.getElementById('primary-hue').value = parseInt(primaryHue);
712 document.getElementById('primary-saturation').value = parseInt(primarySat);
713 document.getElementById('accent-hue').value = parseInt(accentHue);
714
715 document.getElementById('primary-hue-value').textContent = primaryHue + '°';
716 document.getElementById('primary-saturation-value').textContent = primarySat;
717 document.getElementById('accent-hue-value').textContent = accentHue + '°';
718 }
719
720 // Generate random theme
721 generateRandomTheme() {
722 const primaryHue = Math.floor(Math.random() * 360);
723 const accentHue = (primaryHue + 120 + Math.floor(Math.random() * 120)) % 360;
724 const saturation = 70 + Math.floor(Math.random() * 30); // 70-100%
725
726 this.setVariable('theme-primary-h', primaryHue);
727 this.setVariable('theme-primary-s', saturation + '%');
728 this.setVariable('theme-accent-h', accentHue);
729 this.setVariable('theme-accent-s', saturation + '%');
730
731 // Update sliders
732 document.getElementById('primary-hue').value = primaryHue;
733 document.getElementById('primary-saturation').value = saturation;
734 document.getElementById('accent-hue').value = accentHue;
735
736 document.getElementById('primary-hue-value').textContent = primaryHue + '°';
737 document.getElementById('primary-saturation-value').textContent = saturation + '%';
738 document.getElementById('accent-hue-value').textContent = accentHue + '°';
739
740 this.updateVariableInspector();
741 }
742
743 // Setup variable inspector
744 setupVariableInspector() {
745 const inspectedVariables = [
746 'theme-primary-h',
747 'theme-primary-s',
748 'theme-accent-h',
749 'theme-accent-s',
750 'color-background',
751 'color-text-primary',
752 'token-space-md',
753 'token-font-size-base',
754 'animation-progress'
755 ];
756
757 const list = document.getElementById('variable-list');
758 list.innerHTML = '';
759
760 inspectedVariables.forEach(variable => {
761 const value = this.getVariable(variable);
762 const li = document.createElement('li');
763 li.innerHTML = `766`;
767 list.appendChild(li);
768 });
769 }
770
771 // Update variable inspector
772 updateVariableInspector() {
773 setTimeout(() => this.setupVariableInspector(), 100);
774 }
775
776 // Setup event listeners
777 setupEventListeners() {
778 // Watch for system theme changes
779 const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
780 mediaQuery.addListener((e) => {
781 if (!localStorage.getItem('theme')) {
782 this.applyTheme(e.matches ? 'dark' : 'light');
783 }
784 });
785 }
786
787 // Animation effects
788 pulseEffect() {
789 const element = document.querySelector('.animated-element');
790 element.style.setProperty('--animation-progress', '0');
791
792 setTimeout(() => {
793 element.style.setProperty('--animation-progress', '1');
794 setTimeout(() => {
795 element.style.setProperty('--animation-progress', '0');
796 }, 600);
797 }, 50);
798 }
799
800 colorCycle() {
801 let hue = 0;
802 const interval = setInterval(() => {
803 this.setVariable('theme-primary-h', hue);
804 hue = (hue + 10) % 360;
805
806 if (hue === 0) {
807 clearInterval(interval);
808 // Reset to theme default
809 setTimeout(() => {
810 this.resetThemeControls();
811 }, 500);
812 }
813 }, 100);
814 }
815 }
816
817 // Initialize CSS Variable Manager
818 const variableManager = new CSSVariableManager();
819
820 // Global functions for theme controls
821 function setTheme(theme) {
822 variableManager.applyTheme(theme);
823 }
824
825 function updateVariable(name, value) {
826 variableManager.setVariable(name, value);
827
828 // Update display values
829 const control = document.querySelector(`#\${name.replace(/\\[^a-zA-Z0-9\\]/g, '-')}`);
830 if (control) {
831 const display = control.parentElement.querySelector('.value-display');
832 if (display) {
833 display.textContent = value;
834 }
835 }
836 }
837
838 function generateRandomTheme() {
839 variableManager.generateRandomTheme();
840 }
841
842 function pulseEffect() {
843 variableManager.pulseEffect();
844 }
845
846 function colorCycle() {
847 variableManager.colorCycle();
848 }
849
850 // Initialize display values for range inputs
851 document.addEventListener('DOMContentLoaded', () => {
852 const ranges = document.querySelectorAll('input[type="range"]');
853 ranges.forEach(range => {
854 const display = range.parentElement.querySelector('.value-display');
855 if (display && range.id.includes('hue')) {
856 display.textContent = range.value + '°';
857 } else if (display && range.id.includes('saturation')) {
858 display.textContent = range.value + '%';
859 } else if (display) {
860 display.textContent = range.value;
861 }
862 });
863 });
864
865 console.log('🎨 CSS Custom Properties Mastery loaded! Explore themes, variables, and dynamic styling.');
866 </script>
867</body>
868</html>This comprehensive demonstration showcases every aspect of CSS Custom Properties & Variables Mastery:
🎯 Foundation Design Token System:
1. Systematic Color Architecture:
2. Typography & Spacing Scales:
3. Advanced Theming System:
4. Dynamic Variable Manipulation:
Interactive Controls:
Runtime JavaScript Integration:
5. Component Integration Patterns:
Button System:
Card Components:
6. Advanced CSS Techniques Demonstrated:
Calculated Values:
Performance Optimizations:
7. Design System Architecture:
Token Hierarchy:
Naming Conventions:
8. Interactive Demonstrations:
Theme Controls:
Variable Inspector:
9. Real-World Applications:
Color Palette Visualization:
Animation Control:
10. Best Practices Implementation:
This demonstration serves as both a comprehensive learning tool and practical reference for implementing sophisticated CSS custom property systems in production applications, showcasing how variables transform static stylesheets into dynamic, intelligent design systems.
Outstanding work mastering CSS custom properties and variables! You now have the skills to build sophisticated design systems with dynamic theming, runtime updates, and systematic token architectures. Next, we'll explore "Advanced Pseudo-elements & Pseudo-classes" where you'll learn to create complex selectors, generate dynamic content, and build sophisticated styling patterns that extend beyond basic CSS capabilities. Get ready to unlock the full power of CSS selectors!
Your progress is saved in this browser, on this device only.