loading...

"currentColor", the first CSS variable

kenbellows profile image Ken Bellows ・7 min read

The recent addition to CSS of Custom Properties, a.k.a. CSS variables, was a very welcome addition to the language. It's opened the door for a lot of really cool techniques; there's a lot that you can only do when you can keep track of the state of your system and keep different bits in sync with each other, and variables give you a way to do that.

But here's something that developers newer to CSS may not know, and those who've been around often forget: we've actually had another variable in CSS since long before Custom Properties came on the scene. It's much simpler, and limited in scope, so it can't do everything Custom Properties can do, but it's way better supported, and with a bit of cleverness it can be used to accomplish some pretty cool stuff.

This variable is the special CSS keyword currentColor!

What is it?

The currentColor keyword is basically what it sounds like: it's a special keyword that holds the value of the color property at the location where it's used.

So for a very simple example, you can use it to make a pull quote box with a border that's the same color as the text in the box:

blockquote {
  color: hotpink;
  border-color: currentColor;
}

Snazzy, I think.

Interestingly though, in this particular case, the border-color rule is unnecessary. I always thought that the default border-color value was black, or else was set by the browser, but I recently discovered by accident that it actually defaults to currentColor! So if border-color just isn't specified, it will use hotpink by default!

Several properties actually default to currentColor:

By the way, I didn't know about almost any of those rules before I looked up which rules default to currentColor! I need to read more about text-emphasis; it's really weird and interesting. Man, every time I dive into the docs to find something specific, I end up learning about something unexpected.

Browser support

Of course, the first question you should ask whenever you learn about a cool feature of the web platform that you've never seen before is, "How good is its browser support? Can I actually use it?" Fortunately, the answers for currentColor are "super good" and "yes!"

