Master CSS custom properties for dynamic theming, maintainable code, and responsive design systems. Learn variable scope, inheritance, and calc() functions.
CSS custom properties (variables) revolutionize how we write maintainable, dynamic stylesheets by allowing us to store and reuse values throughout our CSS. Unlike preprocessor variables, CSS custom properties are live values that can change dynamically, respond to user interactions, and be modified with JavaScript.
Custom properties enable powerful design systems where changing a single variable can update an entire theme, support responsive design with calculated values, and create more maintainable codebases by centralizing design tokens. They're essential for modern CSS architecture and component-based styling.
This lesson will teach you everything about CSS custom properties: from basic syntax and scope to advanced techniques like theming systems, responsive calculations, and integration with JavaScript. You'll learn to build flexible, maintainable stylesheets that scale with your projects.
CSS custom properties provide a way to store values that can be reused and modified throughout your stylesheets.
Basic Syntax and Declaration:
1/* Declaration with -- prefix */
2:root {
3 --primary-color: #3b82f6;
4 --secondary-color: #64748b;
5 --success-color: #10b981;
6 --warning-color: #f59e0b;
7 --error-color: #ef4444;
8
9 --base-font-size: 16px;
10 --line-height: 1.6;
11 --border-radius: 8px;
12 --box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
13
14 --spacing-xs: 0.5rem;
15 --spacing-sm: 1rem;
16 --spacing-md: 1.5rem;
17 --spacing-lg: 2rem;
18 --spacing-xl: 3rem;
19}
20
21/* Usage with var() function */
22.button {
23 background: var(--primary-color);
24 color: white;
25 padding: var(--spacing-sm) var(--spacing-md);
26 border-radius: var(--border-radius);
27 box-shadow: var(--box-shadow);
28 font-size: var(--base-font-size);
29 line-height: var(--line-height);
30}
31
32.card {
33 background: white;
34 padding: var(--spacing-lg);
35 border-radius: var(--border-radius);
36 box-shadow: var(--box-shadow);
37 margin-bottom: var(--spacing-md);
38}Fallback Values:
1/* var() with fallback values */
2.element {
3 /* Single fallback */
4 color: var(--text-color, #1a1a1a);
5
6 /* Multiple fallbacks */
7 font-family: var(--custom-font, var(--system-font, system-ui));
8
9 /* Complex fallbacks */
10 background: var(--gradient-bg, linear-gradient(135deg, #667eea 0%, #764ba2 100%));
11
12 /* Nested var() functions */
13 padding: var(--component-padding, var(--default-padding, 1rem));
14
15 /* Fallback for calculations */
16 width: var(--custom-width, calc(100% - 2rem));
17}
18
19/* Conditional values using invalid fallbacks */
20.responsive-element {
21 /* Desktop first approach */
22 font-size: var(--mobile-font-size, 1.2rem);
23}
24
25@media (max-width: 768px) {
26 .responsive-element {
27 --mobile-font-size: 1rem;
28 }
29}Variable Inheritance and Cascade:
1/* Global variables */
2:root {
3 --primary: #3b82f6;
4 --text: #1e293b;
5 --background: #ffffff;
6}
7
8/* Component-level variables */
9.card {
10 --card-padding: 2rem;
11 --card-border: 1px solid #e5e7eb;
12
13 padding: var(--card-padding);
14 border: var(--card-border);
15 background: var(--background);
16 color: var(--text);
17}
18
19/* Inherited and overridden variables */
20.card.featured {
21 --card-padding: 3rem;
22 --card-border: 2px solid var(--primary);
23 --background: #f8fafc;
24}
25
26.card.compact {
27 --card-padding: 1rem;
28}
29
30/* Scoped variables */
31.theme-dark {
32 --text: #f8fafc;
33 --background: #1e293b;
34 --primary: #60a5fa;
35}
36
37.theme-dark .card {
38 /* Inherits updated variables from parent */
39 background: var(--background);
40 color: var(--text);
41}Local vs Global Scope:
1/* Global scope - available everywhere */
2:root {
3 --global-color: #3b82f6;
4 --global-spacing: 1rem;
5}
6
7/* Element scope - only available to element and children */
8.component {
9 --local-color: #10b981;
10 --local-spacing: 0.5rem;
11
12 color: var(--local-color);
13 padding: var(--local-spacing);
14}
15
16.component .child {
17 /* Can access parent's local variables */
18 border-color: var(--local-color);
19 /* And global variables */
20 margin: var(--global-spacing);
21}
22
23.other-component {
24 /* Cannot access .component's local variables */
25 /* color: var(--local-color); -- This won't work */
26
27 /* But can access global variables */
28 color: var(--global-color);
29}
30
31/* Media query scope */
32@media (max-width: 768px) {
33 :root {
34 --global-spacing: 0.75rem; /* Override global variable */
35 }
36
37 .mobile-specific {
38 --mobile-font: 0.9rem; /* Local to media query */
39 font-size: var(--mobile-font);
40 }
41}
42
43/* Container-specific scope */
44.container {
45 --container-width: 1200px;
46}
47
48.container.narrow {
49 --container-width: 800px;
50}
51
52.container .content {
53 max-width: var(--container-width);
54 margin: 0 auto;
55}Invalid Values and Error Handling:
1/* Invalid custom property values */
2.element {
3 --invalid-color: red blue; /* Invalid - will be ignored */
4 --valid-color: #ff0000;
5
6 /* Browser will use fallback for invalid values */
7 color: var(--invalid-color, var(--valid-color));
8}
9
10/* Type checking with custom properties */
11.typed-element {
12 /* These work fine */
13 --number: 42;
14 --length: 100px;
15 --color: #3b82f6;
16 --string: "hello world";
17
18 /* Usage determines validity */
19 font-size: calc(var(--number) * 1px); /* Valid - creates 42px */
20 width: var(--length); /* Valid - 100px */
21 color: var(--color); /* Valid - #3b82f6 */
22 /* content: var(--string); -- Valid in content property */
23}
24
25/* Debugging custom properties */
26.debug {
27 /* Use initial to reset custom properties */
28 --debug-color: initial;
29
30 /* Use inherit to force inheritance */
31 --inherited-value: inherit;
32
33 /* Use unset for natural behavior */
34 --natural-value: unset;
35}Create flexible theming systems that can switch between different visual styles dynamically using CSS custom properties.
Light and Dark Mode Theming:
1/* Base theme variables */
2:root {
3 --theme-bg-primary: #ffffff;
4 --theme-bg-secondary: #f8fafc;
5 --theme-bg-tertiary: #f1f5f9;
6
7 --theme-text-primary: #0f172a;
8 --theme-text-secondary: #475569;
9 --theme-text-tertiary: #64748b;
10
11 --theme-border: #e2e8f0;
12 --theme-border-hover: #cbd5e1;
13
14 --theme-accent: #3b82f6;
15 --theme-accent-hover: #2563eb;
16 --theme-accent-bg: #eff6ff;
17
18 --theme-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
19 --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
20}
21
22/* Dark theme overrides */
23[data-theme="dark"] {
24 --theme-bg-primary: #0f172a;
25 --theme-bg-secondary: #1e293b;
26 --theme-bg-tertiary: #334155;
27
28 --theme-text-primary: #f8fafc;
29 --theme-text-secondary: #e2e8f0;
30 --theme-text-tertiary: #cbd5e1;
31
32 --theme-border: #475569;
33 --theme-border-hover: #64748b;
34
35 --theme-accent: #60a5fa;
36 --theme-accent-hover: #3b82f6;
37 --theme-accent-bg: #1e3a8a;
38
39 --theme-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
40 --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3);
41}
42
43/* System preference detection */
44@media (prefers-color-scheme: dark) {
45 :root {
46 --theme-bg-primary: #0f172a;
47 --theme-bg-secondary: #1e293b;
48 --theme-text-primary: #f8fafc;
49 --theme-text-secondary: #e2e8f0;
50 /* ... other dark theme variables */
51 }
52}
53
54/* Component styling using theme variables */
55body {
56 background: var(--theme-bg-primary);
57 color: var(--theme-text-primary);
58 transition: background 0.3s ease, color 0.3s ease;
59}
60
61.card {
62 background: var(--theme-bg-secondary);
63 border: 1px solid var(--theme-border);
64 box-shadow: var(--theme-shadow);
65 color: var(--theme-text-primary);
66}
67
68.card:hover {
69 border-color: var(--theme-border-hover);
70 box-shadow: var(--theme-shadow-lg);
71}
72
73.button {
74 background: var(--theme-accent);
75 color: var(--theme-bg-primary);
76 border: 1px solid var(--theme-accent);
77}
78
79.button:hover {
80 background: var(--theme-accent-hover);
81}
82
83.button.secondary {
84 background: var(--theme-accent-bg);
85 color: var(--theme-accent);
86}Brand Theme Variations:
1/* Base brand system */
2:root {
3 --brand-primary: #3b82f6;
4 --brand-secondary: #64748b;
5 --brand-success: #10b981;
6 --brand-warning: #f59e0b;
7 --brand-danger: #ef4444;
8}
9
10/* Blue theme (default) */
11.theme-blue {
12 --brand-primary: #3b82f6;
13 --brand-primary-light: #dbeafe;
14 --brand-primary-dark: #1e40af;
15 --brand-gradient: linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%);
16}
17
18/* Green theme */
19.theme-green {
20 --brand-primary: #10b981;
21 --brand-primary-light: #d1fae5;
22 --brand-primary-dark: #047857;
23 --brand-gradient: linear-gradient(135deg, #10b981 0%, #059669 100%);
24}
25
26/* Purple theme */
27.theme-purple {
28 --brand-primary: #8b5cf6;
29 --brand-primary-light: #ede9fe;
30 --brand-primary-dark: #7c3aed;
31 --brand-gradient: linear-gradient(135deg, #8b5cf6 0%, #7c3aed 100%);
32}
33
34/* Orange theme */
35.theme-orange {
36 --brand-primary: #f97316;
37 --brand-primary-light: #fed7aa;
38 --brand-primary-dark: #ea580c;
39 --brand-gradient: linear-gradient(135deg, #f97316 0%, #ea580c 100%);
40}
41
42/* Components using brand variables */
43.hero {
44 background: var(--brand-gradient);
45}
46
47.badge {
48 background: var(--brand-primary-light);
49 color: var(--brand-primary-dark);
50 border: 1px solid var(--brand-primary);
51}
52
53.progress-bar {
54 background: var(--brand-primary);
55}Contextual Theming:
1/* Context-based theme switching */
2.error-context {
3 --context-color: var(--brand-danger);
4 --context-bg: #fef2f2;
5 --context-border: #fecaca;
6}
7
8.success-context {
9 --context-color: var(--brand-success);
10 --context-bg: #f0fdf4;
11 --context-border: #bbf7d0;
12}
13
14.warning-context {
15 --context-color: var(--brand-warning);
16 --context-bg: #fefbeb;
17 --context-border: #fde68a;
18}
19
20.info-context {
21 --context-color: var(--brand-primary);
22 --context-bg: #eff6ff;
23 --context-border: #dbeafe;
24}
25
26/* Contextual components */
27.alert {
28 background: var(--context-bg);
29 color: var(--context-color);
30 border: 1px solid var(--context-border);
31 padding: 1rem;
32 border-radius: 0.5rem;
33}
34
35.alert .icon {
36 color: var(--context-color);
37}
38
39.alert .button {
40 background: var(--context-color);
41 border-color: var(--context-color);
42}
43
44/* Size variations using custom properties */
45.component {
46 --size-multiplier: 1;
47 --base-padding: 1rem;
48 --base-font-size: 1rem;
49 --base-border-radius: 0.5rem;
50
51 padding: calc(var(--base-padding) * var(--size-multiplier));
52 font-size: calc(var(--base-font-size) * var(--size-multiplier));
53 border-radius: calc(var(--base-border-radius) * var(--size-multiplier));
54}
55
56.component.small { --size-multiplier: 0.75; }
57.component.large { --size-multiplier: 1.25; }
58.component.xl { --size-multiplier: 1.5; }CSS-in-JS Style Theming:
1/* Component-based theming similar to styled-components */
2.styled-button {
3 /* Default theme */
4 --btn-bg: var(--brand-primary);
5 --btn-color: white;
6 --btn-border: var(--brand-primary);
7 --btn-hover-bg: var(--brand-primary-dark);
8 --btn-hover-border: var(--brand-primary-dark);
9 --btn-padding-x: 1.5rem;
10 --btn-padding-y: 0.75rem;
11 --btn-font-weight: 500;
12 --btn-border-radius: 0.5rem;
13
14 background: var(--btn-bg);
15 color: var(--btn-color);
16 border: 1px solid var(--btn-border);
17 padding: var(--btn-padding-y) var(--btn-padding-x);
18 font-weight: var(--btn-font-weight);
19 border-radius: var(--btn-border-radius);
20 cursor: pointer;
21 transition: all 0.2s ease;
22}
23
24.styled-button:hover {
25 background: var(--btn-hover-bg);
26 border-color: var(--btn-hover-border);
27}
28
29/* Variant modifications */
30.styled-button.outline {
31 --btn-bg: transparent;
32 --btn-color: var(--brand-primary);
33 --btn-hover-bg: var(--brand-primary);
34 --btn-hover-color: white;
35}
36
37.styled-button.ghost {
38 --btn-bg: transparent;
39 --btn-border: transparent;
40 --btn-color: var(--brand-primary);
41 --btn-hover-bg: var(--brand-primary-light);
42}
43
44.styled-button.danger {
45 --btn-bg: var(--brand-danger);
46 --btn-border: var(--brand-danger);
47 --btn-hover-bg: #dc2626;
48 --btn-hover-border: #dc2626;
49}
50
51/* Size variations */
52.styled-button.sm {
53 --btn-padding-x: 1rem;
54 --btn-padding-y: 0.5rem;
55 --btn-font-size: 0.875rem;
56}
57
58.styled-button.lg {
59 --btn-padding-x: 2rem;
60 --btn-padding-y: 1rem;
61 --btn-font-size: 1.125rem;
62}Master the calc() function with custom properties to create flexible, responsive layouts and dynamic styling systems.
Basic Calculations:
1/* Basic arithmetic with variables */
2:root {
3 --base-unit: 1rem;
4 --multiplier: 1.5;
5 --container-width: 1200px;
6 --sidebar-width: 300px;
7 --gap: 2rem;
8}
9
10.layout {
11 --main-width: calc(var(--container-width) - var(--sidebar-width) - var(--gap));
12
13 display: grid;
14 grid-template-columns: var(--sidebar-width) var(--main-width);
15 gap: var(--gap);
16 max-width: var(--container-width);
17}
18
19.typography {
20 --h1-size: calc(var(--base-unit) * 2.5);
21 --h2-size: calc(var(--base-unit) * 2);
22 --h3-size: calc(var(--base-unit) * 1.75);
23 --h4-size: calc(var(--base-unit) * 1.5);
24 --body-size: var(--base-unit);
25 --small-size: calc(var(--base-unit) * 0.875);
26}
27
28h1 { font-size: var(--h1-size); }
29h2 { font-size: var(--h2-size); }
30h3 { font-size: var(--h3-size); }
31h4 { font-size: var(--h4-size); }
32p { font-size: var(--body-size); }
33small { font-size: var(--small-size); }Responsive Calculations:
1/* Fluid typography using calc() and viewport units */
2:root {
3 --min-font-size: 16;
4 --max-font-size: 24;
5 --min-viewport: 320;
6 --max-viewport: 1200;
7
8 /* Calculated fluid font size */
9 --font-size: calc(
10 var(--min-font-size) * 1px +
11 (var(--max-font-size) - var(--min-font-size)) *
12 (100vw - var(--min-viewport) * 1px) /
13 (var(--max-viewport) - var(--min-viewport))
14 );
15}
16
17body {
18 font-size: var(--font-size);
19 line-height: calc(var(--font-size) * 1.6);
20}
21
22/* Responsive spacing system */
23:root {
24 --space-unit: 1rem;
25 --space-ratio: 1.618; /* Golden ratio */
26
27 --space-xs: calc(var(--space-unit) / (var(--space-ratio) * var(--space-ratio)));
28 --space-sm: calc(var(--space-unit) / var(--space-ratio));
29 --space-md: var(--space-unit);
30 --space-lg: calc(var(--space-unit) * var(--space-ratio));
31 --space-xl: calc(var(--space-unit) * var(--space-ratio) * var(--space-ratio));
32 --space-xxl: calc(var(--space-unit) * var(--space-ratio) * var(--space-ratio) * var(--space-ratio));
33}
34
35/* Dynamic grid calculations */
36.responsive-grid {
37 --min-item-width: 300px;
38 --gap: 1.5rem;
39 --grid-columns: max(1, floor((100% + var(--gap)) / (var(--min-item-width) + var(--gap))));
40
41 display: grid;
42 grid-template-columns: repeat(auto-fill, minmax(var(--min-item-width), 1fr));
43 gap: var(--gap);
44}
45
46/* Container-based responsive design */
47.container {
48 --container-padding: clamp(1rem, 5vw, 3rem);
49 --content-max-width: min(90vw, 1200px);
50
51 width: 100%;
52 max-width: var(--content-max-width);
53 margin: 0 auto;
54 padding: 0 var(--container-padding);
55}Complex Layout Calculations:
1/* Advanced grid layout with calculations */
2.dashboard-layout {
3 --header-height: 4rem;
4 --sidebar-width: 16rem;
5 --footer-height: 3rem;
6 --gap: 1rem;
7
8 --main-height: calc(100vh - var(--header-height) - var(--footer-height));
9 --content-width: calc(100vw - var(--sidebar-width) - var(--gap) * 2);
10
11 display: grid;
12 grid-template-areas:
13 "sidebar header"
14 "sidebar main"
15 "sidebar footer";
16 grid-template-columns: var(--sidebar-width) 1fr;
17 grid-template-rows: var(--header-height) 1fr var(--footer-height);
18 gap: var(--gap);
19 height: 100vh;
20}
21
22/* Card layout with dynamic sizing */
23.card-container {
24 --card-min-width: 280px;
25 --card-max-width: 400px;
26 --card-gap: 1.5rem;
27 --available-width: calc(100% - var(--card-gap) * 2);
28
29 --cards-per-row: max(1, floor(var(--available-width) / var(--card-min-width)));
30 --card-width: min(
31 var(--card-max-width),
32 calc((var(--available-width) - (var(--cards-per-row) - 1) * var(--card-gap)) / var(--cards-per-row))
33 );
34
35 display: flex;
36 flex-wrap: wrap;
37 gap: var(--card-gap);
38}
39
40.card-container .card {
41 flex: 0 0 var(--card-width);
42}
43
44/* Aspect ratio calculations */
45.media-container {
46 --aspect-ratio: 16/9;
47 --max-height: 60vh;
48 --calculated-height: calc(var(--width) / var(--aspect-ratio));
49
50 width: 100%;
51 height: min(var(--calculated-height), var(--max-height));
52 position: relative;
53 overflow: hidden;
54}
55
56/* Dynamic spacing based on content */
57.content-spacing {
58 --content-length: attr(data-content-length number, 100);
59 --base-spacing: 1rem;
60 --spacing-multiplier: calc(1 + (var(--content-length) - 100) / 1000);
61
62 margin-bottom: calc(var(--base-spacing) * var(--spacing-multiplier));
63}Animation and Transition Calculations:
1/* Dynamic animations with custom properties */
2:root {
3 --animation-speed: 1;
4 --animation-delay-base: 0.1s;
5 --ease-curve: cubic-bezier(0.4, 0, 0.2, 1);
6}
7
8.animated-element {
9 --element-index: 1;
10 --calculated-delay: calc(var(--animation-delay-base) * var(--element-index));
11 --calculated-duration: calc(0.3s / var(--animation-speed));
12
13 animation-delay: var(--calculated-delay);
14 animation-duration: var(--calculated-duration);
15 animation-timing-function: var(--ease-curve);
16}
17
18/* Staggered animation system */
19.stagger-container {
20 --stagger-delay: 0.1s;
21}
22
23.stagger-item:nth-child(1) { --item-index: 1; }
24.stagger-item:nth-child(2) { --item-index: 2; }
25.stagger-item:nth-child(3) { --item-index: 3; }
26.stagger-item:nth-child(4) { --item-index: 4; }
27.stagger-item:nth-child(5) { --item-index: 5; }
28
29.stagger-item {
30 --calculated-delay: calc(var(--stagger-delay) * var(--item-index));
31 animation-delay: var(--calculated-delay);
32}
33
34/* Interactive scaling calculations */
35.interactive-scale {
36 --base-scale: 1;
37 --hover-multiplier: 1.05;
38 --active-multiplier: 0.95;
39 --transition-duration: 0.2s;
40
41 transform: scale(var(--base-scale));
42 transition: transform var(--transition-duration) ease;
43}
44
45.interactive-scale:hover {
46 --current-scale: calc(var(--base-scale) * var(--hover-multiplier));
47 transform: scale(var(--current-scale));
48}
49
50.interactive-scale:active {
51 --current-scale: calc(var(--base-scale) * var(--active-multiplier));
52 transform: scale(var(--current-scale));
53}
54
55/* Progress calculations */
56.progress-bar {
57 --progress: 0; /* 0-100 */
58 --bar-width: calc(var(--progress) * 1%);
59 --hue: calc(var(--progress) * 1.2); /* 0 = red, 120 = green */
60
61 width: 100%;
62 height: 8px;
63 background: #e5e7eb;
64 border-radius: 4px;
65 overflow: hidden;
66}
67
68.progress-bar::before {
69 content: '';
70 display: block;
71 width: var(--bar-width);
72 height: 100%;
73 background: hsl(var(--hue), 70%, 50%);
74 transition: width 0.3s ease, background-color 0.3s ease;
75}Explore advanced techniques for using CSS custom properties in design systems, component libraries, and dynamic interfaces.
Design Token Systems:
1/* Comprehensive design token system */
2:root {
3 /* Color tokens */
4 --color-primary-50: #eff6ff;
5 --color-primary-100: #dbeafe;
6 --color-primary-200: #bfdbfe;
7 --color-primary-300: #93c5fd;
8 --color-primary-400: #60a5fa;
9 --color-primary-500: #3b82f6;
10 --color-primary-600: #2563eb;
11 --color-primary-700: #1d4ed8;
12 --color-primary-800: #1e40af;
13 --color-primary-900: #1e3a8a;
14
15 /* Semantic color mappings */
16 --color-primary: var(--color-primary-500);
17 --color-primary-hover: var(--color-primary-600);
18 --color-primary-active: var(--color-primary-700);
19 --color-primary-light: var(--color-primary-50);
20 --color-primary-dark: var(--color-primary-900);
21
22 /* Typography tokens */
23 --font-family-sans: 'Inter', system-ui, sans-serif;
24 --font-family-serif: 'Playfair Display', serif;
25 --font-family-mono: 'JetBrains Mono', monospace;
26
27 --font-weight-light: 300;
28 --font-weight-normal: 400;
29 --font-weight-medium: 500;
30 --font-weight-semibold: 600;
31 --font-weight-bold: 700;
32
33 --font-size-xs: 0.75rem;
34 --font-size-sm: 0.875rem;
35 --font-size-base: 1rem;
36 --font-size-lg: 1.125rem;
37 --font-size-xl: 1.25rem;
38 --font-size-2xl: 1.5rem;
39 --font-size-3xl: 1.875rem;
40 --font-size-4xl: 2.25rem;
41
42 --line-height-tight: 1.25;
43 --line-height-snug: 1.375;
44 --line-height-normal: 1.5;
45 --line-height-relaxed: 1.625;
46 --line-height-loose: 2;
47
48 /* Spacing tokens */
49 --space-px: 1px;
50 --space-0: 0;
51 --space-0-5: 0.125rem;
52 --space-1: 0.25rem;
53 --space-1-5: 0.375rem;
54 --space-2: 0.5rem;
55 --space-2-5: 0.625rem;
56 --space-3: 0.75rem;
57 --space-3-5: 0.875rem;
58 --space-4: 1rem;
59 --space-5: 1.25rem;
60 --space-6: 1.5rem;
61 --space-8: 2rem;
62 --space-10: 2.5rem;
63 --space-12: 3rem;
64 --space-16: 4rem;
65 --space-20: 5rem;
66 --space-24: 6rem;
67 --space-32: 8rem;
68
69 /* Border radius tokens */
70 --radius-none: 0;
71 --radius-sm: 0.125rem;
72 --radius-base: 0.25rem;
73 --radius-md: 0.375rem;
74 --radius-lg: 0.5rem;
75 --radius-xl: 0.75rem;
76 --radius-2xl: 1rem;
77 --radius-3xl: 1.5rem;
78 --radius-full: 9999px;
79
80 /* Shadow tokens */
81 --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.05);
82 --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
83 --shadow-base: 0 4px 6px rgba(0, 0, 0, 0.07), 0 2px 4px rgba(0, 0, 0, 0.06);
84 --shadow-md: 0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05);
85 --shadow-lg: 0 20px 25px rgba(0, 0, 0, 0.1), 0 10px 10px rgba(0, 0, 0, 0.04);
86 --shadow-xl: 0 25px 50px rgba(0, 0, 0, 0.15);
87 --shadow-inner: inset 0 2px 4px rgba(0, 0, 0, 0.06);
88}
89
90/* Component-specific token usage */
91.button {
92 font-family: var(--font-family-sans);
93 font-weight: var(--font-weight-medium);
94 font-size: var(--font-size-sm);
95 line-height: var(--line-height-tight);
96 padding: var(--space-2) var(--space-4);
97 border-radius: var(--radius-md);
98 box-shadow: var(--shadow-sm);
99 background: var(--color-primary);
100 color: white;
101 border: 1px solid var(--color-primary);
102 transition: all 0.15s ease;
103}
104
105.button:hover {
106 background: var(--color-primary-hover);
107 border-color: var(--color-primary-hover);
108 box-shadow: var(--shadow-md);
109}Component State Management:
1/* State-driven component styling */
2.component {
3 /* State variables */
4 --is-loading: 0;
5 --is-disabled: 0;
6 --is-focused: 0;
7 --is-hovered: 0;
8 --is-active: 0;
9
10 /* Computed styles based on state */
11 --opacity: calc(1 - var(--is-disabled) * 0.5);
12 --cursor: var(--is-disabled) 'not-allowed', var(--is-loading) 'wait', 'pointer';
13 --scale: calc(1 + var(--is-hovered) * 0.05 - var(--is-active) * 0.05);
14
15 opacity: var(--opacity);
16 transform: scale(var(--scale));
17 cursor: var(--cursor);
18 transition: all 0.2s ease;
19}
20
21.component:hover {
22 --is-hovered: 1;
23}
24
25.component:active {
26 --is-active: 1;
27}
28
29.component:focus {
30 --is-focused: 1;
31 box-shadow: 0 0 0 3px rgba(var(--color-primary-rgb), 0.2);
32}
33
34.component[disabled] {
35 --is-disabled: 1;
36}
37
38.component[aria-busy="true"] {
39 --is-loading: 1;
40}
41
42/* Loading state with custom properties */
43.component[aria-busy="true"]::after {
44 content: '';
45 position: absolute;
46 inset: 0;
47 background: linear-gradient(
48 90deg,
49 transparent,
50 rgba(255, 255, 255, var(--is-loading)),
51 transparent
52 );
53 animation: shimmer calc(1.5s / var(--is-loading, 1)) infinite;
54}Responsive Component Architecture:
1/* Container query-inspired responsive variables */
2.responsive-component {
3 /* Breakpoint flags */
4 --is-mobile: 0;
5 --is-tablet: 0;
6 --is-desktop: 0;
7
8 /* Size-dependent values */
9 --padding: calc(
10 var(--is-mobile) * var(--space-4) +
11 var(--is-tablet) * var(--space-6) +
12 var(--is-desktop) * var(--space-8)
13 );
14
15 --font-size: calc(
16 var(--is-mobile) * var(--font-size-sm) +
17 var(--is-tablet) * var(--font-size-base) +
18 var(--is-desktop) * var(--font-size-lg)
19 );
20
21 --columns: calc(
22 var(--is-mobile) * 1 +
23 var(--is-tablet) * 2 +
24 var(--is-desktop) * 3
25 );
26
27 padding: var(--padding);
28 font-size: var(--font-size);
29 display: grid;
30 grid-template-columns: repeat(var(--columns), 1fr);
31 gap: var(--space-4);
32}
33
34@media (max-width: 768px) {
35 .responsive-component {
36 --is-mobile: 1;
37 }
38}
39
40@media (min-width: 769px) and (max-width: 1024px) {
41 .responsive-component {
42 --is-tablet: 1;
43 }
44}
45
46@media (min-width: 1025px) {
47 .responsive-component {
48 --is-desktop: 1;
49 }
50}
51
52/* Dynamic grid with custom properties */
53.dynamic-grid {
54 --min-item-size: 200px;
55 --max-item-size: 300px;
56 --gap: var(--space-4);
57 --container-padding: var(--space-6);
58 --available-space: calc(100vw - 2 * var(--container-padding));
59
60 --items-per-row: max(1, floor(var(--available-space) / var(--min-item-size)));
61 --item-size: min(
62 var(--max-item-size),
63 calc((var(--available-space) - (var(--items-per-row) - 1) * var(--gap)) / var(--items-per-row))
64 );
65
66 display: grid;
67 grid-template-columns: repeat(auto-fill, minmax(var(--item-size), 1fr));
68 gap: var(--gap);
69 padding: 0 var(--container-padding);
70}JavaScript Integration:
1/* CSS variables controlled by JavaScript */
2.js-controlled {
3 --mouse-x: 50%;
4 --mouse-y: 50%;
5 --scroll-progress: 0;
6 --time: 0;
7 --user-preference: 1;
8
9 /* Mouse-following gradient */
10 background: radial-gradient(
11 circle at var(--mouse-x) var(--mouse-y),
12 rgba(59, 130, 246, 0.2) 0%,
13 transparent 50%
14 );
15
16 /* Scroll-driven animations */
17 transform: translateY(calc(var(--scroll-progress) * -20px));
18 opacity: calc(1 - var(--scroll-progress) * 0.5);
19
20 /* Time-based animations */
21 filter: hue-rotate(calc(var(--time) * 1deg));
22
23 /* User preference scaling */
24 font-size: calc(1rem * var(--user-preference));
25}
26
27/* Performance-optimized updates */
28.perf-optimized {
29 --will-change: 'auto';
30 will-change: var(--will-change);
31}
32
33.perf-optimized.animating {
34 --will-change: 'transform, opacity';
35}
36
37/* Debugging custom properties */
38.debug-properties {
39 --debug-mode: 0;
40}
41
42.debug-properties::before {
43 content: 'Debug: ' var(--debug-info, 'off');
44 position: fixed;
45 top: 10px;
46 left: 10px;
47 background: #000;
48 color: #fff;
49 padding: 4px 8px;
50 font-size: 12px;
51 border-radius: 4px;
52 z-index: 9999;
53 opacity: var(--debug-mode);
54 pointer-events: none;
55}
56
57/* Environment-based styling */
58@media (prefers-reduced-motion: reduce) {
59 :root {
60 --animation-duration-multiplier: 0.01;
61 --transition-duration-multiplier: 0.01;
62 }
63}
64
65@media (prefers-contrast: high) {
66 :root {
67 --border-width-multiplier: 2;
68 --shadow-opacity-multiplier: 0.3;
69 }
70}
71
72.adaptive-component {
73 border-width: calc(1px * var(--border-width-multiplier, 1));
74 animation-duration: calc(1s * var(--animation-duration-multiplier, 1));
75 transition-duration: calc(0.3s * var(--transition-duration-multiplier, 1));
76}A comprehensive demonstration of CSS custom properties creating a dynamic theme system with light/dark modes, brand variations, and responsive design.
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 Variables & Custom Properties Mastery</title>
7 <style>
8 /* Design Token System */
9 :root {
10 /* Color palette - Light theme */
11 --color-primary-50: #eff6ff;
12 --color-primary-100: #dbeafe;
13 --color-primary-200: #bfdbfe;
14 --color-primary-300: #93c5fd;
15 --color-primary-400: #60a5fa;
16 --color-primary-500: #3b82f6;
17 --color-primary-600: #2563eb;
18 --color-primary-700: #1d4ed8;
19 --color-primary-800: #1e40af;
20 --color-primary-900: #1e3a8a;
21
22 /* Semantic color assignments */
23 --theme-bg-primary: #ffffff;
24 --theme-bg-secondary: #f8fafc;
25 --theme-bg-tertiary: #f1f5f9;
26 --theme-text-primary: #0f172a;
27 --theme-text-secondary: #475569;
28 --theme-text-tertiary: #64748b;
29 --theme-border: #e2e8f0;
30 --theme-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
31 --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
32
33 /* Brand colors */
34 --brand-primary: var(--color-primary-500);
35 --brand-primary-hover: var(--color-primary-600);
36 --brand-primary-light: var(--color-primary-50);
37 --brand-gradient: linear-gradient(135deg, var(--color-primary-500) 0%, var(--color-primary-700) 100%);
38
39 /* Typography system */
40 --font-family-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
41 --font-weight-normal: 400;
42 --font-weight-medium: 500;
43 --font-weight-semibold: 600;
44 --font-weight-bold: 700;
45
46 /* Responsive font sizes */
47 --font-size-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
48 --font-size-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
49 --font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
50 --font-size-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
51 --font-size-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
52 --font-size-2xl: clamp(1.5rem, 1.3rem + 1vw, 2rem);
53 --font-size-3xl: clamp(1.875rem, 1.5rem + 1.875vw, 3rem);
54
55 /* Spacing system using custom properties */
56 --space-unit: 1rem;
57 --space-ratio: 1.618; /* Golden ratio */
58 --space-xs: calc(var(--space-unit) / (var(--space-ratio) * var(--space-ratio)));
59 --space-sm: calc(var(--space-unit) / var(--space-ratio));
60 --space-md: var(--space-unit);
61 --space-lg: calc(var(--space-unit) * var(--space-ratio));
62 --space-xl: calc(var(--space-unit) * var(--space-ratio) * var(--space-ratio));
63 --space-2xl: calc(var(--space-unit) * var(--space-ratio) * var(--space-ratio) * var(--space-ratio));
64
65 /* Layout variables */
66 --container-max-width: min(90vw, 1200px);
67 --container-padding: clamp(1rem, 5vw, 3rem);
68 --header-height: 4rem;
69 --sidebar-width: 16rem;
70 --border-radius: 0.75rem;
71
72 /* Animation variables */
73 --animation-speed: 1;
74 --transition-duration: calc(0.3s / var(--animation-speed));
75 --transition-curve: cubic-bezier(0.4, 0, 0.2, 1);
76
77 /* Component state flags */
78 --is-dark-mode: 0;
79 --is-high-contrast: 0;
80 --is-reduced-motion: 0;
81 }
82
83 /* Dark theme overrides */
84 [data-theme="dark"] {
85 --theme-bg-primary: #0f172a;
86 --theme-bg-secondary: #1e293b;
87 --theme-bg-tertiary: #334155;
88 --theme-text-primary: #f8fafc;
89 --theme-text-secondary: #e2e8f0;
90 --theme-text-tertiary: #cbd5e1;
91 --theme-border: #475569;
92 --theme-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
93 --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3);
94
95 --brand-primary: var(--color-primary-400);
96 --brand-primary-hover: var(--color-primary-300);
97 --brand-primary-light: var(--color-primary-900);
98 --brand-gradient: linear-gradient(135deg, var(--color-primary-400) 0%, var(--color-primary-600) 100%);
99
100 --is-dark-mode: 1;
101 }
102
103 /* System preference detection */
104 @media (prefers-color-scheme: dark) {
105 :root:not([data-theme="light"]) {
106 --theme-bg-primary: #0f172a;
107 --theme-bg-secondary: #1e293b;
108 --theme-bg-tertiary: #334155;
109 --theme-text-primary: #f8fafc;
110 --theme-text-secondary: #e2e8f0;
111 --theme-text-tertiary: #cbd5e1;
112 --theme-border: #475569;
113 --theme-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
114 --theme-shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.3);
115 --brand-primary: var(--color-primary-400);
116 --is-dark-mode: 1;
117 }
118 }
119
120 /* Accessibility preference overrides */
121 @media (prefers-reduced-motion: reduce) {
122 :root {
123 --animation-speed: 0.01;
124 --transition-duration: 0.01ms;
125 --is-reduced-motion: 1;
126 }
127 }
128
129 @media (prefers-contrast: high) {
130 :root {
131 --is-high-contrast: 1;
132 --theme-border: #000000;
133 }
134 }
135
136 /* Brand theme variations */
137 .theme-blue {
138 --color-primary-500: #3b82f6;
139 --color-primary-600: #2563eb;
140 --color-primary-700: #1d4ed8;
141 --brand-primary: var(--color-primary-500);
142 }
143
144 .theme-green {
145 --color-primary-500: #10b981;
146 --color-primary-600: #059669;
147 --color-primary-700: #047857;
148 --brand-primary: var(--color-primary-500);
149 }
150
151 .theme-purple {
152 --color-primary-500: #8b5cf6;
153 --color-primary-600: #7c3aed;
154 --color-primary-700: #6d28d9;
155 --brand-primary: var(--color-primary-500);
156 }
157
158 .theme-orange {
159 --color-primary-500: #f97316;
160 --color-primary-600: #ea580c;
161 --color-primary-700: #c2410c;
162 --brand-primary: var(--color-primary-500);
163 }
164
165 /* Base styles */
166 * {
167 margin: 0;
168 padding: 0;
169 box-sizing: border-box;
170 }
171
172 body {
173 font-family: var(--font-family-sans);
174 font-size: var(--font-size-base);
175 font-weight: var(--font-weight-normal);
176 line-height: 1.6;
177 color: var(--theme-text-primary);
178 background: var(--theme-bg-primary);
179 transition: background var(--transition-duration) var(--transition-curve),
180 color var(--transition-duration) var(--transition-curve);
181 }
182
183 .container {
184 max-width: var(--container-max-width);
185 margin: 0 auto;
186 padding: 0 var(--container-padding);
187 }
188
189 /* Header with theme controls */
190 .header {
191 background: var(--theme-bg-secondary);
192 border-bottom: 1px solid var(--theme-border);
193 padding: var(--space-md) 0;
194 position: sticky;
195 top: 0;
196 z-index: 1000;
197 backdrop-filter: blur(8px);
198 }
199
200 .nav {
201 display: flex;
202 justify-content: space-between;
203 align-items: center;
204 }
205
206 .nav-brand {
207 font-size: var(--font-size-xl);
208 font-weight: var(--font-weight-bold);
209 color: var(--brand-primary);
210 text-decoration: none;
211 display: flex;
212 align-items: center;
213 gap: var(--space-sm);
214 }
215
216 .nav-brand::before {
217 content: '🎨';
218 font-size: 1.5rem;
219 }
220
221 .theme-controls {
222 display: flex;
223 gap: var(--space-sm);
224 align-items: center;
225 }
226
227 /* Button component system */
228 .btn {
229 --btn-padding-x: var(--space-md);
230 --btn-padding-y: var(--space-sm);
231 --btn-font-size: var(--font-size-sm);
232 --btn-font-weight: var(--font-weight-medium);
233 --btn-border-radius: var(--border-radius);
234 --btn-transition: all var(--transition-duration) var(--transition-curve);
235
236 /* Primary variant (default) */
237 --btn-bg: var(--brand-primary);
238 --btn-color: white;
239 --btn-border: var(--brand-primary);
240 --btn-hover-bg: var(--brand-primary-hover);
241 --btn-hover-border: var(--brand-primary-hover);
242 --btn-hover-transform: translateY(-2px);
243 --btn-hover-shadow: var(--theme-shadow-lg);
244
245 display: inline-flex;
246 align-items: center;
247 justify-content: center;
248 padding: var(--btn-padding-y) var(--btn-padding-x);
249 font-size: var(--btn-font-size);
250 font-weight: var(--btn-font-weight);
251 text-decoration: none;
252 background: var(--btn-bg);
253 color: var(--btn-color);
254 border: 1px solid var(--btn-border);
255 border-radius: var(--btn-border-radius);
256 cursor: pointer;
257 transition: var(--btn-transition);
258 position: relative;
259 overflow: hidden;
260 }
261
262 .btn::before {
263 content: '';
264 position: absolute;
265 top: 50%;
266 left: 50%;
267 width: 0;
268 height: 0;
269 background: rgba(255, 255, 255, 0.2);
270 border-radius: 50%;
271 transform: translate(-50%, -50%);
272 transition: width 0.3s ease, height 0.3s ease;
273 }
274
275 .btn:hover {
276 background: var(--btn-hover-bg);
277 border-color: var(--btn-hover-border);
278 transform: var(--btn-hover-transform);
279 box-shadow: var(--btn-hover-shadow);
280 }
281
282 .btn:hover::before {
283 width: 200px;
284 height: 200px;
285 }
286
287 .btn:active {
288 transform: translateY(0);
289 }
290
291 /* Button variants */
292 .btn.secondary {
293 --btn-bg: var(--theme-bg-secondary);
294 --btn-color: var(--theme-text-primary);
295 --btn-border: var(--theme-border);
296 --btn-hover-bg: var(--theme-bg-tertiary);
297 }
298
299 .btn.outline {
300 --btn-bg: transparent;
301 --btn-color: var(--brand-primary);
302 --btn-border: var(--brand-primary);
303 --btn-hover-bg: var(--brand-primary);
304 --btn-hover-color: white;
305 }
306
307 .btn.ghost {
308 --btn-bg: transparent;
309 --btn-color: var(--theme-text-secondary);
310 --btn-border: transparent;
311 --btn-hover-bg: var(--theme-bg-secondary);
312 }
313
314 /* Button sizes */
315 .btn.sm {
316 --btn-padding-x: var(--space-sm);
317 --btn-padding-y: var(--space-xs);
318 --btn-font-size: var(--font-size-xs);
319 }
320
321 .btn.lg {
322 --btn-padding-x: var(--space-lg);
323 --btn-padding-y: var(--space-md);
324 --btn-font-size: var(--font-size-lg);
325 }
326
327 /* Hero section */
328 .hero {
329 background: var(--brand-gradient);
330 color: white;
331 padding: var(--space-2xl) 0;
332 text-align: center;
333 position: relative;
334 overflow: hidden;
335 }
336
337 .hero::before {
338 content: '';
339 position: absolute;
340 top: -50%;
341 right: -50%;
342 width: 200%;
343 height: 200%;
344 background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 50%);
345 animation: rotate calc(20s / var(--animation-speed)) linear infinite;
346 }
347
348 @keyframes rotate {
349 to { transform: rotate(360deg); }
350 }
351
352 .hero-content {
353 position: relative;
354 z-index: 2;
355 }
356
357 .hero h1 {
358 font-size: var(--font-size-3xl);
359 font-weight: var(--font-weight-bold);
360 margin-bottom: var(--space-md);
361 }
362
363 .hero p {
364 font-size: var(--font-size-lg);
365 opacity: 0.9;
366 margin-bottom: var(--space-xl);
367 max-width: 600px;
368 margin-left: auto;
369 margin-right: auto;
370 }
371
372 /* Section styling */
373 .section {
374 padding: var(--space-2xl) 0;
375 }
376
377 .section:nth-child(even) {
378 background: var(--theme-bg-secondary);
379 }
380
381 .section-title {
382 font-size: var(--font-size-2xl);
383 font-weight: var(--font-weight-bold);
384 text-align: center;
385 margin-bottom: var(--space-xl);
386 color: var(--theme-text-primary);
387 position: relative;
388 }
389
390 .section-title::after {
391 content: '';
392 position: absolute;
393 bottom: calc(0px - var(--space-sm));
394 left: 50%;
395 width: 60px;
396 height: 4px;
397 background: var(--brand-primary);
398 border-radius: 2px;
399 transform: translateX(-50%);
400 }
401
402 /* Card system */
403 .card-grid {
404 display: grid;
405 grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
406 gap: var(--space-lg);
407 margin: var(--space-xl) 0;
408 }
409
410 .card {
411 --card-padding: var(--space-lg);
412 --card-bg: var(--theme-bg-primary);
413 --card-border: var(--theme-border);
414 --card-shadow: var(--theme-shadow);
415 --card-hover-shadow: var(--theme-shadow-lg);
416 --card-hover-transform: translateY(-4px) scale(1.02);
417
418 background: var(--card-bg);
419 border: 1px solid var(--card-border);
420 border-radius: var(--border-radius);
421 padding: var(--card-padding);
422 box-shadow: var(--card-shadow);
423 transition: all var(--transition-duration) var(--transition-curve);
424 position: relative;
425 overflow: hidden;
426 }
427
428 .card::before {
429 content: '';
430 position: absolute;
431 top: 0;
432 left: -100%;
433 width: 100%;
434 height: 100%;
435 background: linear-gradient(
436 90deg,
437 transparent,
438 rgba(var(--brand-primary), 0.1),
439 transparent
440 );
441 transition: left 0.5s ease;
442 }
443
444 .card:hover {
445 transform: var(--card-hover-transform);
446 box-shadow: var(--card-hover-shadow);
447 }
448
449 .card:hover::before {
450 left: 100%;
451 }
452
453 .card-header {
454 display: flex;
455 align-items: center;
456 gap: var(--space-md);
457 margin-bottom: var(--space-md);
458 }
459
460 .card-icon {
461 --icon-size: 3rem;
462 --icon-bg: var(--brand-primary);
463
464 width: var(--icon-size);
465 height: var(--icon-size);
466 background: var(--icon-bg);
467 border-radius: var(--border-radius);
468 display: flex;
469 align-items: center;
470 justify-content: center;
471 font-size: 1.5rem;
472 color: white;
473 }
474
475 .card h3 {
476 font-size: var(--font-size-xl);
477 font-weight: var(--font-weight-semibold);
478 color: var(--theme-text-primary);
479 }
480
481 .card p {
482 color: var(--theme-text-secondary);
483 line-height: 1.6;
484 }
485
486 /* Variable showcase */
487 .variable-demo {
488 background: var(--theme-bg-tertiary);
489 border-radius: var(--border-radius);
490 padding: var(--space-lg);
491 margin: var(--space-lg) 0;
492 }
493
494 .variable-grid {
495 display: grid;
496 grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
497 gap: var(--space-md);
498 margin: var(--space-lg) 0;
499 }
500
501 .variable-item {
502 background: var(--theme-bg-primary);
503 border: 1px solid var(--theme-border);
504 border-radius: calc(var(--border-radius) / 2);
505 padding: var(--space-md);
506 text-align: center;
507 transition: all var(--transition-duration) var(--transition-curve);
508 }
509
510 .variable-item:hover {
511 transform: scale(1.05);
512 border-color: var(--brand-primary);
513 }
514
515 .variable-name {
516 font-family: monospace;
517 font-size: var(--font-size-sm);
518 color: var(--brand-primary);
519 font-weight: var(--font-weight-medium);
520 margin-bottom: var(--space-xs);
521 }
522
523 .variable-value {
524 font-size: var(--font-size-xs);
525 color: var(--theme-text-tertiary);
526 }
527
528 /* Responsive demonstration */
529 .responsive-demo {
530 --demo-columns: 1;
531 --demo-gap: var(--space-md);
532 --demo-padding: var(--space-lg);
533
534 display: grid;
535 grid-template-columns: repeat(var(--demo-columns), 1fr);
536 gap: var(--demo-gap);
537 padding: var(--demo-padding);
538 background: var(--brand-gradient);
539 border-radius: var(--border-radius);
540 margin: var(--space-lg) 0;
541 }
542
543 @media (min-width: 640px) {
544 .responsive-demo {
545 --demo-columns: 2;
546 }
547 }
548
549 @media (min-width: 1024px) {
550 .responsive-demo {
551 --demo-columns: 3;
552 --demo-gap: var(--space-lg);
553 --demo-padding: var(--space-xl);
554 }
555 }
556
557 .responsive-item {
558 background: rgba(255, 255, 255, 0.1);
559 padding: var(--space-md);
560 border-radius: calc(var(--border-radius) / 2);
561 color: white;
562 text-align: center;
563 backdrop-filter: blur(10px);
564 }
565
566 /* Progress bar using custom properties */
567 .progress-container {
568 --progress: 0%;
569 --progress-height: 8px;
570 --progress-bg: var(--theme-bg-tertiary);
571 --progress-color: var(--brand-primary);
572
573 width: 100%;
574 height: var(--progress-height);
575 background: var(--progress-bg);
576 border-radius: calc(var(--progress-height) / 2);
577 overflow: hidden;
578 margin: var(--space-md) 0;
579 }
580
581 .progress-bar {
582 width: var(--progress);
583 height: 100%;
584 background: var(--progress-color);
585 transition: width var(--transition-duration) var(--transition-curve);
586 }
587
588 /* Animation showcase */
589 .animation-demo {
590 display: grid;
591 grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
592 gap: var(--space-md);
593 margin: var(--space-lg) 0;
594 }
595
596 .animated-box {
597 --box-size: 80px;
598 --animation-duration: calc(2s / var(--animation-speed));
599 --animation-delay: 0s;
600
601 width: var(--box-size);
602 height: var(--box-size);
603 background: var(--brand-primary);
604 border-radius: var(--border-radius);
605 margin: 0 auto;
606 animation: bounce var(--animation-duration) ease-in-out var(--animation-delay) infinite;
607 }
608
609 .animated-box:nth-child(1) { --animation-delay: 0s; }
610 .animated-box:nth-child(2) { --animation-delay: 0.2s; }
611 .animated-box:nth-child(3) { --animation-delay: 0.4s; }
612 .animated-box:nth-child(4) { --animation-delay: 0.6s; }
613 .animated-box:nth-child(5) { --animation-delay: 0.8s; }
614
615 @keyframes bounce {
616 0%, 100% { transform: translateY(0); }
617 50% { transform: translateY(-20px); }
618 }
619
620 /* Mobile optimizations */
621 @media (max-width: 768px) {
622 :root {
623 --container-padding: var(--space-md);
624 --space-2xl: var(--space-xl);
625 }
626
627 .hero {
628 padding: var(--space-xl) 0;
629 }
630
631 .theme-controls {
632 flex-wrap: wrap;
633 gap: var(--space-xs);
634 }
635
636 .btn.mobile-full {
637 width: 100%;
638 }
639 }
640
641 /* High contrast mode adjustments */
642 @media (prefers-contrast: high) {
643 .card {
644 border-width: 2px;
645 }
646
647 .btn {
648 border-width: 2px;
649 font-weight: var(--font-weight-bold);
650 }
651 }
652 </style>
653</head>
654<body class="theme-blue">
655 <!-- Header with theme controls -->
656 <header class="header">
657 <div class="container">
658 <nav class="nav">
659 <a href="#" class="nav-brand">Variable Master</a>
660
661 <div class="theme-controls">
662 <button class="btn sm secondary" onclick="toggleTheme()">🌙 Toggle Theme</button>
663 <button class="btn sm outline" onclick="changeTheme('theme-blue')">Blue</button>
664 <button class="btn sm outline" onclick="changeTheme('theme-green')">Green</button>
665 <button class="btn sm outline" onclick="changeTheme('theme-purple')">Purple</button>
666 <button class="btn sm outline" onclick="changeTheme('theme-orange')">Orange</button>
667 </div>
668 </nav>
669 </div>
670 </header>
671
672 <!-- Hero section -->
673 <section class="hero">
674 <div class="container">
675 <div class="hero-content">
676 <h1>CSS Variables & Custom Properties</h1>
677 <p>Experience dynamic theming, responsive design, and maintainable CSS through the power of custom properties.</p>
678 <button class="btn lg" onclick="scrollToDemo()">Explore Variables</button>
679 </div>
680 </div>
681 </section>
682
683 <!-- Variables showcase -->
684 <section class="section">
685 <div class="container">
686 <h2 class="section-title">🎨 Design Token System</h2>
687
688 <div class="variable-demo">
689 <h3 style="margin-bottom: var(--space-md);">Live CSS Variables</h3>
690 <div class="variable-grid">
691 <div class="variable-item">
692 <div class="variable-name">--brand-primary</div>
693 <div class="variable-value" id="brand-primary-value">#3b82f6</div>
694 <div style="width: 100%; height: 20px; background: var(--brand-primary); border-radius: 4px; margin-top: var(--space-xs);"></div>
695 </div>
696
697 <div class="variable-item">
698 <div class="variable-name">--space-lg</div>
699 <div class="variable-value" id="space-lg-value">2.618rem</div>
700 <div style="width: var(--space-lg); height: 20px; background: var(--brand-primary); border-radius: 4px; margin: var(--space-xs) auto 0;"></div>
701 </div>
702
703 <div class="variable-item">
704 <div class="variable-name">--font-size-xl</div>
705 <div class="variable-value" id="font-size-xl-value">1.25rem</div>
706 <div style="font-size: var(--font-size-xl); color: var(--brand-primary); font-weight: var(--font-weight-bold); margin-top: var(--space-xs);">Sample</div>
707 </div>
708
709 <div class="variable-item">
710 <div class="variable-name">--border-radius</div>
711 <div class="variable-value" id="border-radius-value">0.75rem</div>
712 <div style="width: 60px; height: 60px; background: var(--brand-primary); border-radius: var(--border-radius); margin: var(--space-xs) auto 0;"></div>
713 </div>
714
715 <div class="variable-item">
716 <div class="variable-name">--theme-shadow</div>
717 <div class="variable-value" id="theme-shadow-value">0 1px 3px rgba(0,0,0,0.1)</div>
718 <div style="width: 60px; height: 60px; background: var(--theme-bg-primary); box-shadow: var(--theme-shadow); border-radius: var(--border-radius); margin: var(--space-xs) auto 0;"></div>
719 </div>
720
721 <div class="variable-item">
722 <div class="variable-name">--transition-duration</div>
723 <div class="variable-value" id="transition-duration-value">0.3s</div>
724 <div style="width: 20px; height: 20px; background: var(--brand-primary); border-radius: 50%; margin: var(--space-xs) auto 0; transition: transform var(--transition-duration) ease; cursor: pointer;" onmouseover="this.style.transform='scale(1.5)'" onmouseout="this.style.transform='scale(1)'"></div>
725 </div>
726 </div>
727 </div>
728 </div>
729 </section>
730
731 <!-- Component variations -->
732 <section class="section">
733 <div class="container">
734 <h2 class="section-title">🧩 Component System</h2>
735
736 <div class="card-grid">
737 <div class="card">
738 <div class="card-header">
739 <div class="card-icon">📊</div>
740 <h3>Dynamic Theming</h3>
741 </div>
742 <p>CSS variables enable instant theme switching across all components while maintaining consistent design tokens and responsive behavior.</p>
743 </div>
744
745 <div class="card">
746 <div class="card-header">
747 <div class="card-icon">📐</div>
748 <h3>Calculated Values</h3>
749 </div>
750 <p>Use calc() with custom properties to create flexible layouts that respond to content and viewport changes dynamically.</p>
751 </div>
752
753 <div class="card">
754 <div class="card-header">
755 <div class="card-icon">🎛️</div>
756 <h3>Component Variants</h3>
757 </div>
758 <p>Create scalable component systems with size and style variations using custom property overrides and inheritance.</p>
759 </div>
760 </div>
761
762 <!-- Button showcase -->
763 <div style="text-align: center; margin-top: var(--space-xl);">
764 <h3 style="margin-bottom: var(--space-lg);">Button Variants</h3>
765 <div style="display: flex; flex-wrap: wrap; gap: var(--space-md); justify-content: center; margin-bottom: var(--space-lg);">
766 <button class="btn">Primary</button>
767 <button class="btn secondary">Secondary</button>
768 <button class="btn outline">Outline</button>
769 <button class="btn ghost">Ghost</button>
770 </div>
771 <div style="display: flex; flex-wrap: wrap; gap: var(--space-md); justify-content: center;">
772 <button class="btn sm">Small</button>
773 <button class="btn">Normal</button>
774 <button class="btn lg">Large</button>
775 </div>
776 </div>
777 </div>
778 </section>
779
780 <!-- Responsive demonstration -->
781 <section class="section">
782 <div class="container">
783 <h2 class="section-title">📱 Responsive Variables</h2>
784
785 <div class="responsive-demo">
786 <div class="responsive-item">
787 <h4>Mobile</h4>
788 <p>1 column layout</p>
789 </div>
790 <div class="responsive-item">
791 <h4>Tablet</h4>
792 <p>2 column layout</p>
793 </div>
794 <div class="responsive-item">
795 <h4>Desktop</h4>
796 <p>3 column layout</p>
797 </div>
798 <div class="responsive-item">
799 <h4>Variables</h4>
800 <p>Control everything</p>
801 </div>
802 <div class="responsive-item">
803 <h4>Flexible</h4>
804 <p>Adapts to screen</p>
805 </div>
806 <div class="responsive-item">
807 <h4>Maintainable</h4>
808 <p>Easy to modify</p>
809 </div>
810 </div>
811 </div>
812 </section>
813
814 <!-- Progress bars -->
815 <section class="section">
816 <div class="container">
817 <h2 class="section-title">📊 Dynamic Progress</h2>
818
819 <div style="background: var(--theme-bg-primary); padding: var(--space-lg); border-radius: var(--border-radius); border: 1px solid var(--theme-border);">
820 <h4 style="margin-bottom: var(--space-md);">CSS Variable Progress Bars</h4>
821
822 <div style="margin-bottom: var(--space-md);">
823 <label style="display: block; margin-bottom: var(--space-xs);">HTML: <span id="html-progress">85%</span></label>
824 <div class="progress-container" style="--progress: 85%;">
825 <div class="progress-bar"></div>
826 </div>
827 </div>
828
829 <div style="margin-bottom: var(--space-md);">
830 <label style="display: block; margin-bottom: var(--space-xs);">CSS: <span id="css-progress">92%</span></label>
831 <div class="progress-container" style="--progress: 92%; --progress-color: var(--color-primary-600);">
832 <div class="progress-bar"></div>
833 </div>
834 </div>
835
836 <div style="margin-bottom: var(--space-md);">
837 <label style="display: block; margin-bottom: var(--space-xs);">JavaScript: <span id="js-progress">78%</span></label>
838 <div class="progress-container" style="--progress: 78%; --progress-color: #f59e0b;">
839 <div class="progress-bar"></div>
840 </div>
841 </div>
842
843 <div style="margin-bottom: var(--space-md);">
844 <label style="display: block; margin-bottom: var(--space-xs);">React: <span id="react-progress">65%</span></label>
845 <div class="progress-container" style="--progress: 65%; --progress-color: #10b981;">
846 <div class="progress-bar"></div>
847 </div>
848 </div>
849 </div>
850 </div>
851 </section>
852
853 <!-- Animation showcase -->
854 <section class="section">
855 <div class="container">
856 <h2 class="section-title">🎬 Variable-Driven Animations</h2>
857
858 <div style="text-align: center; margin-bottom: var(--space-lg);">
859 <button class="btn" onclick="adjustAnimationSpeed(0.5)">0.5x Speed</button>
860 <button class="btn secondary" onclick="adjustAnimationSpeed(1)">1x Speed</button>
861 <button class="btn" onclick="adjustAnimationSpeed(2)">2x Speed</button>
862 </div>
863
864 <div class="animation-demo">
865 <div class="animated-box"></div>
866 <div class="animated-box"></div>
867 <div class="animated-box"></div>
868 <div class="animated-box"></div>
869 <div class="animated-box"></div>
870 </div>
871 </div>
872 </section>
873
874 <!-- Summary -->
875 <section class="section" style="text-align: center; background: var(--brand-gradient); color: white;">
876 <div class="container">
877 <h2 style="color: white; margin-bottom: var(--space-lg);">🎨 CSS Variables Mastery!</h2>
878 <p style="font-size: var(--font-size-lg); margin-bottom: var(--space-xl); opacity: 0.9;">
879 You've mastered the power of CSS custom properties for maintainable, dynamic styling!
880 </p>
881
882 <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: var(--space-md); margin: var(--space-xl) 0;">
883 <div style="background: rgba(255,255,255,0.1); padding: var(--space-lg); border-radius: var(--border-radius); backdrop-filter: blur(10px);">
884 <strong>✅ Design Tokens</strong><br>
885 <small>Scalable color, spacing, and typography systems</small>
886 </div>
887 <div style="background: rgba(255,255,255,0.1); padding: var(--space-lg); border-radius: var(--border-radius); backdrop-filter: blur(10px);">
888 <strong>✅ Dynamic Theming</strong><br>
889 <small>Light/dark modes and brand variations</small>
890 </div>
891 <div style="background: rgba(255,255,255,0.1); padding: var(--space-lg); border-radius: var(--border-radius); backdrop-filter: blur(10px);">
892 <strong>✅ Calculations</strong><br>
893 <small>Flexible layouts with calc() functions</small>
894 </div>
895 <div style="background: rgba(255,255,255,0.1); padding: var(--space-lg); border-radius: var(--border-radius); backdrop-filter: blur(10px);">
896 <strong>✅ Maintainable Code</strong><br>
897 <small>Component systems and responsive design</small>
898 </div>
899 </div>
900 </div>
901 </section>
902
903 <script>
904 // Theme management
905 let currentTheme = 'theme-blue';
906 let isDarkMode = false;
907
908 function toggleTheme() {
909 isDarkMode = !isDarkMode;
910 document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
911 updateVariableDisplay();
912 }
913
914 function changeTheme(theme) {
915 currentTheme = theme;
916 document.body.className = theme;
917 updateVariableDisplay();
918 }
919
920 function adjustAnimationSpeed(speed) {
921 document.documentElement.style.setProperty('--animation-speed', speed);
922 }
923
924 function updateVariableDisplay() {
925 // Get computed values of CSS variables
926 const root = document.documentElement;
927 const computedStyle = getComputedStyle(root);
928
929 // Update variable display values
930 const updates = [
931 { id: 'brand-primary-value', property: '--brand-primary' },
932 { id: 'space-lg-value', property: '--space-lg' },
933 { id: 'font-size-xl-value', property: '--font-size-xl' },
934 { id: 'border-radius-value', property: '--border-radius' },
935 { id: 'theme-shadow-value', property: '--theme-shadow' },
936 { id: 'transition-duration-value', property: '--transition-duration' }
937 ];
938
939 updates.forEach(update => {
940 const element = document.getElementById(update.id);
941 if (element) {
942 const value = computedStyle.getPropertyValue(update.property).trim();
943 element.textContent = value;
944 }
945 });
946 }
947
948 // Scroll to demo
949 function scrollToDemo() {
950 document.querySelector('.section').scrollIntoView({
951 behavior: 'smooth',
952 block: 'start'
953 });
954 }
955
956 // Animate progress bars on scroll
957 function animateProgress() {
958 const progressBars = document.querySelectorAll('.progress-container');
959 progressBars.forEach((container, index) => {
960 const rect = container.getBoundingClientRect();
961 if (rect.top < window.innerHeight && rect.bottom > 0) {
962 const currentProgress = container.style.getPropertyValue('--progress');
963 if (!currentProgress || currentProgress === '0%') {
964 setTimeout(() => {
965 const progressValue = container.getAttribute('data-progress') ||
966 ['85%', '92%', '78%', '65%'][index] || '50%';
967 container.style.setProperty('--progress', progressValue);
968 }, index * 200);
969 }
970 }
971 });
972 }
973
974 // Initialize
975 document.addEventListener('DOMContentLoaded', function() {
976 updateVariableDisplay();
977
978 // Add scroll listener for progress animation
979 window.addEventListener('scroll', animateProgress);
980 animateProgress(); // Initial check
981
982 // Demonstrate dynamic variable updates
983 let hue = 0;
984 setInterval(() => {
985 hue = (hue + 1) % 360;
986 document.documentElement.style.setProperty('--dynamic-hue', hue);
987 }, 100);
988
989 // Add interactive elements
990 document.querySelectorAll('.variable-item').forEach(item => {
991 item.addEventListener('click', function() {
992 this.style.transform = 'scale(0.95)';
993 setTimeout(() => {
994 this.style.transform = 'scale(1.05)';
995 setTimeout(() => {
996 this.style.transform = '';
997 }, 150);
998 }, 100);
999 });
1000 });
1001
1002 // Keyboard shortcuts
1003 document.addEventListener('keydown', function(e) {
1004 if (e.key === 'd' && e.ctrlKey) {
1005 e.preventDefault();
1006 toggleTheme();
1007 }
1008 if (e.key >= '1' && e.key <= '4' && e.altKey) {
1009 e.preventDefault();
1010 const themes = ['theme-blue', 'theme-green', 'theme-purple', 'theme-orange'];
1011 changeTheme(themes[e.key - 1]);
1012 }
1013 });
1014 });
1015
1016 // System theme detection
1017 const prefersDark = window.matchMedia('(prefers-color-scheme: dark)');
1018 prefersDark.addListener(function(e) {
1019 if (!document.documentElement.hasAttribute('data-theme')) {
1020 isDarkMode = e.matches;
1021 document.documentElement.setAttribute('data-theme', isDarkMode ? 'dark' : 'light');
1022 }
1023 });
1024
1025 // Initial system theme check
1026 if (prefersDark.matches) {
1027 isDarkMode = true;
1028 document.documentElement.setAttribute('data-theme', 'dark');
1029 }
1030 </script>
1031</body>
1032</html>This comprehensive CSS variables demonstration showcases the full power of custom properties:
🎨 Complete Design Token System:
🌙 Advanced Theming Architecture:
📐 Sophisticated Calculations:
🧩 Component System Excellence:
🎬 Interactive Demonstrations:
This example shows how CSS custom properties enable maintainable, scalable, and dynamic design systems that rival what's possible with preprocessors while providing runtime flexibility.
Outstanding work mastering CSS variables and custom properties! You now understand how to build maintainable, dynamic styling systems with design tokens, theming, and responsive calculations. Next, we'll explore "CSS Architecture & Organization" where you'll learn methodologies like BEM, component patterns, and scalable CSS structure for large projects. Get ready to architect professional CSS codebases!
Your progress is saved in this browser, on this device only.