XenonStack Recommends

Data Visualization

Understanding CSS Custom Properties | Ultimate Guide

Navdeep Singh Gill | 07 March 2022

CSS Custom Properties

What are the CSS Custom Properties?

CSS variables (also known as cascading variables) are elements specified by CSS writers with specific values that can be reused across a document. They're specified with custom property notation (for example, —main-color: black;) and accessible with the var() method (for example, color: var(—main-color);).
Complex websites need a lot of CSS, and there are a lot of repeated values. For example, if the same color is used in hundreds of different places, a worldwide search and replace operation is required if the color needs to be changed. A value can be saved in one place and then referenced in several places using custom properties. An additional benefit is semantic identifiers. —main-text-colour, for example, is easier to grasp than #00ff00, especially if the same color is used elsewhere.

CSS font size adjusts all the measurement units in which font sizes are present, like rem, em, px and viewport units. Click to explore about, CSS Size Adjust for Font Face

Why should we use CSS Custom Properties?

  • They assist in making your CSS more DRY. "Don't Repeat Yourself," as the saying goes. Because you can alter one value and reflect it in several locations, custom properties make code easier to manage. But be careful: too much abstraction might backfire and make code less intelligible.
  • They're very useful for things like designing website color schemes.
  • They open up new CSS options. They're not just because they're cascading, but they're also because they're complicated.
  • The fact that they can be modified using JavaScript expands the possibilities further.

Naming CSS Custom Properties

Custom properties must start with two dashes (--) and must be included within a selector:

It's best to use letters, digits, and dashes and make sure the custom property is declared within a valid selector.

/* Nope, not within a selector */
--foo: 1;

body {
/* No, 0 or 1 dash won't work */
foo: 1;
-foo: 1;

/* Yep! */
--foo: 1;

/* OK, but they're different properties */
--FOO: 1;
--Foo: 1;
/* Totally fine */
--mainColor: red;
--main-color: red;

/* Special characters are a no */
--color@home: red;
--black&blue: black;
--black^2: black;
}

The most impactful CSS in which we can stop the rendering of the elements and reduce the paint and layout shift time. Click to explore about, CSS Content Visibility Property to Boosts Rendering Performance

CSS Custom Properties as Properties

Some users prefer doing it this way:

html {
--red: #a24e34;
--green: #01f3e6;
--yellow: #f0e765;
--error: var(--red);
--errorBorder: 1px dashed var(--red);
--ok: var(--green);
--warning: var(--yellow);
}

Since it allows the name of a custom property to be descriptive and then utilized in another property with a more useful name, again keeping things DRY. It can even help in the readability and understanding of functional names.

Valid Values for Custom Properties

When it comes to the values they allow, custom properties are surprisingly tolerant.
Here are some basic examples that you should work with and complete.

body {
--brand-color: #990000;
--transparent-black: rgba(0, 0, 0, 0.5);

--spacing: 0.66rem;
--max-reading-length: 70ch;
--brandAngle: 22deg;
--visibility: hidden;
--my-name: "Chris Coyier";
}

Do you see what I mean? They can be hex values, color functions, various units, and even text strings.

On the other hand, custom properties do not have whole values. Let's look at how handy it is to break down legitimate CSS values into pieces that can be stuffed into custom properties.

A web browser consists of various structured bundles of code that are required to perform certain tasks to retrieve HTML, CSS and javascript. Click to explore about, How the Web Browser Renders the Pages with DOM CSSOM?

Breaking up values using CSS Custom Properties

To break up multi-part values, you can utilize custom properties.

Let's say you're utilizing the RGB color function (). There can be a custom property for each color channel value. This opens up a lot of options, such as adjusting the alpha value for a certain use case or establishing color themes.

Splitting colors

Consider the HSL colour space. We may break it down into smaller components and reassemble it as needed. Perhaps we're dealing with the background colour of a button. We may update select areas of the HSL component when the button is hovered, in focus, or disabled without having to declare a backdrop in any of those states.

buttons {
--h: 90;
--s: 50%;
--l: 50%;
--a: 1;
background: hsl(var(--h) var(--s) var(--l) / var(--a));
}
.buttons:hover { /* Change the lightness on hover */
--l: 75%;
}
.buttons:focus { /* Change the saturation on focus */
--s: 75%;
}
.buttons[disabled] { /* Make look disabled */
--s: 0%;
--a: 0.5;
}

