[CSS Weekly #486] CSS custom attributes

🥳 Welcome interested partners to do something meaningful together! Translator: Rick Ma

I launched a weekly translation program, Warehouse addressAccess address

There is still a shortage of like-minded partners. They are purely personal interests. Of course, they will also help to improve English and front-end skills. Requirements: English is not too bad, github is proficient, persistent, modest and responsible for what you do.

If you want to participate, you can wx You can also send issue messages to the warehouse. My blog also has specific personal contact information: daodaolee.cn

What are CSS custom properties?

The custom properties of CSS are equivalent to the let in JS, which can be used to define properties that are reused in styles.
At the same time, he still abides by the cascading rules of CSS.
This means that we can define default attribute values for custom attributes, and then override them as needed.

You can use two dashes in front of the attribute to implement the custom attribute -- my property
When calling with CSS function var()

The following example defines a custom attribute of -- color
And use it for the property value of color

    --color: blue;
    color: var(--color);

How are they different from preprocessor variables?

Although preprocessors like Sass and Less have already put variables into production, the generated values remain unchanged in the compiled style sheet.

Variables in the preprocessor are more suitable for attribute values that are repeated in the style but do not need to be changed after compilation.

Custom attributes are more advantageous for attribute values that change dynamically through inline style overrides and style sheet context

In addition, if we use the preprocessor to set the font color for the button, when we change the font color of the button using a method like: hover, we can only redirect the attribute value to another preprocessor variable.

In other words, we can't change the value of a preprocessor variable after it is defined, but CSS custom properties can do this through cascading rules.

Another advantage of preprocessor variables is that they can be defined as strings used anywhere, such as a breakpoint of a media query, or the following selector string

$classes: ".class-a, class-b" !default;
#{$classes} {
    // Define CSS properties

Why use custom attributes?

Let's answer this question through the previous button example.

If I want to change the color of the button text and border when hovering, I can change the -- color value directly.

Notice how we use the var() function only as part of the value, in this case, to define the border color.

.btn {
    --color: blue;

    color: var(--color);
    border: 2px solid var(--color);
    padding: 0.25em 0.5em;
    border-radius: 0.25em;
    text-decoration: none;

.btn:hover {
    --color: red;

Use custom properties to set defaults

CSS function var() can call custom properties or set default values. As follows:

var(--color, blue)

We can even set a custom attribute to the default value, let's write a different version btn class
Make -- color the default value of -- border color

.btn-v2 {
  --color: blue;

  color: var(--color);
  border: 2px solid var(--border-color, var(--color));
  padding: 0.25em 0.5em;
  border-radius: 0.25em;
  text-decoration: none;

.btn-v2:hover {
  --border-color: red;

Inheritance of custom attributes

According to the previous introduction to custom attributes,
It may make people think that all custom attributes should be saved to the: root selector

What I want to propose is that on the: root selector, only the real global attributes should be saved
The custom attribute should be as close to the place where it is called as possible

Another key point is that when using custom attribute values in functions such as calc() through CSS,
Will let the final calculated value inherit

The calculated final value cannot be changed if it is saved on the: root selector
As follows, although -- unit in the root selector is overwritten,
But -- size LG gets the final value, so the upper and outer margins of margin top -- 3XL are still 30px

:root {
  --unit: 10px;
  --size-lg: calc(3 * var(--unit));

/* This will not recalculate the value of -- size LG */
.margin-top--3xl {
  --unit: 30px;
  margin-top: var(--size-lg);

This inheritance problem is usually solved by combining the root selector with other selectors

In the following example, due to The -- margin unit and -- multiplier attributes of margin top -- 3XL override Margin top has corresponding attributes, so margin top achieves a dynamic effect

:root {
  --unit: 10px;

.margin-top {
  --margin-unit: var(--unit);
  --multiplier: 1;

  margin-top: calc(var(--multiplier) * var(--margin-unit));

.margin-top--3xl {
  --margin-unit: 30px;
  --multiplier: 3;

div[class*="margin"] {
  background-color: dodgerblue;
  color: white;
  padding: 0.5rem;
  font-size: 1.5rem;

We can also use undefined custom attributes in the project to make the project more flexible
The benefit of undefined is that you can inherit values from any ancestor element

When using undefined attributes, we usually have the following two options:

  1. Property is undefined and has no default value, which is somewhat like being given unset
    For example: color: var(--color)
  2. Property is undefined but has a default value, which is used when there is no inherited value
    For example: color: var(--color, blue)

Using JavaScript to reference and define custom properties

Application scenarios where JavaScript manipulates CSS custom attributes:

  1. Transform values for CSS animation
  2. Viewport dimensions for responsive layouts
  3. Any value that cannot be obtained separately in CSS
  4. Override unsupported CSS properties

To access the value of a custom property in JavaScript, you need to use getComputedStyle() and getPropertyValue().


Next, we will use JavaScript to get the width of the paragraph. It is then assigned as a hue value to the hsl() color function

.js-color {
  background-color: hsl(var(--hue), 100%, 80%);
  color: black;
  font-size: 1.5rem;
  padding: 1rem;

.js-color::after {
  content: " Current: " attr(style);
const p = document.querySelector('.js-color');
const setColor = () => p.style.setProperty('--hue', p.offsetWidth);
window.onresize = setColor;

Use preprocessor variables with CSS custom properties

The combination of preprocessor variables and custom variables can give full play to their advantages

Here we take Sass as an example, and use Sass variables as user-defined attribute values. You can use the following interpolation method

--custom-property: #{$sass-var};

In ordinary work, functions such as brand theme color.
We can use Sass! Default sets a default value, which means that the value can be overridden.
Then, we can use it as a custom attribute value, and we can also use other functions of Sass (such as loops) to generate similar attribute groups.

$color-link: blue !default;
$font-sizes: (
  "small": .875rem,
  "normal": 1rem,
  "medium": 1.25rem,
  "large": 2rem
) !default;

:root {
  --color-link: #{$color-link};

  @each $size, $value in $font-sizes {
    --font-size-#{$size}: #{$value};

Related links

CSS Custom Properties

Original translation plan

Keywords: Front-end css3 css

Added by dycero on Sun, 09 Jan 2022 17:11:58 +0200