Getting to grips with CSS variables

If you have ever used JavaScript variables then the concept of CSS variables should feel pretty familiar.

  1. You set a variable
  2. You use the variable

CSS variables follows this same pattern, but the language is slightly different.

body {
    --my-variable: red;
}


h1 {
    color: var(--my-variable);
}

What is happening here? Firstly we set the variables - essentially they are custom properties. We use -- before the variable name to make it a variable. Then we use the variable by using var(--variable-name).

<body> <!-- --my-variable: red; -->
    <h1>CSS - Carl's Super Styles!</h1> <!-- colour: red  -->
</body>

Usually most variables are set on the pseudo element ::root so that every HTML element will be encompassed by it.

:root {
    --color: red;
    --size: 20px;
    --background: #222;
    --padding: 1em;
}

Scope of variables

CSS variables are scoped to their ancestors (parents, though grandparents to the root pseudo element).

Variables can be changed by child elements, but only apply further downstream in the DOM. That means that variables set in different branches of the DOM are only applicable to that tree. A bit like genetics, you only share the same genes from shared ancestors.

Changing a variable

:root {
    --my-variable: red;
}

body {
    --my-variable: blue;
}

h1 {
    color: var(--my-variable);
}

Here the root color of red is overridden by the my-variable on the body, so the h1 ends up with blue text.

<!-- :root --my-variable: red; -->
<body> <!-- --my-variable: blue; -->
    <h1>CSS - Carl's Super Styles!</h1> <!-- colour: blue  -->
</body>

The Same variable in different trees

In the following example the root --color variable is black. We then set the classes of .red and .blue to red and blue respectively. Then we create a h2 to consume the --color variable.

:root {
    --color: black;
}

.red {
    --color: red;
}

.blue {
    --color: blue;
}

h2 {
    color: var(--color);
}

The h2 that is not wrapped by either one of red or blue inherits the value for the root color variable which is black. Both red and blue redefine the value of the variable and the h2 within their trees will be the relevant color.

<h2>Black</h2>

<div class="red">
    <h2>Red</h2>
</div>

<div class="blue">
    <h2>Blue</h2>
</div>

Media queries

In the pre variable days of css we did this:

.red { 
    font-size: 1em;
}

.blue { 
    font-size: 1em;
}

@media screen and (min-width: 32em) {
    .red  {
         font-size: 2em;
     }
    .blue  {
         font-size: 2em;
     }

}

With variables we can replace the hardcoded values with values set at the :root.

:root {
    --mobile-size: 1em;
    --desktop-size: 2em;
}

.red { 
    width: var(--mobile-size);
}

.blue { 
    width: var(--mobile-size);
}

@media screen and (min-width: 32em) {
    .red  {
         width: var(--desktop-size);
     }
    .blue  {
         width: var(--desktop-size);
     }
}

We can do one better and move the mediaqueries to the root, cutting out the need to add extra code for developers to maintain. Mediaqueries can then all be managed in 1 place too!

:root {
    --font-size: 1em;
}

@media screen and (min-width: 32em) {
    :root {
        --font-size: 2em;
    }
}

.red { 
    width: var(--font-size);
}

.blue { 
    width: var(--font-size);
}

Tags