loading...

Learn About CSS Custom Properties Through Clever Uses of Them

chriscoyier profile image Chris Coyier ・4 min read

One of the biggest use-cases for CSS custom properties is theming. Let's consider that for a second. Perhaps you'd set some variables at the highest level you can:

html {
  --column-bg: #ae0001;
  --menu-bg-hover: #680001;
  --active-item: #D3A625;
}

/* Anywhere else in the CSS, you use the variables */
.menu:hover, .menu:focus {
  background: var(--menu-bg-hover);
}

Then if you want to change the theme, you have the opportunity to do that in one isolated place, which makes things tremendously easier to reason about. Here we'll allow a class change on that root element to change the variables. Anywhere those variables are used will instantly update.

html {
  --column-bg: #ae0001;
  --menu-bg-hover: #680001;
  --active-item: #D3A625;
}
html.alternate-theme {
  --column-bg: #680001;
  --menu-bg-hover: #BE0002;
  --active-item: #00FFBA;
}

/* Anywhere else in the CSS, you use the variables */
.menu:hover, .menu:focus {
  background: var(--menu-bg-hover);
}

Here's a wonderful use of theming by Stephanie Liu. It's a recreation of the Slack interface's theming capabilities

Above, I showed how you might alter the values of CSS custom properties by changing a class, but JavaScript is capable of changing those variable values directly by selecting the element and passing a new value to it, like el.style.setProperty("--custom-property", "new-value");, which is how Stephanie is doing it in this demo.

Like any good theming, a user's choice should persist. Stephanie handles this in this demo by plopping the selections into localStorage, so check out her JavaScript to see how she's doing that.

Adjusting Theme Colors

Another consideration with CSS custom properties being in control of color themes is that sometimes you want a variation of a color, rather than having to pick a whole new second color. Like a button with the chosen color as a border, but a faded version for a background.

In a post by Ben Szabo, Theming with CSS variables in RGBA, he mentions you could use RGBa or HSLa to make those adjustments with opacity.

img

If the original color is in RGB or HSL to begin with, the opacity adjustment is easy:

:root {
  --my-color-rgb: 255, 0, 0; 
}

.btn {
  border: 1px solid var(--my-color-rgb);
  background: rgba(var(--my-color-rgb), 0.5);
}

I did a demo once where I laid a transparent black gradient over top the color to darken it, so it's not just lightening you can do but darkening as well:

Ana Tudor showed us we can make drastic changes to styling with the flip of a CSS custom property toggle.

She called it DRY switching.

The trick is rooted in math and the power of 0 and 1. With calc(), we can multiple values by zero and one and either get nothing or the original value. We can use that base trick for colors, positions, transforms... all kinds of stuff to get hugely different results when that flip is switched.

Interesting SVG hovers from Marius Niveri

I like this concept in which normal colored SVG has it's color temporarily removed with CSS, moved to a custom property, and then re-applied on hover. Like progressive enhancement coloring!

Keith Clark combined them with conic gradients to make pie charts

Pass the percentage in right from the markup:

<div class="pie pie--value" style="--percent:65;"></div>

Then use that value in a conic-gradient to draw the pie chart.

.pie {
  background-image: conic-gradient(
    rgba(0,0,0,0) calc(3.6deg  var(--percent)),
    rgba(0,0,0,1) calc(3.6deg  var(--percent))
  );
  background-blend-mode: overlay;
  background-position: 50% 50%;
  background-size: 150%; /* oversize bg image to prevent "underdraw" */
  width: 3.75em;
  height: 3.75em;
  border-radius: 50%;
}

Keith's demo is fancied up:

He's even got a bonus trick in there of using CSS counters to display the percentage value.

Sérgio Gomes aspect ratio trick with custom properties

What if you could tell an HTML element directly what aspect ratio you wanted it to be? That's documented here. You pass in a ratio directly from the a custom property on the element:

<div style="--aspect-ratio:16/9;">
</div>

Then use that value to apply a perfectly sized psuedo element inside that pushes it to that size.

[style="--aspect-ratio"] > :first-child {
  width: 100%;
}
[style="--aspect-ratio"] > img {   height: auto;
} 
@supports (--custom:property) {
  [style="--aspect-ratio"] {
    position: relative;
  }
  [style="--aspect-ratio"]::before {
    content: "";
    display: block;
    padding-bottom: calc(100% / (var(--aspect-ratio)));
  }
  [style*="--aspect-ratio"] > :first-child {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
  }
}

Clever stuff.

Posted on by:

chriscoyier profile

Chris Coyier

@chriscoyier

Writing at [CSS-Tricks](https://css-tricks.com), podcasting at [ShopTalk](https://shoptalkshow.com), co-founder of [CodePen](https://codepen.io).

Discussion

markdown guide
 

We're actually in the process of rolling out CSS variables on this site for the purpose of theming

[WIP] Theme-able CSS Variables #1377

I thought we ought to have a place where we keep a note of the current CSS Variables and also propose different variables that should be included.

Currently included:

Variable Description Default
--theme-background Background color of the main body #f9f9fa
--theme-top-bar-background Background color of the top bar #fdf9f3

Pull request pending:

Variable Description Default
--theme-top-bar-color Text and icon color for the top bar #0a0a0a
--theme-top-bar-search-background Background color of the search box in the top bar #e8e7e7
--theme-top-bar-search-color Text color for the search box, and its placeholder, in the top bar #0a0a0a

Proposed:

Variable Description Default
--theme-color Text color for the main body #0a0a0a
--theme-container-background Background color of the articles and nav-elements #ffffff
--theme-container-color Text color for the articles and nav-elements #0a0a0a

I think the best thing to do is leave a comment below of further proposals and I will update the main post.

Also feel free to do pull requests to help roll these out.

If you'd like to contribute that would be greatly appreciated 🙂

 

Nice, I'm sure a lot of us would love a dark theme. I've been using the extension DarkReader at night, but it does not play nicely with dev.to so I've been waiting for a built-in option.

 

Custom properties look fairly straightforward to get started with. Your first example looks easy to implement for anyone familiar with CSS.

I'm glad to see that CSS is closing the gap with CSS preprocessors a little bit. Learning and configuring tools to transpile code can get a bit overwhelming at times.

 
 

Good things and useful to know.....