By isolating values in this way, we can control values in ways we never could before. Consider how we didn't need to define all the HSL parameters to style a button's hover, focus, and disabled states. We just overrode some HSL values when necessary.

Shadows

On its own, box-shadow lacks a shorthand attribute for controlling the distribution of the shadow. We could, however, use a custom property to determine the box-shadow spread value (demo).

.buttons {
--spread: 10px;
box-shadow: 0 0 20px var(--spread) black;
}
.buttons:hover {
--spread: 20px;
}

Gradients

There is no such thing as a shorthand for gradients called background-gradient-angle (or something similar). We can change that component with custom properties as if it existed.

body{
--angle: 150deg;
background: linear-gradient(var(--angle), yellow, blue);
}
body.sideways {
--angle: 90deg;
}

Grids

Let's try a couple more cases now that we're on a roll. For example, we can abstract the grid-template-columns property's values into additional properties to create a highly versatile grid system:

.grid {
display: grid;
--edge: 10px;
grid-template-columns: var(--edge) 1fr var(--edge);
}
@media (min-width: 1000px) {
.grid {
--edge: 15%;
}
}

Transforms

Individual transforms will be added to CSS in the near future. However, custom properties will allow us to receive them sooner. The purpose is to apply all potential transforms to an element ahead of time, then control each one as needed:

.buttons {
transform: var(--scale, scale(1)) var(--translate, translate(0));
}
.buttons:active {
--translate: translate(0, 2px);
}
.buttons:hover {
--scale: scale(0.9);
}

Combination of Unit Types

Combining parts of values does not always function as well as you might anticipate. You can't make 24px by combining 24 and px, for example. However, multiplying the raw number by a numerical value with a unit can be done.

body {
--value: 34;
--unit: px;

/* Nope */
font-size: var(--value) + var(--unit);

/* Yep */
font-size: calc(var(--value) * 2px);
/* Yep */
--pixel_converter: 2px;
font-size: calc(var(--value) * var(--pixel_converter));
}

Typography is the color, contrast, alignment, size, and font that directly impact a web page's performance. Click to explore about, Fluid Typography Best Practices and Benefits

What are the Root Things for CSS Custom Properties?

Custom properties are frequently set "at the root." This is what it means:

:root {
--color: blue;
}
/* ...is largely the same as writing: */
html {
--color: blue;
}
/* ...except :root has higher specificity, so remember that! */

There's no compelling reason to define custom attributes in this manner. It's simply a method of putting custom properties as high up as possible. That's just good if you like it. When setting properties, I plan to make them available globally or everywhere. I find it more natural to apply them to the HTML or body selectors.

There's also no necessity to set variables with such a vast scope. Setting them exactly at the level you'll use them can be just as valuable and perhaps more readable and understanding (or fairly close in the DOM tree).

.module {
--module-spacing: 2rem;
--module-border-width: 3px;
border: var(--module-border-width) solid black;
}
.module + .module {
margin-top: var(--module-spacing);
}

It's worth noting that if you add a custom property on the module itself, it won't inherit from its ancestor (unless we set the value to inherit). There are times when we want to specify them in situ (at the global level) and other times when we want to inherit them from context, much like with other inherited properties (at the component level). Both are beneficial. Custom properties are helpful because we can specify them in one place, inherit them behind the scenes, and use them in multiple places.

The splitting of code into components or numerous bundles which can be loaded when there is a demand or in parallel. Click to explore about, Code-Splitting in ReactJs with Its Best Practices

CSS Custom Property Fallbacks

The var() function allows custom properties to have fallback values.

We're assigning a scale() transform function to a custom property in this case, but there's also a comma-separated second value of 1.2. If —scale is not specified, the 1.2 value will be utilized.

.big {
transform: scale(var(--scale, 1.2));
}

Any further commas after the first are part of the backup value. This enables us to design fallbacks that contain comma-separated values. We may, for example, have one variable default to a whole stack of fonts:

html {
font-family: var(--fonts, Helvetica, Arial, sans-serif);
}

We may also supply a series of variable fallbacks (as many as we want), but this requires nesting:

.big {
transform: scale(var(--scale, var(--second-fallback, 1.2));
}

If —scale isn't specified, we fall back to the —second-fallback option. If that's likewise undefined, we'll have to settle for 1.2.

Conclusion

CSS variables, often known as custom properties, are valuable to any designer's or developer's toolkit. They help you save time by reducing repetition, simplifying global changes, and adding automatic documentation to your style sheets. Plus, as you can see from the examples above, they're really simple to use and understand.