Using The LESS CSS fade Method To Apply Opacity To A HEX Color
When I define colors in my CSS (Cascading Stylesheets), I use HEX (Hexadecimal) values. Like #FF0099. To me, this is familiar and easy to read and to reason about. The only time I ever switch from HEX notation over to RGB notation is when I need to add an alpha-channel for opacity. Recently, however, while listening to the Syntax Podcast on CSS, Wes Bos dropped a tasty treat on me: LESS - my CSS preprocessor of choice - has a fade() method that will allow me to apply an opacity to a HEX value, resulting in an RGBa notation. This is awesome!
Run this demo in my JavaScript Demos project on GitHub.
To see this in action, I put together a tiny Angular 4 demo that renders a number of "faded" blocks over an image. In this case, I'm using Angular because I'm it's easy in my local setup; but, there's nothing about the use of fade() that requires Angular - you just need some sort of pipeline that will process your LESS files and generate CSS files. Here's my HTML markup:
// Import the core angular services.
import { Component } from "@angular/core";
@Component({
selector: "my-app",
styleUrls: [ "./app.component.less" ],
template:
`
<div class="pattern">
<!--
This container will be UNDER the blocks (positioned absolutely) and will
contain a pattern that will show through the opacity of the blocks.
-->
</div>
<div class="blocks">
<div class="block block-100">
#FF0099 - 100%
</div>
<div class="block block-80">
#FF0099 - 80%
</div>
<div class="block block-60">
#FF0099 - 60%
</div>
<div class="block block-40">
#FF0099 - 40%
</div>
<div class="block block-20">
#FF0099 - 20%
</div>
<div class="block block-0">
#FF0099 - 0%
</div>
</div>
`
})
export class AppComponent {
// ...
}
In this Angular component, I have a "pattern" container and a "blocks" container. Both of these containers are going to be absolutely-positioned with the pattern container at a lower zIndex. This way, more or less of the pattern will show-through depending on the relative opacity of the blocks.
Now, let's look at the .less file associated with this demo component:
:host {
display: block ;
font-size: 16px ;
}
.pattern {
background: url( "./goose-duck.jpg" ) ;
height: 300px ;
left: 20px ;
position: absolute ;
top: 90px ;
width: 300px ;
z-index: 2 ;
}
.blocks {
left: 20px ;
position: absolute ;
top: 90px ;
width: 300px ;
z-index: 3 ;
}
.block {
color: #FFFFFF ;
height: 50px ;
font-family: sans-serif ;
font-weight: bold ;
line-height: 50px ;
text-align: center ;
transition: background-color 200ms ease ;
// With the fade() method, you can apply an opacity to a HEX value!!
&-100 {
background-color: fade( #FF0099, 100% ) ;
}
&-80 {
background-color: fade( #FF0099, 80% ) ;
}
&-60 {
background-color: fade( #FF0099, 60% ) ;
}
&-40 {
background-color: fade( #FF0099, 40% ) ;
}
&-20 {
background-color: fade( #FF0099, 20% ) ;
}
&-0 {
background-color: fade( #FF0099, 0% ) ;
}
&:hover {
background-color: fade( #FF0099, 100% ) ;
}
}
Notice that the background-color of my blocks are all being defined with the LESS CSS fade() method and a HEX value. For example:
background-color: fade( #FF0099, 100% ) ;
And, when we run this app in the browser, we get the following output:
As you can see, our use of the LESS CSS fade() method was able to convert the HEX value into an RGB value with an alpha-channel.
This may seem like a really minor thing; and, in the grand scheme of things, it is. But, by using fade() in my LESS CSS pre-processor styles, it probably means that I never have to switch over to RGB notation. Now, I can keep my color values consistent. And, for me, consistency brings happiness. Thanks Wes Bos for your tasty treats!
Want to use code from this post? Check out the license.
Reader Comments
This doesn't fit perfectly with this article, but it prompted me to share this nonetheless...
You can get CSS colors in "rgb(R,G,B)" format regardless of how they were set using the pure JS function window.getComputedStyle(element). What's super cool about that is, you (or your users) can specify colors in hex, rgb or even HTML color names like "magenta" or "deepskyblue" and this function will return the rgb() format every time.
Then, it's easy to grab the rgb values with a regex and add an alpha value on the fly.
//set an element's background color to an HTML color name
element.style.backgroundColor = "chartreuse";
//get the computed value for the background color
//this will be in the format rgb(R, G, B) or rgba(R, G, B, A)
var bg = window.getComputedStyle(element).backgroundColor;
//extract the rgb values with a regex
var c = bg.match(/rgba?\((\d+),\s+(\d+),\s+(\d+)/);
//set the alpha value to 0.5
element.style.backgroundColor = "rgba("+c[0]+","+c[1]+","+c[2]+",0.5)";
I thought that was pretty cool. I know in the past I have written functions to convert hex color codes to decimal rgb values, and lookup tables for common color names in order to manipulate them, but that's actually not necessary.
Note that CSS has an 8-digit hex notation, where the last two digits represent the alpha value. It is supported in Safari, Firefox, and soon Chrome, and you can use it via the PostCSS plugin (I do, works great).
@Šime,
Oh very cool - I had no idea. I'll keep my eye open for stronger support. That said, I am not sure that a two-digit HEX value for Alpha is a human-friendly as a % value (ex, "7F" vs. "50%").
@Darren,
Very interesting. I am not sure I've ever used the getComputedStyle() method before. I'll take a look. But, I like it :)