This is the second half of my CSS Variable post,
Using var()
The var() accesses custom property values (CSS variables). Its syntax is as follows:
var( <custom-property-name>, <fallback-value>? )
Basic Rules
The first parameter must be a CSS variable: Direct values, such as
var(20px), will result in an error, asvar()only accepts custom property names.var()cannot replace property names: In other words, you cannot write something likevar(--prop-name): 20px;becausevar()is limited to use in property values only.
.foo {
margin: var(20px); /* Error, 20px is not a CSS variable */
--prop-name: margin-top;
var(--prop-name): 20px; /* Error, cannot use var() this way */
}
Detailed Behaviors
var(--b, fallback_value)Fallbacks: The second parameter acts as a fallback value, used when--bis invalid.var(--c,)Syntax with an Empty Fallback: If the fallback value is left empty, the syntax remains valid and will default to an empty value if--cis invalid.Multiple Comma: In
var(--d, var(--e), var(--f), var(--g)), everything after the first comma is treated as fallback, so if--dis invalid, thevar()expression evaluatesvar(--e), var(--f), var(--g)as one fallback, to determine the result.var()as a Complete CSS Token: The function acts as a complete CSS token, like20pxwould. Therefore,var(--size)var(--unit)will not create20pxand is considered invalid.Using
initialwith CSS Variables: Assigninginitialto a CSS variable means it is invalid. To displayinitialas a value, it must be placed in the fallback.url()andvar()Usage: Sinceurl()is treated as a complete CSS token, you need to define the fullurl()within the variable.
:root {
/* 1. */
margin: var(--b, 20px); /* Uses 20px if --b is invalid */
/* 2. */
padding: var(--c,) 20px; /* Falls back to 20px if --c is invalid */
/* 3. */
font-family: var(--fonts, "lucida grande", tahoma, Arial); /* Uses fallback font stack if --fonts is invalid */
/* 4. */
--text-size: 12;
--text-unit: px;
font-size: var(--text-size)var(--text-unit); /* Invalid, as it does not resolve to 12px */
/* 5. */
--initialized: initial;
background: var(--initialized, initial); /* Results in background: initial */
/* 6. */
--invalid-url: "https://useme.medium.com";
background: url(var(--invalid-url)); /* Invalid, as url() cannot parse var() */
--valid-url: url(https://useme.medium.com);
background: var(--valid-url); /* Correct usage */
}
Variable Resolution and Scope
CSS variables, like other CSS properties, follow CSS-specific rules for scope and specificity. Understanding how these factors affect CSS variables allows for more precise control.
Global and Scoped Variables:
Variables defined in :root are applied globally, while those defined in selectors have a more limited scope.
:root {
--main-color: blue; /* Globally applied */
}
.container {
--main-color: green; /* Scoped, applies only within .container */
}
Priority by Specificity:
Higher specificity will override lower specificity for CSS variables.
:root {
--main-color: blue;
}
.section {
--main-color: green; /* Overrides :root definition */
}
.section p {
color: var(--main-color); /* Shows green */
}
p {
color: var(--main-color); /* Shows blue */
}
<div class="section">
<p>This text will use .section's --main-color and be green.</p>
</div>
<p>This text will use :root's --main-color and be blue.</p>
Calculating Values Based on Specificity Order:
Like CSS properties, variables are resolved based on specificity in ascending order.
:root {
--red: 255;
--green: 255;
--blue: 255;
--background: rgb(var(--red), var(--green), var(--blue));
}
.box {
--green: 0;
background: var(--background);
}
In this example, the background color of .box remains white, as --background was resolved to rgb(255, 255, 255) before .box redefined --green: 0.
Reevaluating Variables with Pseudo-Classes:
Variables change based on pseudo-class states when defined at the same level.
:root {
--red: 255;
--green: 255;
--blue: 255;
}
.box {
--background: rgb(var(--red), var(--green), var(--blue));
background: var(--background);
}
.box:hover {
--green: 0; /* Changes background color on hover */
}
Next, let’s explore some advanced use cases for CSS variables:
Usage Example A: Animations
CSS variables cannot be directly animated because the browser cannot infer the data type. To resolve this, use @property to define the variable's type and initial value, enabling the browser to understand how to animate the variable.
@property --green {
syntax: "<number>";
initial-value: 255;
inherits: false;
}
.section {
padding: 5em;
background: rgb(50, var(--green), 50);
transition: --green 0.5s;
}
.section:hover {
--green: 50;
}
<div class="section">
<p>Hover to see CSS variables + animation in action.</p>
</div>
In this example, @property is used to declare --green as a <number> type with an initial value of 255. When hovering over .section, --green changes to 50, creating a smooth color transition effect.
technique to simplify variable settings. Here’s the code, followed by an explanation of how it works:
:root {
--ON: initial; /* Default state variable to use for switching colors */
--OFF: ; /* Alternative state variable for switching colors */
/* Set default color variables based on light mode */
--light: var(--ON);
--dark: var(--OFF);
/* Define custom properties for colors used in light and dark modes */
--background-color: var(--light, #fbfbfb) var(--dark, #121212);
--container-background-color: var(--light, #ebebeb) var(--dark, #555555);
--headline-color: var(--light, #0077ee) var(--dark, #94b2e6);
--text-color: var(--light, #333333) var(--dark, #e0e0e0);
}
:root:has(input[type="checkbox"]:checked) {
--light: var(--OFF);
--dark: var(--ON);
}
The key here is in the line --background-color: var(--light, #fbfbfb) var(--dark, #121212);. Here, the background color depends on the values of --light and --dark, effectively simulating an if/else in the property.
How does it work? Initially, --light: var(--ON); and --ON: initial; make --ON an invalid state. Meanwhile, --OFF is set as an empty string. When applied to var(--light, #fbfbfb) var(--dark, #121212), the invalid --light variable will default to #fbfbfb, and the valid --dark variable (empty) allows --background-color to equal #fbfbfb.
All the other color variables follow the same logic, adjusting based on the state of --light and --dark. This way, each color variable only needs to be defined once.
Switching states becomes simple. If dark mode is active, use --light: var(--OFF); and --dark: var(--ON);. In light mode, reverse them. Though not immediately intuitive, this method is currently the most effective with CSS. If there are better solutions, they are worth exploring.
Complete example:
SOCIAL SHARE CARD GENERATOR