Introduction
CSS custom properties, commonly called CSS variables, let you store a value once and reuse it throughout a stylesheet. Unlike preprocessor variables (such as those in Sass), custom properties are a native part of the CSS language, are resolved at runtime in the browser, can be updated dynamically with JavaScript, and cascade and inherit just like any other CSS property.
Cricket analogy: A CSS variable is like a team's official ball brand set once by the board and used across every match, but unlike a fixed pre-tour equipment list (Sass), it can be swapped live mid-match by the umpire (JavaScript) and still follows ground-specific rules (cascade and inheritance).
Syntax
:root {
--primary-color: #3b82f6;
--spacing-unit: 8px;
--font-stack: "Segoe UI", sans-serif;
}
.card {
color: var(--primary-color);
padding: calc(var(--spacing-unit) * 2);
font-family: var(--font-stack);
}
.card--danger {
--primary-color: #dc2626; /* overrides only within this scope */
}Explanation
Custom property names must start with two hyphens, like --primary-color, and are typically declared on :root so they are available globally, since :root has the highest specificity selector matching the document's root element. The var() function reads the value, and it accepts an optional second argument as a fallback, for example var(--gap, 16px), which is used if the variable is undefined. Because custom properties follow the cascade, they can be overridden at any selector scope, such as within a specific class, to create localized theme variations.
Cricket analogy: Declaring --primary-color on :root is like the ICC setting an official ball color for all Test matches at headquarters; var(--gap, 16px) is like a fallback fielding position used if the captain hasn't set one, and a specific team can still override the pitch color locally for a home ground.
Example
:root {
--gap: 16px;
--radius: 6px;
}
[data-theme="dark"] {
--bg-color: #1f2937;
--text-color: #f9fafb;
}
[data-theme="light"] {
--bg-color: #ffffff;
--text-color: #111827;
}
body {
background-color: var(--bg-color, #ffffff);
color: var(--text-color, #000000);
gap: var(--gap);
border-radius: var(--radius);
}Output
Depending on the data-theme attribute applied to the document, the body's background and text colors switch between dark and light palettes without duplicating any layout rules. If neither data-theme selector matches, the fallback values in var(--bg-color, #ffffff) apply instead, preventing the styles from breaking.
Cricket analogy: Switching data-theme between day and day-night matches changes the ball color and sightscreen without rewriting every fielding rule, and if neither condition is set, a fallback white ball keeps play from breaking, just like var(--bg-color, #ffffff) prevents undefined styling.
Key Takeaways
- Custom properties are declared with a double-hyphen prefix, e.g. --main-color, and read using var(--main-color).
- They cascade and inherit, so they can be scoped and overridden at any selector, not just :root.
- var() supports a fallback value as its second argument for graceful degradation.
- Unlike Sass variables, CSS custom properties can be changed live via JavaScript using element.style.setProperty().
Practice what you learned
1. How is a CSS custom property declared?
2. Which function is used to read the value of a custom property?
3. What is the purpose of the second argument in var(--gap, 16px)?
4. Where are custom properties commonly declared to make them globally accessible?
5. How do CSS custom properties differ from Sass/SCSS variables?
Was this page helpful?
You May Also Like
CSS Transitions and Animations
Understand how to animate CSS property changes smoothly using transitions and create complex motion with keyframe animations.
CSS Specificity and the Cascade
Learn how the browser decides which CSS rule wins when multiple selectors target the same element.
CSS Preprocessors (Sass/LESS)
Learn how Sass and LESS extend CSS with variables, nesting, mixins, and partials to write more maintainable stylesheets.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics