Some years ago (2018 I think), I gave a talk during the JavaScript Meetup of Luxembourg where I presented briefly my interest for this new topic: CSS Variables. The official name of this specification is CSS Custom Properties. It allows you to store dynamic custom values to be used as CSS value within your code.

Long time I should have publish this, but better late than never, isn’t it?
Unfortunately, the event wasn’t recorded, so here are the slides of the talk. But I’ll explain a bit more some of the concept of CSS Variables afterwards.

I won’t go into detail of each slide, but don’t hesitate to ask me on Twitter if you have any question. You can even ask me to talk for your meetup or conference if you think this topic is interesting for your public.

CSS Variable: declaration and usage

So, first, how to use CSS Variables in your code?

  1. Declare your variable so they are available in a specific scope:
    :root {
    --colorprimary: #BADA33;
    }
    Scope is global thanks to :root
  2. Then use the function var() to use the variable value as property value.
    a {
    color: var(--primarycolor);
    }
  3. The end.

Note that variables are scoped. Meaning that if you declare your variables within a specific div for instance, the variable will be available only for this div and all its children.

This is interesting because it allows you to create themable sections or contexts within your interface.

Why should I use CSS Variables?

Don’t feel the need to use it just because it’s trendy, use it if you need to make things vary here and there. For instance, it can be really handy for dark mode adjustments or media queries.

:root {
--primarycolor: #BADA33;
--pagebg: #FFF;
--text: #444;
--btn_bg: var(--primarycolor);
--btn_text: black;
}

body {
background: var(--pagebg);
color: var(--text);
line-height: 1.55;
}

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

button,
[type="submit"],
[role="button"] {
border: 0;
padding: 8px 16px;
background: var(--btn_bg);
color: var(--btn_text);
border-radius: 4px;
}

@media (prefers-color-scheme: dark) {
--primarycolor: #98B32A;
--pagebg: #444;
--text: #F2F2F2;
--btn_bg: var(--primarycolor);
--btn_text: white;
}

But, for a lesser need, you can also use it to vary styles while hovering or in active states of elements.

button {
--icon_pos: 0;
--bg_color: salmon;

background: var(--bg_color);
}

button .icon {
transform: translateX(var(--icon_pos));
}

button:hover,
button:focus {
--bg_color: darksalmon;
--icon_pos: 5px;
}

This code example is a bit too simple to find an interest into CSS Variable, but when you build complex component, you are happy to be able to set variables and vary those variables at the component level, without re-declaring all the selectors and states.

CSS Variables are live and JS-friendly

CSS Variables aren’t Sass or LESS variables, they are interpreted by the browser and live all the time. You can change it with JS if you need, or via usual class or states (:hover, :active, :focus, :checked, :valid, etc.) changing.

For instance, this CodePen shows you JavaScript and CSS Variables working together.

dark

The JS part is quit short compared to the CSS linear-gradient declaration. For the JS Part we only set one variable depending on the cursor position.

document.querySelector('.title').addEventListener('mousemove', (e) => {

const x = e.pageX - e.target.offsetLeft

e.target.style.setProperty('--x', `${ x }`)

});

Then we use this variable in CSS to make things dynamic and animated.

.title {
--x: 100;
display: inline-block;
margin: 0;
font-size: 4rem;
font-weight: 600;
background-image: linear-gradient(45deg,#fff070 0%,#fff070 35%,#00c9d3 66%,#00c9d3 100%);
background-image: linear-gradient(45deg,#fff070 0%,#fff070 calc(var(--x) * .1 * 1%),#00c9d3 calc(var(--x) * .4 * 1%),#00c9d3 calc(var(--x) * .7 * 1%) );
-webkit-text-fill-color: transparent;
-webkit-background-clip: text;
}

The double background declaration is for browser that doesn’t support CSS Vars. You can also use @support in some cases. Note that here the initial value is set directly in CSS at the beginning of the selector, scoped.

Another similar shot just to share the effect with you. The first item shows you how it works when Variables are supported, and the 2 others in case they are not.

dark

CSS Variables specificity

There are some things you need to now before jumping into using it without caution.

  • CSS Variable names are case sensitive: --button and --Button are different variables.
  • You can’t “cycle” variables. So you can’t write --value: calc(--value + 10em);
  • You can’t build-up values. The value has to be a valid CSS value for the given usage. So you can’t write:
    :root {
    --unit: 8;
    }

    button {
    padding-top: var(--unit)px; /* doesn't work */
    }
  • You can use !important into Custom Properties values: --value: 10px !important; (but don’t…)
  • A blank character is a valid CSS Custom Properties value: --value: ; is valid, --value:; isn’t.
  • You can have a fallback while using a variable: color: var(--primary, #005533);
  • A variable is a valid fallback: color: var(--primary, var(--neutral, #005533)); and yes, it can be infinite.

I hope this short transcript helped you a little bit. Don’t hesitate to contact me on Twitter if you need any advice.