Dynamically theme-able websites using CSS currentColor

— 3rd of July 2016

First of all, what is currentColor?

CSS currentColor is exactly what is sounds like. It will take the elements' current computed color value and allow other properties to use it.

Using currentColor to create themeable content

If you set the color on the html or body elements you can pick and choose different elements to use the currentColor as one of their properties. If you then let people change that value, all of the elements using the html's currentColor will update too.

I'm not going to re-create the whole demo in this post, just some of the techniques used when creating it.

Change the color being inlined on the html element below to see it in action.


1. Basic usage

I'm going to create a div nested inside another div, set the parent's color to blue, and then set the child elements' background to currentColor. Just so we can see what happens.

<div class="div-1">
  I'm blue
  <div class="div-2">
    da ba dee da ba die
  </div>
</div>
.div-1 {
  color: blue;
}

.div-2 {
  background-color: currentColor;
}

Aaaaand the result:

I'm blue
da ba dee da ba die

Booyah.

Well, it's working, but it doesnt seem to be too useful. What's the point of setting the background color to the text color, you can't see anything...

If we set the color of div-2 to white, It'll have a blue background because of its parent, and the white text will make it legible again, right?

I'm blue
da ba dee da ba die

wrong.

Because the color of the element has changed, so has the currentColor property.

The way I fix this is putting a span inside whatever element I want to set the background of. That span will ensure the text stays white without changing the currentColor of the div with the blue background

<div class="div-1">
  I'm blue
  <div class="div-2">
    <span class="white">
      da ba dee da ba die
    </span>
  </div>
</div>
.div-1 {
  color: blue;
}

.div-2 {
  background-color: currentColor;
}

.white {
  color: white;
}

Aaaaand the result:

I'm blue
da ba dee da ba die

Woooo! And if the text color of div-1 changes?

I'm blue
da ba de... oh.

oh yeah

This is essentially all I've done for 90% of that demo.


Lightening and darkening the currentColor

This one would be a walk in the park in sass land with lighten() and darken(), but, we're not in sass land. No nesting, no loops, no mixins and no color functions. But what about the button in the demo? well...

background-image: linear-gradient to the rescue!

because gradients are background images, and an element can have both background-color and background-image, and the background-image always sits infront of the background-color, if we set the background-image to a linear-gradient that uses two identical rgba() values (so the gradient is a solid color) we can have a semi-transparent overlay above the color, effectively darkening it.

Instead of putting a span in my earlier example and making the text white, I'm going to darken the background with a translucent gradient.

<div class="div-1">
  I'm not blue anymore
  <div class="div-2">
    and I'm somewhat legible again
  </div>
</div>
.div-1 {
  color: red;
  background-color: #f2f2f2;
}

.div-2 {
  background-color: currentColor;
  background-image: linear-gradient(
    -180deg,
    rgba(0,0,0,0.50) 0%,
    rgba(0,0,0,0.50) 100%
  );
}
I'm not blue anymore
And I'm somewhat legible again

This is how I created the hover states, the artwork under the hero, and the lightened and darkened sections.

Instead of using 20% black, try using 80% white, or other colours and blend modes for different effects.

Bonus artwork demo:
four semi-transparent divs sitting in a div with a currentColor background giving the illusion of the color darkening

.artwork {
  display: flex;
  width: 100%;
  height: 3em;
  background: currentcolor
}

.artwork > * {
  width: 25%;
  height: 100% 
}

.one   { background: rgba(0,0,0,0.1) }
.two   { background: rgba(0,0,0,0.3) }
.three { background: rgba(0,0,0,0.5) }
.four  { background: rgba(0,0,0,0.7) }


Go forth and theme-ify

You can use currentColor to fill an SVG, set backgrounds, borders and whatever else you might want to do with it. It's exactly the same as using a color.

Fill SVG's

svg {
  fill: currentColor;
}

Blend currentColor with an image

.blend {
  background: currentColor url('image.jpg');
  background-size: cover;
  background-blend-mode: multiply;
}

Set the border of an active menu item link?

li.active {
  border-bottom: 3px solid currentColor
}