HSB Colors with Sass

Alexander Futekov

Why do we need another color model you might ask? And it is a fair question, considering we already have RGB, HSL, and hex and we’re doing just fine. To convince you, I will tell you why HSB is awesome and how you can easily implement it in any Sass project.

Why HSB?

The HSB/HSV color model is actually a close kin of HSL. HSB stands for Hue, Saturation, and Brightness, the Hue component being equal to the one in HSL.

HSB colors, just like their cousin HSL, have some nice advantages over RGB and Hex — they allow you to quickly identify a color by seeing how saturated and bright it is, Chris Coyier also tells us why HSL is cooler and Dudley Storey has a nice visual guide on how to think about HSL colors. All of these pros apply equally well to HSB.

In addition, Karen Menezes wrote a helpful article on how to think about color modifications with a great section about the HSL model. HSL even has its own mother-effing site.

This easy-to-understand-at-a-glance factor isn’t present in RGB and hex — just try to imagine what rgb(173, 149, 128) or #ad9580 look like.

Also, if you need some level of transparency for a color, hex is no longer an option; you have to choose between RGBa and HSLa (and now HSBa).

HSB colors are also more readily available for use than HSL if you choose/get your colors from graphics software. Programs such as GIMP or Adobe’s Photoshop and Illustrator all prefer the HSB color model to HSL.

Having that foundation, let’s see how we can use HSB in a Sass project.

Building the Function

Adding support for HSB colors in your project is easy. We will define an HSB function, so that later we can use it just like HSL or RGB colors:

color: hsb(333, 84, 76)

This function will accept 3 or 4 parameters, the fourth one being the alpha channel, which we will set to 1 (fully opaque) by default:

@function hsb($h-hsb, $s-hsb, $b-hsb, $a: 1)

On the inside, the function will convert the HSB color to HSL (it’s the easiest conversion mathematically speaking). Sass will output the color in its Hex equivalent (or RGBa if the color has transparency) no matter the format you provide the input color in. Other preprocessors work the same way.

The Hue component doesn’t need to be converted, since it’s the same for HSB and HSL. To get the other components though, we need some math.

Deriving the Luminosity of the HSL equivalent to our HSB color is done with a simple equation:

$l-hsl: ($b-hsb/2) * (2 - ($s-hsb/100));

And this is how we calculate the HSL Saturation:

$s-hsl: ($b-hsb * $s-hsb) / if($l-hsl < 50, $l-hsl * 2, 200 - $l-hsl * 2);

The if statement is there for the proper behavior of the saturation, which starts to decrease once the lightness of the HSL surpasses 50%. Here is a more detailed explanation.

In the end, we simply return the new value:

@return hsla($h-hsb, $s-hsl, $l-hsl, $a);

Okay, now we have all 3 components: Hue, Saturation, and Luminosity. But our code isn’t flawless yet. Our function will fail if the third parameter (the Brightness, or $b-hsb) is 0 because we cannot divide by zero. Happily for us, having a brightness of 0 in HSB means that the output color will always be black, no matter what the other two parameters are.

Therefor, the best way to resolve this issue is to add a condition to our function that automatically outputs black if the brightness is zero:

@function hsb($h-hsb, $s-hsb, $b-hsb, $a: 1) {
  @if $b-hsb == 0 {
    @return hsla(0, 0, 0, $a)
  } @else {
    $l-hsl: ($b-hsb/2) * (2 - ($s-hsb/100));
    $s-hsl: ($b-hsb * $s-hsb) / if($l-hsl < 50, $l-hsl * 2, 200 - $l-hsl * 2);
    @return hsla($h-hsb, $s-hsl, $l-hsl, $a);

And we’re done. Check out the demo that includes some test cases:

See the Pen HSB Color Function with Sass by SitePoint (@SitePoint) on CodePen.

Alternatively, if you prefer the Stylus preprocessor, you don’t have to feel left out.

A Final Note on Precision

Keep in mind that the color picker of Adobe Photoshop (and other graphics software) does some rounding when calculating the equivalent HSB of a certain Hex color. This happens because these different color models allow for different precision for its color components.

An example of the rounding issue is shown in the CodePen above, under .test-precision, where a hex color from Photoshop outputs rounded HSB values, and if you put these rounded values in an HSB to hex converter (for example the one we just built) we might get a slightly different hex color than the original (the difference however, is imperceptible).

If you play around with this awesome color converter you will see that the HSB/HSV equivalent of most hex and RGB colors doesn’t have all its components nicely rounded like we’re used to seeing in Photoshop. This is the tool I’m recommending if you happen to need precise colors or just want to avoid this rounding issue for Zen reasons.