About RGB, HSL, LCH and LAB function colors

Table of contents

These past days I notice more and more comments about the newest functions in CSS to declare colors, introduced in the current working draft (level 4) document about the color standard. Although it is not a recommendation yet and the support by the browsers is very insignificant, it is supposed to go on.

Since the document is so wide we will focus on understand why this step has been taken and how some new functions works


Sure you are used to declare CSS colors using the hexadecimal notation, rgb or hsl functions or named colors.

Perhaps you use one of the variants that let us modify the opacity of the color, which in many cases is totally needed.

Well, it does not matter which one you use because your browser uses rgb() under the hood. Go and check it by yourself on the computed tab at the inspector of elements devtool. Then, the differences between all these methods seems to be syntactic sugar.

Capture of the devtools panel

Named colors

It is the easiest notation due to it is exactly the same as how we speak. In despite of it is very used for quickly examples, it is not in real life (on production) mostly because the colors are predefined and we must memorize them and being lucky enough to have a palette scheme that matches with these colors which is something odd however the list of available colors are so wide. To be honest, this is one of the reasons but there are more like the system has some inconsistencies that could lead us to errors, such as darkgray which is lighten than gray or lightpink which is darken thatn pink.


The rgb() function let us declare a color destructured in its lights Red, Green and Blue. The output is the sum of the lights.

The rgba() function uses the alpha channel to handle its opacity.

Each of the arguments of the function is a channel, and could have a value between 0 and 255 (both included), but alpha, which should be between 0 and 1 (both also included).

Although this notation is also very popular, it is difficult for us as authors to understand at a first glance which color will be outputted.

.element {
	color: rgba(255, 0, 102, 1);


It is very similar to rgb. With this notation we indicate which value has the color in its three different channels, but despite being equal, this syntax is more used since it is shorter, easier to write (no commas neither parenthesis which result in few possibilities to fail writing).

Its formula consists of a ‘#’ followed by 3, 4, 6, or 8 digits that could take values between 0 and 9 or characters from A to F (no case-sensitive).

The 3-digit notation is the shorthand for the 6-digit notation, and it is possible to be used when each pair of values are the same.

On the other side, the 4-digit notation is the short form of the 8-digit formula, and the difference is that in this case we specify the alpha channel.

.element-A {
	color: #ff0066;

.another-element-A {
	color: #f06;

.element-B {
	color: #ff0066ff;

.another-element-B {
	color: #f06f;


The hsl function is the easiest to understand and guess what color we are referring since each channel is not a color but a reference to concepts about the real perception: hue, saturation and lightness.

The hue is the color. All possible colors are within a circle and its value is expressed in degrees. 0 and 360 correspond to red, 120 to green, and 240 to blue. So remembering these 3 references it is easy to approximate the value you want to use.

Hue wheel

Saturation is the vividness of the color, its power. And it is expressed as a percentage between 0 and 100.

Luminosity is its clarity. It is also expressed as a percentage between 0 and 100. The brighter it is, the closer to white it will be.

Similar to the case of rgba (), the hsla () function uses the alpha channel to express a variation of its opacity.

.element {
	color: hsl(336deg, 100%, 50%, 1);

Nothing is more comfortable than copying and pasting from Figma or Sketch, but if we have to reference a new color, the hsl() notation is the easiest way to know what color we choose and escaping at the same time from predefined colors


However, all the notations we use to declare colors (it doesn’t matter which one) work in the sRGB color space. A model that simplifies its representation on the screen, but that has inconsistencies related to how people actually perceive colors. This means that the same levels of saturation and luminosity on different hues make us perceive some colors more luminous or vivid than others (as occurs with yellow and blue), however in nature, if levels of saturation and luminosity are the same, we would not perceive none of them more vivid than another.

.element {
	color: hsl(53deg, 75%, 55%);

.another-element {
	color: hsl(228deg, 75%, 55%);

Is in this context that the CIE LAB color space gets into play, a model that represents colors more closely to our perception, and the new functions that use this new model appear.


The argument “l” refers to the luminosity, but it is not like the L in hsl, but CIE Lightness, and it is expressed as a percentage between 0 and 100.

Arguments “a” and “b” are positive and negative values ​​ranging from -160 to 160, and refer to the distance between the axes “a” and “b” in the Lab color space.

The fourth argument is for manipulating the alpha channel separated by the slash (/) character, as in the rgba() function with the new notation.

.element {
	color: lab(54.25% 82.88 -18.86 / 1);

You may have noticed in the inspector of elements that the arguments are separated with spaces instead of commas on the color functions, and at the same time also separated with a slash from the alpha channel. This is the new notation.


The argument ‘l’ is like that of the function lab (), instead, the second and third parameters are quite different.

‘c’ argument is the chroma or amount of color, and its value ranges from 0 to 230.

‘h’ argument is the hue and it is similar to <hue> in the hsl () function. It can take a value between 0 and 360 and although it does not have a unit, we can understand it as a circle that is completed counterclockwise, that is, the values ​​0, 90, 270 and 360 would be projected on a cartesian coordinate axis, so the value 0 being the positive part of the ‘a’ axis (purple red), 90 the positive of the ‘b’ axis (mustard yellow), 180 the negative of ‘a’ (greenish cyan) and 270 the negative of ‘b’ (sky blue).


The fourth argument is reserved for the alpha channel, separated from the rest of the arguments by a slash following the new notation.

.element {
	color: lch(54.25% 85 12.82 / 1);


We will probably start using these new functions since they seem to improve the current ones, but it is better not to go crazy, if we have reached until this day without big deals in the construction of color palettes we should not suddenly lose our minds.

We probably found difficulties when using automatic palette generators due to the sRGB mode implicit defect, but nothing that could not be solved by correcting the saturation and luminosity of a specific color. That is, if we generate our palette randomly or if we work on an application to distribute with different themes (themes or skins), we must carefully evaluate these new themes, since depending on the hue, this defect can lift or sink the interface, its contrast, and consequently cause accessibility problems.

As we said, the specification is much broader and brings new functions such as device-cmyk (), or color () among others, in addition, it incorporates new predefined color spaces that can be used, such as display-p3 or rec2020 but I think it is enough for the moment, and when the support is better and we can test everything comfortably, it will be time to get more conclusions.

Know more

comments powered by Disqus

If you find it interesting

If you have any doubt or you want to talk about this topic, if the content or our profiles are interesting to you and you think we could something together, do not hesitate to contact us on twitter or trough the email address hola@mamutlove.com