CSS variables: scoping
Tags: css
Published: 2020-08-03 14:08:44

---
title: CSS variables: scoping
published: true
date: 2020-07-27 15:58:02 UTC
tags: css
canonical_url: https://blog.logrocket.com/css-variables-scoping/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/lndu7x6iuj80ym4mo9rk.png
---
**Written by [Chidume Nnamdi](https://blog.logrocket.com/author/chidumennamdi/)**✏️

We can declare variables in CSS in the same way we declare variables in other programming languages.

We declare a variable in CSS assigned with a value. The variable can then be consumed in CSS rulesets.

In JavaScript, for example, we declare variables using the `let`, `var` and `const` keywords:

```jsx
let nine = 9;
var ten = 10;
var eight = 8;
```

Then, we consume them by referring to their variable names:

```jsx
>> nine
9
>>  ten
10
>> eight 
8
```

We can also do this in CSS. To declare a variable in CSS, we use this format:

```jsx
--varName
```

In CSS, it’ll look like this:

```jsx
body {
    --mainColor: limegreen;
}
```

Let’s say we declare a variable with the name `--mainColor` and a value of `limegreen`. This variable holds a color name.

To consume variables in CSS, we use  `var()`:

```jsx
var(--varName);
```

`var` will retrieve the value of the variable passed to it, and replace itself with the value:

```jsx
body {
    --mainColor: limegreen;
}

div {
    color: var(--mainColor);
}
```

Here, `div` consumes the `mainColor` variable using the `var` function. The `var` will retrieve the value `limegreen` from `--mainColor` and replace itself with `limegreen`, the value of the `--mainColor` variable.

So, the color of the text node in the `div` element will be lime green. In other words, the CSS code would translate to this:

```jsx
body {
    --mainColor: limegreen;
}

div {
    color: limegreen;
}
```

## Scoping

The place in the CSS hierarchy where you declare a CSS variable will determine its level of visibility throughout the lower levels of the hierarchy.

A CSS variable used throughout the entire page is declared in the `::root` pseudo selector, or in the `html` selector.

This is because all the elements on our page are enclosed in one HTML element, so CSS variables declared in the HTML element or in its `::root` selector will be visible for consumption from its children.

`::root` is a pseudo selector attached to the root of the HTML element in a document. In an RSS document, the `::root` element is attached to the RSS element.

Generally, a CSS variable is only visible to child elements of the parent element it is declared in.

Now, we have this:

```jsx
<body>
    <div>Div 1</div>
    <div>Div 2</div>
</body>
```

The `body` element is parent to its child elements `div`, `Div 1`, and `Div 2`.

So this is feasible:

```jsx
body {
    --bgColor: limegreen;
}

div {
    background: var(--bgColor);
}
```

The CSS variable `bgColor` is declared in the body element and consumed in a `div` to set the background of div elements to lime green.

This would be visible to our two div elements because they are child elements to the body element, which is where the CSS variable it consumed is declared.

Now, if the reverse was true:

```jsx
body {
    background: var(--bgColor);
}

div {
    --bgColor: limegreen;
}

<body>
    <div>Div 1</div>
    <div>Div 2</div>
</body>
```

The `--bgColor` variable is declared in the div element and consumed in the body element. Now, the body element is above the div element, so the `--bgColor` variable won’t be visible to the body element. As a result, the background of the body element won’t turn to lime green.

The `--bgColor` variable in this case will be visible to elements beneath the div elements:

```jsx
body {
    background: var(--bgColor);
}

div {
    --bgColor: limegreen;
}

p {
    background: var(--bgColor);
}

<body>
    <div>Div 1
        <p>Paragraph 1</p>
    </div>
    <div>Div 2
        <p>Paragraph 2</p>
    </div>
</body>
```

The `--bgColor` variable will be visible to the `p` elements because they are child elements of `div`.

We can see here that the visibility of CSS variables depends on a parent-child relationship. A child element is within the scope of its parent element, so it can use the CSS variable declarations in the parent scope.

Theming is done with CSS variables, and mostly the theming propagates the entire DOM tree, so the CSS variables are usually set in the `html` element or in the `::root` element. This is because no element is placed outside the HTML element:

```jsx
::root {
    --bgColor: lightcoral;
    --mainColor: limegreen;
    --borderColor: seagreen;
}
```

In rare cases when we want to theme a portion of the DOM tree or to theme a DOM branch using CSS variables, we’ll set the CSS variables in the root element of the DOM branch so it will propagate down the branch tree.

```jsx
<html>
    <body>
        <div class="branch">
            <p>
                Paragraph 1
            </p>
        </div>
        <p>
            Paragraph 2
        </p>
    </body>
</html>
```
```css
.branch {
    --brBgColor: palevioletred;
    --brMainColor: blueviolet;
}

p {
    background: var(--brBgColor);
    color: var(--brMainColor);
}
```

The CSS variables declared in the `div.branch` will be visible to the `p` element `Paragraph 1`, because it is a child element of the `div` with class name `branch`. The background color and text color will be painted `palevioletred` and `blueviolet` colors, respectively. The `p` element `Paragraph 2` will not be affected with the styling because the CSS variables `--brBgColor` `--brMainColor` will not be visible to it.  
This is because it is not a child element of the `div.branch`.

So, this is scoping at work in CSS variables.

### Global Scope

CSS variables declared in the `::root` selector are said to be in the Global scope. This means that they can be accessed anywhere in the CSSOM.

Why does it work?

Like we learned earlier, the `::root` selector is attached at the root of the document. All elements in the web document are under the root document, so CSS variables declared in the `::root` will cascade down to all levels if the document. Alternatively, the declared CSS variables will be visible to all elements in the document.

### Local Scope

Just like in the `::root` selector, CSS variables can also be declared in all levels of the CSSOM hierarchy or a particular selector.

Now, CSS variables declared in these levels or in a selector are only visible or scoped locally to the selector and its child nodes.

### Hoisting

> CSS Variables are hoisted and they are moved on the top of the CSSOM before rendering the styles of respective HTML elements in the browser.

Just like in JavaScript, CSS Variables can be hoisted. This means that CSS variables can be used before they are declared.

```jsx
var num2 = 90

var add = num1 + num2

var num1 = 10

log(add)
```

In the above example, the `num1` variable is being used before it is declared. That means that `num1` was hoisted. Upon running the code, add will log 100. Despite being used first before declaration, JavaScript was able to get the value and perform the operation.

The same is also true in CSS variables:

```jsx
body {
    background-color: var(--bgColor);
}

::root {
    --bgColor: rgb(221, 221, 221);
}
```

As you can see, the CSS variable `--bgColor` was used before it was declared in the `::root` pseudo-selector. And the code works perfectly fine!

So, CSS variables can be accessed first and declared later. This makes CSS variables a very powerful feature.

## Checking for Support

CSS variables are widely supported in major browsers, though support may be lacking in older versions of Chrome and Firefox. Support for CSS variables in IE and Edge are presently underway.

Because not all browsers support CSS variables, we can detect CSS variable feature support using the `@supports`.

```jsx
@supports(--bgColor: rgb(221, 221, 221)) {

}
```

The second option is to set a fallback value:

```jsx
::root {
    --primaryColor: blue;
}

button {
    color: var(--primaryColor);
    color: blue;
}
```

We set up a `--primaryColor` variable in the `::root` selector with color `blue`. However, we’re not sure the browser our CSS runs on supports CSS variables. To make the code work, we added a fallback value in the button selector. This makes sure the button uses our primary color in browsers that don’t support CSS variables.

### Advantages of using CSS variables

**Theming**

CSS Variables scoping improves the way we add and modify themes in our CSS. With CSS variables, theming in CSS won’t require extra stylesheets with different themes. Instead, all you need to do is update the CSS variables.

**Styling**

> Leveraging CSS Variable scope improves the size, specificity, & semantics of our stylesheets

Let’s say we have a button:

```jsx
button {
    padding: 10px 5px;
}
```

With different button styles:

```jsx
.btn-danger {
    background-color: orange;
}

.btn-success {
    background-color: lightblue;
}
```

With CSS variables, we don’t have to define `background-color` in every button style.

```jsx
button {
    --btnBgColor: blue;
    padding: 10px 5px;
    background-color: var(--btnBgColor);
}

.btn-danger {
    --btnBgColor: orange;
}

.btn-success {
    --btnBgColor: lightblue;
}
```

We simply assign the `--btnBgColor` new values in every button style. We no longer need to override the base styles.

See? CSS Variables are very powerful, and the scoping feature makes them an ideal tool for clean, modular design systems.

## Conclusion

We just treated a potential bug in CSS today.

Just as we have scoping in JavaScript and other languages, the same is true in CSS variables. We have seen one major application of CSS variables: theming. There are lots more it can offer us.

If you have any questions regarding this or anything I should add, correct or remove, feel free to comment, email, or DM me.

* * *
## Is your frontend hogging your users' CPU?

As web frontends get increasingly complex, resource-greedy features demand more and more from the browser. If you’re interested in monitoring and tracking client-side CPU usage, memory usage, and more for all of your users in production, [try LogRocket.](https://logrocket.com/signup/) 

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/403rye2ptzx994uhktk1.png)

[LogRocket](https://logrocket.com/devto) is like a DVR for web apps, recording everything that happens in your web app or site. Instead of guessing why problems happen, you can aggregate and report on key frontend performance metrics, replay user sessions along with application state, log network requests, and automatically surface all errors.

Modernize how you debug web apps — [Start monitoring for free.](https://logrocket.com/signup/)
* * *

The post [CSS variables: scoping](https://blog.logrocket.com/css-variables-scoping/) appeared first on [LogRocket Blog](https://blog.logrocket.com).