CSS variables (AKA custom backdrop) have been supported in web browsers for most four years. I like to apply them depending on the project and the situation. They are very useful and easy to apply, only oftentimes, a front-stop developer might misuse or misunderstand them.

The master purpose of this article is that I wanted to take a place where I can dump all the information I know about CSS variables, and even larn more and certificate them. You volition larn virtually everything you need to know nearly CSS variables with lots of examples and use-cases.

Are yous ready? Let'due south swoop in.

Introduction

CSS variables are values that are defined in a CSS certificate with the goal of reusability and reducing back-up in CSS values. Hither is a basic example.

                          .section              {              border              :              2px              solid              #235ad1              ;              }              .section-title              {              colour              :              #235ad1              ;              }              .department-title              ::before              {              content              :              ""              ;              brandish              :              inline-block              ;              width              :              20px              ;              height              :              20px              ;              background-color              :              #235ad1              ;              }                      

In this snippet, the value #235ad1 is used three times. Imagine this for a large project, different CSS files, and you got asked to modify the color. The best matter you tin can do is the good sometime Find & Replace.

With CSS variables, this can be made much better like so. Let'due south acquire how to ascertain one. Commencement, you need to add the double hyphen -- before a variable name. As a start, we will ascertain the variable in the :root or the <html> element for now.

                          :root              {              --color-master              :              #235ad1              ;              }              .section              {              border              :              2px              solid              var              (              --colour-master              );              }              .department-championship              {              color              :              var              (              --color-master              );              }              .section-title              ::earlier              {              /* Other styles */              groundwork-colour              :              var              (              --colour-main              );              }                      

Isn't that much, much cleaner than the previous snippet? The variable --colour-primary is a global variable, because nosotros divers information technology in the :root element. However, we can besides scope variables to certain elements throughout the document.

Naming variables

Similar to naming variables in programming languages, naming CSS variables are not that dissimilar. The valid naming for a CSS variable should incorporate alphanumeric characters, underscores, dashes. Also, it's worth mentioning that CSS variables are example sensitive.

                          /* Valid names */              :root              {              --principal-color              :              #222              ;              --_primary-color              :              #222              ;              --12-primary-colour              :              #222              ;              --primay-color-12              :              #222              ;              }              /* Invalid names */              :root              {              --primary              colour              :              #222              ;              /* Spacings are non allowed */              --main$%#%$#              }                      

Scoping

What's useful about CSS variables is that nosotros can scope them. The concept is similar to what we have in other programming languages. Accept Javascript, for example.

                          let              element              =              "absurd"              ;              function              cool              ()              {              permit              otherElement              =              "Non cool"              ;              panel              .              log              (              element              );              }                      

The variable element is global, and then it can be accessed inside the cool() function. However, the variable otherElement can simply be accessed inside the cool() function. Allow's utilise the above concept to CSS variables.

                          :root              {              --main-color              :              #235ad1              ;              }              .section-championship              {              --primary-colour              :              d12374              ;              colour              :              var              (              --primary-colour              );              }                      

The variable --primary-colour is global and can be accessed from any element in the document. By redefining it inside the scope of .section-title declaration block, its new value only works there.

Here is a visual example that explains information technology better.

We accept --primary-color that is used for the section title color. We want to customize the color for the featured authors and the latest articles sections, so we override it. The same thing applies to the --unit variable. Here is the CSS version for the figure above.

                          /* Global variables */              :root              {              --primary-color              :              #235ad1              ;              --unit              :              1rem              ;              }              /* Section title default color and spacing */              .section-championship              {              colour              :              var              (              --principal-colour              );              margin-bottom              :              var              (              --unit              );              }              /* Overrding the section championship color */              .featured-authors              .section-title              {              --primary-colour              :              #d16823              ;              }              /* Overrding the section title color & spacing */              .latest-articles              .department-title              {              --primary-color              :              #d12374              ;              --unit              :              2rem              ;              }                      

Providing fallback

By fallback, this doesn't mean to provide a fallback to a browser that doesn't support CSS variables. The fallback is a feature that we can use with CSS variables. Consider the following instance:

                          .section-championship              {              colour              :              var              (              --primary-colour              ,              #222              );              }                      

Observe that the var() has multiple values. The 2nd one #222 will only work in example the variable --master-color is non defined for some reason. Not but that, we can nest a var() inside some other one.

                          .section-title              {              color              :              var              (              --master-color              ,              var              (              --blackness              ,              #222              ));              }                      

This feature can be useful in cases where a variable value depends on a sure action. When the variable doesn't have a value, it'southward important to provide a fallback for it.

Use cases and examples

Controlling the size of a component

Information technology's common to take multiple sizes for a button in a blueprint system. Usually, a push button can have three sizes (Small, normal, large). Information technology hasn't been easier to implement this with CSS variables.

                          .button              {              --unit              :              1rem              ;              padding              :              var              (              --unit              );              }              .button--minor              {              --unit              :              0.5rem              ;              }              .button--big              {              --unit              :              1.5rem              ;              }                      

Past irresolute the variable --unit within the scope of the push button component, nosotros created different variations of the button.

CSS variables and HSL Colors

HSL stands for hue, saturation, brightness. The hue value determines the color. The saturation and brightness values tin control how night or light the color is.

                          :root              {              --primary-h              :              221              ;              --primary-s              :              71%              ;              --principal-b              :              48%              ;              }              .button              {              background-color              :              hsl              (              var              (              --primary-h              ),              var              (              --primary-s              ),              var              (              --primary-b              ));              transition              :              background-color              0.3s              ease-out              ;              }              /* Making the background darker */              .button              :hover              {              --main-b              :              33%              ;              }                      

Notice how I made the button darker by decreasing the variable --primary-b.

If you want to learn more near colors in CSS, I wrote a detailed article about them.

Proportional resizing

If you have worked with a design program like Photoshop, Sketch, Figma, or Adobe XD, so you might have an idea most holding the Shift key while resizing an chemical element to avert distorting it.

In CSS, in that location is no direct style to do this, only we accept a simple workaround that uses, you guessed it, CSS variables.

Suppose that at that place is an icon and its width and height should be equal. I divers the variable --size and used information technology for both the width and peak.

                          .icon              {              --size              :              22px              ;              width              :              var              (              --size              );              height              :              var              (              --size              );              }                      

That'due south information technology! Now you can mimic the Shift resizing effect past only changing the value of --size variable. You tin read more near this in this snippet by yours truly.

CSS Grid

CSS variables tin be extremely useful for grids. Imagine that you want a grid container to display its kid items based on a defined preferred width. Instead of creating a class for each variation and duplicating CSS, it'due south easier to exercise that with variables.

                          .wrapper              {              --detail-width              :              300px              ;              display              :              grid              ;              grid-template-columns              :              repeat              (              auto-fill up              ,              minmax              (              var              (              --item-width              ),              one              fr              ));              grid-gap              :              1rem              ;              }              .wrapper-2              {              --particular-width              :              500px              ;              }                      

With that, we can create a total grid organization that is flexible, easy to maintain, and can exist used in other projects. The same concept tin can be applied to the filigree-gap holding.

                          .wrapper              {              --item-width              :              300px              ;              --gap              :              0              ;              brandish              :              grid              ;              filigree-template-columns              :              echo              (              auto-fill              ,              minmax              (              var              (              --particular-width              ),              1              fr              ));              }              .wrapper.gap-1              {              --gap              :              16px              ;              }                      

Storing total values

CSS Gradients

By full values, I mean things like a gradient, for example. If you lot have a slope or a background that is existence used across the system, storing information technology into a CSS variable might be a good thing to practice.

                          :root              {              --master-gradient              :              linear-slope              (              150deg              ,              #235ad1              ,              #23d1a8              );              }              .element              {              background-epitome              :              var              (              --chief-gradient              );              }                      

Or we tin can store a unmarried value. Take the gradient angle, for example.

                          .element              {              --bending              :              150deg              ;              groundwork-image              :              linear-slope              (              var              (              --angle              ),              #235ad1              ,              #23d1a8              );              }              .element.inverted              {              --angle              :              -150deg              ;              }                      

Background position

Nosotros can include multiple values inside a CSS variable, and this is helpful in case we have an element that needs to be positioned differently based on a specific context.

                          .table              {              --size              :              50px              ;              --pos              :              left              center              ;              background              :              #ccc              linear-slope              (              #000              ,              #000              )              no-repeat              ;              background-size              :              var              (              --size              )              var              (              --size              );              background-position              :              var              (              --pos              );              }                      

Switching between dark and light mode

The dark and light modes are requested now more ever for websites. With CSS variables, we can store two versions of them, and toggle between them based on the user or system preference.

                          :root              {              --text-color              :              #434343              ;              --edge-colour              :              #d2d2d2              ;              --primary-bg-color              :              #fff              ;              --action-bg-color              :              #f9f7f7              ;              }              /* A class added to the <html> chemical element*/              .night-mode              {              --text-color              :              #e9e9e9              ;              --border-colour              :              #434343              ;              --master-bg-colour              :              #434343              ;              --activeness-bg-colour              :              #363636              ;              }                      

Setting a default value

In some cases, you volition demand to set a CSS variable with JavaScript. Let's suppose that we demand to get the superlative of an expandable component. I learned about this technique from an article past Michael Scharnagl.

The variable --details-height-open up is empty and it will be added to a specific HTML element. Information technology volition comprise a pixel value. When Javascript fails for some reason, it'southward important to provide a proper default or fallback value.

                          .section.is-active              {              max-height              :              var              (              --details-height-open              ,              auto              );              }                      

The auto value is the fallback value in case Javascript fails and the CSS variable --details-height-open is not divers.

Controlling a wrapper width

A website wrapper tin can accept multiple variations. Yous might need a small-scale wrapper for a page, and a larger i for another. In such a example, incorporating CSS variables tin can be useful.

                          .wrapper              {              --size              :              1140px              ;              max-width              :              var              (              --size              );              }              .wrapper--pocket-sized              {              --size              :              800px              ;              }                      

Inline styles

Using CSS variables with inline styles tin open a lot of new possibilities that you might not be aware of. I wrote a complete commodity but about that, but I volition mention some of the interesting use-cases here.

This might not be the perfect approach for production websites, merely it tin can exist useful for prototyping and testing different ideas.

Dynamic grid items

We can add the variable --item-width insides the manner attribute, and that's all. This approach tin can assist in prototyping grids, for instance.

                          <div              class=              "wrapper"              fashion=              "--item-width: 250px;"              >              <div></div>              <div></div>              <div></div>              </div>                      
                          .wrapper              {              display              :              grid              ;              grid-template-columns              :              echo              (              auto-fill              ,              minmax              (              var              (              --item-width              ),              1              fr              ));              grid-gap              :              1rem              ;              }                      

Demo

User avatars

Another useful use-case is sizing elements. Say you need four dissimilar sizes of a user avatar with the ability to control their size with only 1 variable.

                          <img              src=              "user.jpg"              alt=              ""              class=              "c-avatar"              style=              "--size: 1"              />              <img              src=              "user.jpg"              alt=              ""              class=              "c-avatar"              manner=              "--size: two"              />              <img              src=              "user.jpg"              alt=              ""              class=              "c-avatar"              style=              "--size: 3"              />              <img              src=              "user.jpg"              alt=              ""              class=              "c-avatar"              style=              "--size: iv"              />                      
                          .c-avatar              {              display              :              inline-cake              ;              width              :              calc              (              var              (              --size              ,              ane              )              *              30px              );              meridian              :              calc              (              var              (              --size              ,              1              )              *              30px              );              }                      

Let's clarify the in a higher place CSS:

  • First, we accept var(--size, 1). I added a fallback value in case the value wasn't added in the style attribute.
  • The minimum size of an avatar is 30px * 30px.

Media queries

Combining CSS variables and media queries can be very useful to tweak variables that are used beyond the whole website. The simplest example I can think about is changing the spacing value.

                          :root              {              --gutter              :              8px              ;              }              @media              (              min-width              :              800px              )              {              :root              {              --gutter              :              16px              ;              }              }                      

Any element using the --gutter variable will modify its spacing depending on the viewport size. Isn't that awesome?

Inheritance

Yeah, CSS variables do inherit. If a parent has a CSS variable defined within it, then the descendant elements volition inherit the same CSS variable. Let's have the following instance.

                          <div              course=              "parent"              >              <p              class=              "kid"              ></p>              </div>                      
                          .parent              {              --size              :              20px              ;              }              .child              {              font-size              :              var              (              --size              );              }                      

The .child element volition have access to the variable --size as a consequence of inheriting it from its parent. Interesting, no? You lot might be wondering about how can we get the do good of this? Well, here is a real-life example.

We have a grouping of action items with the following requirements:

  • The ability to alter the size of all items by only irresolute one variable
  • The spacing should be dynamic (Shrinks when the item's size is decreased and grows when the item's size is increased)
                          <div              grade=              "actions"              >              <div              course=              "actions__item"              ></div>              <div              class=              "actions__item"              ></div>              <div              form=              "actions__item"              ></div>              </div>                      
                          .actions              {              --size              :              50px              ;              display              :              flex              ;              gap              :              calc              (              var              (              --size              )              /              5              );              }              .actions--g              {              --size              :              70px              ;              }              .actions__item              {              width              :              var              (              --size              );              elevation              :              var              (              --size              );              }                      

Notice how I used the variable --size for the flexbox gap belongings. That means, the spacing tin can be dynamic and it will depend on the --size variable.

Another useful example is using CSS variables inheritance to customize CSS animations. The following is an example from this article by Sandrina Pereira on CSS Tricks.

                          @keyframes              breath              {              from              {              transform              :              scale              (              var              (              --scaleStart              ));              }              to              {              transform              :              scale              (              var              (              --scaleEnd              ));              }              }              .walk              {              --scaleStart              :              0.iii              ;              --scaleEnd              :              1.7              ;              animation              :              breath              2s              alternate              ;              }              .run              {              --scaleStart              :              0.8              ;              --scaleEnd              :              1.2              ;              blitheness              :              jiff              0.5s              alternate              ;              }                      

That mode, we don't demand to ascertain the @keyframes twice, and it volition inherit the customized CSS variable for the .walk and .run elements.

How validation works for CSS variables

When the CSS variable inside the var() office is invalid, the browser substitute with the initial or inherited value based on the property used.

                          :root              {              --master-color              :              16px              ;              }              .section-title              {              color              :              var              (              --master-color              );              }                      

I used 16px is a value for the color belongings. This is completely wrong. Since the color property is inherited, the browser volition do the post-obit:

  • Is the property inheritable?
    • If yep, does the parent has the property?
      • Yes: inherit the value
      • No: set to initial
    • If no, ready to initial

Here is a flowchart that explains the browser's work.

Invalid at computed-value time

The above is technically called invalid at computed-value time, which happens when the var() references a CSS variable with its initial value or it's using a valid CSS variable with an invalid value for the CSS belongings.

Consider the post-obit example that I learned well-nigh from this article past Lea Verou.

                          .section-title              {              pinnacle              :              10px              ;              top              :              clamp              (              5px              ,              var              (              --offset              ),              20px              );              }                      

If the browser doesn't support the clamp() function, will the tiptop: 10px work as a fallback? The short answer is no. The reason is that considering past the time the browser discovered an invalid property value, it has already thrown away the other cascade values. That means, it will ignore the pinnacle: 10px.

According to the CSS spec:

The invalid at computed-value fourth dimension concept exists considering variables can't "fail early" like other syntax errors tin, then by the fourth dimension the user agent realizes a property value is invalid, information technology's already thrown away the other cascaded values.

Equally a result, if you want to use a CSS characteristic that isn't widely supported and there is a CSS variable within information technology, you need to use CSS @supports for that reason. Here is how Lea Verou used that technique in her article:

                          @supports              (              top              :              max              (              1em              ,              1px              ))              {              #toc              {              summit              :              max              (              0em              ,              11rem              -              var              (              --scrolltop              )              *              1px              );              }              }                      

Interesting findings

URL values

You might non have command over all the resource in a web folio, and some of them must be hosted online. In that case, you can shop the link's URL value in a CSS variable.

                          :root              {              --main-bg              :              url("https://instance.com/cool-paradigm.jpg")              ;              }              .section              {              background              :              var              (              --main-bg              );              }                      

But, yous might wonder if information technology'south possible to interpolate CSS variables with url(). Consider the following:

                          :root              {              --primary-bg              :              "https://case.com/cool-image.jpg"              ;              }              .section              {              background              :              url(var(--main-bg)              );              }                      

It'due south not possible equally var(--main-bg) is treated as the url itself, which is invalid. Past the time the browser has computed the value, it's no longer valid and it won't work every bit expected.

Storing multiple values

What'south useful is that yous can store multiple values regardless of the variable value. If they are valid, then information technology should work. Consider the post-obit example:

                          :root              {              --main-color              :              35              ,              90              ,              209              ;              }              .department-title              {              color              :              rgba              (              var              (              --principal-colour              ),              0.75              );              }                      

In the example, we accept a rgba() office, and the RGB values are stored in CSS variable, separated past a comma. This can provide flexibility in case you want to tweak the alpha value depending on the element.

The but downside of this is that it won't be possible to tweak the rgba value using the DevTools color picker. If this is important to your use-example or project, then you might demand to reconsider using the rgba equally explained above.

Another example is using this with the background holding.

                          :root              {              --bg              :              linear-slope              (              #000              ,              #000              )              centre              /              50px              ;              }              .department              {              background              :              var              (              --bg              );              }              .section--unique              {              background              :              var              (              --bg              )              no-repeat              ;              }                      

We have two sections, and ane of them requires the backgrounds to non echo across the x and y axes.

Animating variables within a @keyframes rule

If you have read the spec for CSS variables, you might read the term animation-tainted. The idea is that when using a CSS variable inside a @keyframes rule, it tin can't exist blithe.

                          .box              {              width              :              50px              ;              peak              :              50px              ;              background              :              #222              ;              --start              :              0              ;              transform              :              translateX              (              var              (              --offset              ));              animation              :              moveBox              1s              infinite              alternating              ;              }              @keyframes              moveBox              {              0              %              {              --outset              :              0              ;              }              l              %              {              --beginning              :              50px              ;              }              100              %              {              --start              :              100px              ;              }              }                      

The animation won't work smoothly. It will breathing the box merely for the values (0, 50px, 100px). According to the CSS spec:

..any custom property used in a @keyframes dominion becomes animation-tainted, which affects how information technology is treated when referred to via the var() function in an animation property.

If we want the above animation to work, we should exercise it the old-schoolhouse manner. That means, nosotros need to supervene upon the variable with the actual CSS property we desire to animate.

                          @keyframes              moveBox              {              0              %              {              transform              :              translateX              (              0              );              }              50              %              {              transform              :              translateX              (              50px              );              }              100              %              {              transform              :              translateX              (              100px              );              }              }                      

Encounter the Pen CSS Variables - Keyframes - 1 by Ahmad Shadeed (@shadeed) on CodePen.

Update: 9 Oct 2020

Dannie Vinther pointed out that it'due south possible to animate CSS variables inside keyframes by registering them using the @property . That is supported in Chromium browsers for at present.

                          @belongings              --starting time              {              syntax              :              "<length-percentage>"              ;              inherits              :              truthful              ;              initial-value              :              0px              ;              }                      

See the Pen CSS Variables - Keyframes - 1 by Dannie Vinther (@dannievinther) on CodePen.

Calculations

Y'all might not know that y'all can do calculations with CSS variables. Consider the following example that I explained previously.

                          .c-avatar              {              display              :              inline-block              ;              width              :              calc              (              var              (              --size              ,              1              )              *              30px              );              peak              :              calc              (              var              (              --size              ,              1              )              *              30px              );              }                      

We might have variations of the avatar. I set the default value to 1, and so the default size is (30px * 30px). Notice the different course variations and how irresolute the --size value results in changing the size of the avatar.

                          .c-avatar--modest              {              --size              :              2              ;              }              .c-avatar--medium              {              --size              :              3              ;              }              .c-avatar--large              {              --size              :              iv              ;              }                      

At that place are some useful tricks that we tin employ in the browser DevTools to make information technology easier for us to work with CSS variables. Let's explore them!

The power to meet the color value

Isn't it useful to meet a visual indicator for the colour or background value when you're using a CSS variable? Chrome and Edge prove that.

Computed values

To come across the computed value of a CSS variable, you demand to hover or click, based on the browser.

All computed values can exist revealed on hover, except for Safari, you demand to click on the two-lines-push.

Autocomplete for CSS variables

In a large project, it's hard to remember all the variable names. You got covered! You can type -- some characters and y'all will get a listing with CSS variables on the folio. This works for Chrome, Firefox, and Edge.

Disabling a CSS variable

When y'all need to disable a CSS variable from all elements that are using information technology, this is possible by unchecking it from the element it'southward defined to. See the figure below:

The Finish

That was a lot about CSS variables. I'g now happy that I finally take a defended page for them. I hope you found this useful, and if yes, please practice spread the word. Thank you for reading!

I'thousand writing an ebook

I'm excited to let you know that I'thousand writing an ebook about Debugging CSS.

If you're interested, caput over to debuggingcss.com and subscribe for updates about the book.