1. The Concept of Custom Properties
Custom Properties are user-defined entities that store a specific value for reuse throughout a document. They behave much like variables in programming, offering immense power for maintaining design consistency and enabling easy theming.
- Declaration: Custom properties must start with a double hyphen (
--). - Case-Sensitive: Custom properties are case-sensitive (e.g.,
--Coloris different from--color). - Inheritance: They participate in the Cascade and are inherited by child elements, which is a major advantage over preprocessor variables (like Sass).
2. Declaring and Using Custom Properties
A. Declaration
Custom properties are declared within a selector, just like any other CSS property. To make a property globally available, you declare it inside the :root pseudo-class (which targets the <html> element).
/* Declaring global variables inside the root element */
:root {
--primary-color: #007bff;
--secondary-color: #6c757d;
--spacing-unit: 1rem;
}
/* Declaring a local variable inside a component */
.card {
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
box-shadow: var(--card-shadow);
}
B. Usage with var()
To retrieve and use the stored value, you use the var() function.
/* Using the global variables */
.header {
background-color: var(--primary-color);
padding: var(--spacing-unit);
}
.button {
color: var(--secondary-color);
}
C. Fallback Values
The var() function can accept an optional fallback value as its second argument. This value is used if the custom property is not defined, which is excellent for robustness and backward compatibility.
/* If --accent-color is defined, use it. Otherwise, use red. */
.alert {
border-color: var(--accent-color, red);
}
3. Benefits and Use Cases
A. Theming
The most common use case is for theming. By changing just a few properties in the :root selector, you can instantly change the entire color scheme of your application (e.g., light mode to dark mode).
/* Default (Light) Theme */
:root {
--bg: white;
--text: black;
}
/* Dark Theme (applied via a class on the <body>) */
.dark-mode {
--bg: #222;
--text: white;
}
/* All elements respect the variables dynamically */
body {
background-color: var(--bg);
color: var(--text);
}
B. Calculations and Consistency
Custom properties can be used inside the calc() function (P2.2) and simplify complex, consistent measurements.
:root {
--gutter: 20px;
}
.column {
/* Using calc() for a dynamic width based on a fixed variable */
width: calc(50% - var(--gutter));
padding-left: var(--gutter);
}
4. Custom Properties vs. Preprocessor Variables (Sass/Less)
It’s important to know the key difference:
| Feature | CSS Custom Properties | Preprocessor Variables (e.g., $variable) |
| Scope | Dynamic and part of the CSS Cascade. Can be changed at runtime. | Static and compile-time only. Cannot be changed dynamically. |
| Access | Accessed using the var() function. | Directly referenced (e.g., $primary-color\). |
| JS Access | Can be read and written directly with JavaScript. | Inaccessible to JavaScript after compilation. |
This dynamic nature makes Custom Properties far superior for runtime changes like theming and state management.
