When CSS is getting DRY

CSS isn’t the prettiest ‘language,’ but it has successfully powered the styling of the web for over 20 years now.

Ohans Emmanuel

One of the most important principles in coding is DRY, don’t repeat yourself. But unfortunately, CSS did not hear about it, and most of the time programmers spread CSS values multiple time and repeating the same color again and again. There are plenty of naming conventions as BEM, SMACSS & OOCSS, and Some CSS preprocessors like SASS but still. Until came to the rescue the CSS var’s.

CSS var’s

The syntax is simple, a var declaration must start with “–“, and you use it by the CSS var() function.

:root {
--mainColor: #222;
--otherColor: #ccc;
}

.theBox {
background-color:var(--other-color);
color: var(--mainColor);
}

As all CSS, the names are case sensitive, so theBox is different from TheBox.

CSS Inheritance

CSS variables declaration has the same rules as all the CSS inheritance. You can define global variables on the “:root” CSS pseudo-class that identifies the document.

:root{   --globalVar:red;   }// will work everwhere
p { --innerColor:blue; }// will work only within P

div {color: var(--innerColor);}
p {color: var(--innerColor);}
span {color: var(--globalVar);}

<div>
Sone black text
<p>
Some blue text
<span>
Red text
</span>
<p>
<div>
:root { --color:red;  }
div { --color:green;}
p { --color:blue; }
a { --color:pink; }

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

I am red root
<div>
I'm green div
<p>
Look at me, I'm the blue P
<a>
Pink! why? God tell me why?
</a>
</p>
</div>

Fallback

The CSS var() function has a second variable for fallback value.

div p a{
--someColor: pink;
}
p {background:var(--someColor, blue);}
a {
// Or just in case:
background: var(--val1,var(--val2,var(--val3,var(--val4,var(--val5,red)))))}
<p>
Since we have inheritance limitation, this will be blue text
<a>
And this will be red
</a>
</p>


Single tokens

It is possible to use CSS variable as a single token. Just be aware that the variable adds a space after the token:

:root {
--size: 1.4
--border: 2.2rem
}
div {
font-size: var(--size)rem; // Invalid value -> font-size:1.4 rem
border: solid var(--size)red; // Will work -> border: solid 2.2rem red
}

There is still an option to use single token by taking advantage of the CSS calc() function:

:root {
--size: 1.4
}
div {
font-size: calc(var(--size) * 1rem); // font-size: 1.4rem
}

Invalid variables

After all the happiness, there is one downside you need to know. The CSS variable validation comes before the CSS variables are placed, this means that you can place invalid values into CSS attributes.

 p {
border: solid 1px red;
}
div p {
border: moshe;
}

<div>
<p>

since moshe is invalid, the P will
have the CSS "p" less specific red border

</p>
</div>

// vs
*{
--errorColor: moshe;
}
p {
border: solid 1px red;
}
div p {
border:var(--errorColor);
}

<div>
<p>
Because the CSS variables bypass the CSS
validation, the "p" will nave the invalid
"moshe" border, and will display no border.
</p>
</div>

Last words

Unless you are for some reason using some type of atomic CSS approach, never call a red color red, call it by its use

:root {
--redColor: #ce1616; // Something red'ish
--blueColor: blue;
--greenColor: #16ce34; // Something green'ish
}
.title {
...
...
color: var(--redColor);
background: var(--greenColor);
...
...
}

I can promise you that one day the product manager will announce that we change the site layout to new colors, and you will end out having something like this:

:root {
--redColor: #16ce34; // Something green'ish
--blueColor: #ce1616; // Something red'ish
--greenColor: blue;
}

Believe me, I had seen it again and again. Whatever approach you use for the CSS convention, don’t compromise on the Better use the functional naming.

:root {
--textColor: #ce1616; // Something red'ish
--titlesColor: blue;
--mainBackgroundColor: #16ce34; // Something green'ish
}
.title {
...
...
color: var(--textColor);
background: var(--mainBackgroundColor);
...
...
}

Conclusion

Where has the CSS variables been all this time?