Menu

Introduction to CSS Variables

This guide talks about a subject matter that’s not yet supported in most browsers. See the browser support section for more information.

CSS variables give us many of the same advantages that classic variables offer up to programming languages: convenience, code-reusability, a more readable codebase, and improved mistake-proofing.

Example

:root {
  --base-font-size: 16px;
  --link-color: #6495ed;
}

p {
  font-size: var( --base-font-size );
}

a {
  font-size: var( --base-font-size );
  color: var( --link-color );
}

Basics

There are three main components you should know about when using CSS variables:

Custom Properties

You already know about the standard CSS properties such as color, marginwidth, and font-size.

The following example uses the color CSS property:

body {
  color: #000000; /* The "color" CSS property */
}

A custom property just means that we (the CSS authors) get to define the property’s name.

To define a custom property name, we need to prefix it with two dashes (--).

If we want to create a custom property with the name of text-color that has a color value of black (#000000 in hex code), this is how we could do it:

:root {
  --text-color: #000000; /* A custom property named "text-color" */
}

var() Function

In order to apply our custom properties to our work, we have to use the var() function, otherwise browsers won’t know what they’re for.

If we want to use the value of our --text-color custom property in our p, h1, and h2 style rules, then we need to use the var() function like this:

:root {
  --text-color: #000000;
}

p {
  color: var( --text-color );
  font-size: 16px;
}

h1 {
  color: var( --text-color );
  font-size: 42px;
}

h2 {
  color: var( --text-color );
  font-size: 36px;
}

The example above is equivalent to:

p {
  color: #000000;
  font-size: 16px;
}

h1 {
  color: #000000;
  font-size: 42px;
}

h2 {
  color: #000000;
  font-size: 36px;
}

:root Pseudo-class

We need a place to put our custom properties in. We can specify custom properties within any style rule, but many times, that’s not a good idea because specifying custom properties all over the place presents maintainability and CSS-readability challenges.

The :root pseudo-class represents the top level of our HTML documents. This selector is a good place to put our custom properties in because we can predictably overwrite the custom property values through other CSS selectors that have greater specificity.

Benefits of CSS Variables

Maintainability

Within a given web development project, we’ll often be reusing certain CSS property values. We’ll often reuse colors, line heights, margins, font sizes and so forth.

Here’s an example of four style rules that could benefit from CSS variables:

h1 {
  margin-bottom: 20px;
  font-size: 42px;
  line-height: 120%;
  color: gray;
}

p {
  margin-bottom: 20px;
  font-size: 18px;
  line-height: 120%;
  color: gray;
}

img {
  margin-bottom: 20px;
  border: 1px solid gray;
}

.callout {
  margin-bottom: 20px;
  border: 3px solid gray;
  border-radius: 5px;
}

The problem surfaces when we need to change certain property values later on.

If we manually change our values by hand, it might take us a lot of time, and there’s a huge chance we’ll make an error somewhere, especially if our stylesheet is huge. Similarly, if we perform a batch find-and-replace, we might unintentionally affect other style rules.

We can rewrite the above example using CSS variables:

:root {
  --base-bottom-margin: 20px;
  --base-line-height:   120%;
  --text-color:         gray;
}

h1 {
  margin-bottom: var( --base-bottom-margin );
  font-size: 42px;
  line-height: var( --base-line-height );
  color: var( --text-color );
}

p {
  margin-bottom: var( --base-bottom-margin );
  font-size: 18px;
  line-height: var( --base-line-height );
  color: var( --text-color );
}

img {
  margin-bottom: var( --base-bottom-margin );
  border: 1px solid gray;
}

.callout {
  margin-bottom: var( --base-bottom-margin );
  border: 1px solid gray;
  border-radius: 5px;
  color: var( --text-color );
}

Now imagine your client says to you that the text on the screen is hard to read because the text color is too light. In this situation, we just need to update one line in our CSS:

--text-color: black;

That’s -66% fewer lines of code we have to edit, in the context of the previous set of style rules (one line versus three lines)  .

In the same token, using CSS variables gives us an easier time when we want to experiment with our designs. While we’re developing the project, we can rapidly test color values, line-heights, and bottom-margin values all in one place, and we’ll be able to see the effects in a holistic way.

Improved CSS Readability

Custom properties can help make our stylesheets easier to read. It could make our CSS property declarations more meaningful as well.

Compare this:

background-color: yellow;
font-size: 18px;

To this:

background-color: var( --highlight-color );
font-size: var( --base-font-size );

Property values like yellow and 18px don’t give us any useful contextual information. But when we read custom property names like --base-font-size and --highlight-color, even when we’re reading someone else’s code, we instantly know what the property value is doing.

Things to Keep in Mind

Case-sensitivity

Custom properties are case-sensitive (unlike regular CSS properties).

:root {
  --main-bg-color: green;
  --MAIN-BG-COLOR: RED;
}

.box {
  background-color: var( --main-bg-color ); /* green background */
}

.circle {
  BACKGROUND-COLOR: VAR(--MAIN-BG-COLOR ); /* red background */
  border-radius: 9999em;
}

.box,
.circle {
  height: 100px;
  width: 100px;
  margin-top: 25px;
  box-sizing: padding-box;
  padding-top: 40px;
  text-align: center;
}

In the above example, there are actually two custom properties that have been defined: --main-bg-color and --MAIN-BG-COLOR.

Custom Property Value Resolution

When a custom property is declared more than once, the assignment follows normal CSS cascading and inheritance rules.

In the following example, the link will be assigned the color of red because the .container selector has greater specificity compared to :root and body.

HTML

<body>
  <div class="container">
    <a href="">Link</a>
  </div>
</body>

CSS

:root {
  --highlight-color: yellow;
}

body {
  --highlight-color: green;
}

.container {
  --highlight-color: red;
}

a {
  color: var( --highlight-color );
}

However, if we remove the .container style rule from our code, the link will be assigned the color of green because body now becomes the next selector that matches our links.

Fallback Values

You can assign a fallback property value when using the var() function notation. Simply provide the fallback property value as an additional argument delineated with a comma (,).

In the following example, the .box element is supposed to be rendered with a black background. However, because there’s a typo when referencing the custom property name, the background will be rendered using the fallback value (i.e. red).

HTML

<div class="box">A Box</div>

CSS

div {
  --container-bg-color: black;
}

.box {
  width: 100px;
  height: 100px;
  padding-top: 40px;
  box-sizing: padding-box;
  background-color: var( --container-bf-color, red );
  color: white;
  text-align: center;
}

Invalid Values

Beware of assigning CSS properties with the wrong type of value.

In the following example, since the --small-button custom property is given a length unit, its use within the .small-button style rule is invalid.

:root {
  --small-button: 200px;
}

.small-button {
 color: var(--small-button);
}

A good way to avoid this situation is to come up with descriptive custom property names. For instance, naming the above custom property --small-button-width makes its improper use unlikely.

Browser Support for CSS Variables

Last updated: March 2015.

Desktop

BrowserVersion Support
ChromeNone
FirefoxVersion 31
IENone
SafariNone

Mobile

BrowserVersion Support
Chrome (Android)None
Safari (iOS)None

Information covered in this guide uses the latest version of W3C CSS Custom Properties for Cascading Variables Module Level 1 as a reference.

Related Content

Jacob Gube is the founder of Six Revisions. He’s a front-end developer. Connect with him on Twitter and Facebook.

This was published on Mar 25, 2015

3 Comments

Gabriel Mar 25 2015

Hi,

Sounds interesting! But… “not yet supported by most browsers” apparently means “supported only by FireFox”! It will take a lot of time before this replaces LESS or SASS, no?

    Jacob Gube Mar 25 2015

    It will take a lot of time. It will take years. At the time of writing this, the W3C standards for CSS variables is still a Working Draft, which is only the second stage (out of five stages) of completion.

Cathy Mayhue Mar 27 2015

Though not fully implemented across all the browsers and still in the drafting stage but could become a reality in the future, nice concept with interesting possibilities in the web designing, making it more flexible.

This comment section is closed. Please contact us if you have important new information about this post.

Partners