Support actually goes back a really long time. Taking a look at caniuse.com's overview of support, it's supported in every version of Edge, it's been in Chrome and Safari since version 4 (back then they used the same engine under the hood), and it's been in Firefox since version 2! Heck, it's even in Internet Explorer all the way back to IE 9! So don't worry about using it unless you're writing an intranet application for an organization that still hasn't upgraded past IE 8. (Tragically, I'm very aware that they still exist 😢)

Demo: Badges

Okay, let's get practical.

I discovered currentColor while investigating the best way to implement a design for work. I needed to create a row of colored badges, each with a label on the badge and a numeric counter next to it. The background color of each badge matched the text color of its counter, and the label on each badge was colored to match the site background. For the sake of example, suppose the mockup was something like this:

Three colored badges with white text in a horizontal row, each followed by a number whose text color matches the badge color: a red "Errors" badge followed by 123, a yellow "Warnings" badge followed by 45, and a green "Successes" badge followed by 12345

Each of those badges is identical, but for the color. Seems like a good use case for a reusable component! In a modern browser, you could use a CSS variable for the background of the badge and the foreground text color of its counter. But suppose you want/need to support IE 11, Edge 12-14, or another browser that doesn't support custom properties. Or maybe you already have some utility classes in your CSS to define text colors for various situations, like Bootstrap's contextual color classes, e.g. .text-danger and .text-warning, so the idea of using the color property to set the badge color is super convenient. How might you go about it, armed with your new knowledge of currentColor?

First we'll need a root wrapper element for the component. This is where the color will be set, and it's where you'd add a class to override the color.

<div class="badge">
</div>
.badge {
  display: inline-block;
  color: cornflowerblue;
}

So what needs to be inside the badge component? Well, at first glance there are two regions: the bit with a colored background and white text, which I'll call the title block, and the digits off to the side that are colored to match the title block's background, which we've been calling the counter.

The title block definitely needs its own block in the DOM, since it has a background color, but the counter probably doesn't, since it's just sitting off to the side, which is what inline text does anyway. So lets try this markup:

<div class="badge">
  <div class="title-block">
    Things
  </div>
  12345
</div>

Now the fun part! We want the background of the .title-block to match the color specified on the .badge, so we can use background: currentColor! We also want to set the .title-block's text to white, according to our mockup, so let's add color: white as well. (If you've spotted the problem here, no spoilers!)

.title-block {
  display: inline-block;
  padding: 0.5rem;
  background: currentColor;
  color: white;
}

Great! Let's see how it looks:

Ah. Well. That's not what we wanted at all. The title block seems to be missing... or rather, it's completely white. Why is that?

Well, here's the thing: CSS is a declarative language, not an imperative one: it doesn't run top-to-bottom, keeping and updating state along the way. What this means is that when we write:

.something {
  background: currentColor;
  color: white;
}

the browser doesn't figure out currentColor's value, then set color: white. Instead, setting color: white changes the value of currentColor for the background to white as well! This is a limitation of currentColor that you need to keep in mind.

It's an easy enough fix, if a little annoying. We just need another layer of nesting to encapsulate the color: white rule. CSS rules often inherit downward to children, but never upward to parents, so this lets .title-block inherit its currentColor value from .badge, while being able to change the color within its child.

<div class="badge">
  <div class="title-block">
    <span class="title-block-text">
      Things
    </span>
  </div>
  12345
</div>
.title-block {
  display: inline-block;
  padding: 0.5rem;
  background: currentColor;
}
.title-block-text {
  color: white;
}

Now let's take another look:

Perfect!

Now that we've got our component, all we need to do is repeat it a few times and define a color-override class for each be instance.

<div class="error badge">
  <div class="title-block">
    <span class="title-block-text">
      Errors
    </span>
  </div>
  123
</div>

<div class="warning badge">
  <div class="title-block">
    <span class="title-block-text">
      Warnings
    </span>
  </div>
  45
</div>

<div class="success badge">
  <div class="title-block">
    <span class="title-block-text">
      Successes
    </span>
  </div>
  12345
</div>
.error {
  color: red;
}
.warning {
  color: goldenrod;
}
.success {
  color: green;
}

Awesome! We met the requirement!

And this little badge component is pretty handy; there's still more to play with. We can try different colors, put emoji in the title area, add a background color to the counter area... Lots of possibilities!

What else can you come up with?

Conclusion

To recap: there's a cool, undervalued keyword in CSS, currentColor, that can be used as a variable of sorts for certain use cases. It has much more broad support than CSS Custom Properties (a.k.a. CSS variables), and it is perhaps a bit more intuitive to use when developing a reusable component, since you only need to set the color property to populate it's value, which feels very nice.

However, it's clear that currentColor has limitations. The most glaring when comparing to Custom Properties is that it's only a color value, so it can't be used to store length values, image URLs, or fancy gradients. The other main point of caution is that you can't use an inherited color value in currentColor, say for the background or border color, while also setting your own color for text in the same block; setting color will update the value of currentColor everywhere within that block. You need to introduce a child element to keep your color value in a new scope.

So in short, it has limits and caveats, but I personally have found currentColor to be very useful, and it has let me write much cleaner code in a few tricky situations. My absolute favorite feature is just being able to set color on a root element of a component and see the whole thing update. Give it a try, see what you can do with it!

Posted on by:

kenbellows profile

Ken Bellows

@kenbellows

Full-time web dev; JS lover since 2002; CSS fanatic. #CSSIsAwesome I try to stay up with new web platform features. Web feature you don't understand? Tell me! I'll write an article! He/him

Discussion

markdown guide
 

Thanks for writing this up, this is really interesting! I love deep dives like this into things I've never really paid much attention to.

I also really like how you walk through the steps of how you'd expect things to work, which includes running into issues and figuring out what you need to fix to make it work. It makes it much easier to understand how things work, and why you might need to write things a specific way.

Looking forward to future posts!

 

Thanks! 😁 I usually find that working through weird errors and unexpected behaviors is the best way to really learn the details of a feature, so I like to show that. I'm glad someone else appreciates the approach!

 

My favorite use of currentColor is setting an outline (or border) color on anchors in focus. A quick win to improve keyboard accessibility. For example: a:focus {outline: 3px dotted currentColor;}. Cheers!

 

Awesome article! One thing bothers me (a lot): it should be called current-color like everything else in CSS

 

Ha, I know what you mean, it does seem a little inconsistent. But it actually follows the standard pattern for color names, like "MediumVioletRed", "DarkOliveGreen", or "RebeccaPurple". CSS treats these names case-insensitively, so I actually write all lowercase currentcolor most of the time.

 

Man, every time I dive into the docs to find something specific, I end up learning about something unexpected.

Same.

 

interesting! I wasn't aware this is something from CSS. Thanks for digging and sharing it with us.