Briefly
The CSS function var
allows you to substitute custom properties as values for properties.
Example
Declaring a custom property:
:root { --color-cyan: #00ffff;}
:root { --color-cyan: #00ffff; }
Using the var
function to substitute the value of the custom property:
.button { background-color: var(--color-cyan);}
.button { background-color: var(--color-cyan); }
How to Understand
The var
function returns the current value of the custom property. If it changes, the var
function immediately returns the current value.
How var()
works
By passing a custom property to the var
function, the browser moves up the hierarchy of elements in search of the value of the custom property.
It will check if the custom property is set on the current element:
- If yes, it will substitute it for
var
and stop the search.( ) - If not, it will move to the parent element and repeat the check.
The browser will keep moving up the parent elements until it finds a value. The last point will be checking for the value in :root
. If it’s not there, the var
function will set the value to initial
or to a fallback value, if provided.
Let's define a custom property:
:root { --card-color: purple;}
:root { --card-color: purple; }
Let's set the background color of the card using the var
function. The color will be purple:
.card { background-color: var(--card-color);}
.card { background-color: var(--card-color); }
We change the custom property with .set
in JavaScript:
document.documentElement.style.setProperty('--card-color', 'midnightblue')
document.documentElement.style.setProperty('--card-color', 'midnightblue')
Now, wherever the background color is set, the var
function will return dark blue.
How To Write It
Basic Syntax
The var
function takes 2 arguments:
- The name of the custom property.
- A fallback value (optional).
If the custom property referred to by the first argument is invalid, the function will use the second value:
.card { padding: var(--card-padding, 10px);}
.card { padding: var(--card-padding, 10px); }
The value of padding
will be 10px
if -
is not defined.
You can specify multiple fallback values. To do this, you need to pass the var
function with possible values as the second argument:
.title { font-size: var(--font-size, var(--title-font-size, 20px));}
.title { font-size: var(--font-size, var(--title-font-size, 20px)); }
The value of font
will be 20px
if both -
and -
are undefined.
Fallback Value
Another example, although a bit non-obvious. If the variable -
is not defined, the fallback value will be: -
. Unfortunately, this is not valid:
.title { font-size: var(--font-size, --title-font-size, 20px);}
.title { font-size: var(--font-size, --title-font-size, 20px); }
This is because everything after the first comma is treated as a single value. Thus, as a fallback value, the function will return the value from the first comma to the closing parenthesis.
However, this example is valid. The fallback value will be: 10px
:
.navigation { --translate: var(--my-translate, 10px, 10px); transform: translate(var(--translate));}
.navigation { --translate: var(--my-translate, 10px, 10px); transform: translate(var(--translate)); }
About value validity
:root { --text-color: 16px;}.element { color: var(--text-color);}
:root { --text-color: 16px; } .element { color: var(--text-color); }
In this example, the custom property -
has a value of 16px
, which is technically valid. But when the browser substitutes the value -
for var
, it tries to use the value 16px
, which is not a valid value for the property color
.
The browser sees it as an invalid value and checks if the color
property is inherited from the parent element. If so, it uses it. Otherwise, it sets the value to initial
.
Features
The var
function can be substituted as part of a property value:
.card { --border-color: black; border: 1px solid var(--border-color);}
.card { --border-color: black; border: 1px solid var(--border-color); }
The var
function also works with shorthand properties: margin
, padding
, border
, background
, transform
, transition
etc.
You can use it to substitute either a single value:
.element { --margin-top: 10px; margin: var(--margin-top) 10px 20px 30px;}
.element { --margin-top: 10px; margin: var(--margin-top) 10px 20px 30px; }
Or multiple:
.element { --margin-top-right: 10px 10px; margin: var(--margin-top-right) 10px 50px;}
.element { --margin-top-right: 10px 10px; margin: var(--margin-top-right) 10px 50px; }
Limitations
The var
function cannot be used as property names, selectors, or anything else except property values.
For example, the following code incorrectly uses a custom property as a property name:
.element { --side: margin-top; var(--side): 20px;}
.element { --side: margin-top; var(--side): 20px; }
You cannot mix a custom property with any other value in this way:
.element { --gap: 20; margin-top: var(--gap)px;}
.element { --gap: 20; margin-top: var(--gap)px; }
Instead, you can use this trick:
.element { --gap: 20; margin-top: calc(var(--gap) * 1px);}
.element { --gap: 20; margin-top: calc(var(--gap) * 1px); }
Or write the full value in the custom property:
.element { --gap: 20px; margin-top: var(--gap);}
.element { --gap: 20px; margin-top: var(--gap); }
Inside Other Functions
It also works with functions like:
.element-1 { --offset: 50px; height: calc(100vh - var(--offset));}.element-2 { --height: 100vh - 50px; height: calc(var(--height));}
.element-1 { --offset: 50px; height: calc(100vh - var(--offset)); } .element-2 { --height: 100vh - 50px; height: calc(var(--height)); }
rgb
and rgba
.element-1 { --rgb: 0, 0, 0; color: rgba(var(--rgb), 1);}.element-2 { --rgb: 0 0 0; color: rgb(var(--rgb));}.element-3 { --red: 0; --green: 0; --blue: 0; color: rgb(var(--red), var(--green), var(--blue));}
.element-1 { --rgb: 0, 0, 0; color: rgba(var(--rgb), 1); } .element-2 { --rgb: 0 0 0; color: rgb(var(--rgb)); } .element-3 { --red: 0; --green: 0; --blue: 0; color: rgb(var(--red), var(--green), var(--blue)); }
linear
and radial
:root { --c1: red; --c2: blue; --grad: linear-gradient(var(--c1), var(--c2));}.element { --c1: green; background: var(--grad);}
:root { --c1: red; --c2: blue; --grad: linear-gradient(var(--c1), var(--c2)); } .element { --c1: green; background: var(--grad); }
:root { --url: url("https://example.com/example.jpg");}.element { background: var(--url);}
:root { --url: url("https://example.com/example.jpg"); } .element { background: var(--url); }
But this example will not work because the url
function interprets the structure var
as a URL:
:root { --url: "https://example.com/example.jpg";}.element { background: url(var(--url));}
:root { --url: "https://example.com/example.jpg"; } .element { background: url(var(--url)); }