Hi, everyone, I’m Wheatup, and it’s my first time to publish an article in nuggets. If there are any mistakes or inaccuracies, please kindly correct them.

Most of you have already been exposed to CSS Custom Properties, and this is not a new concept.

However, many people use it only for the definition of global variables, used to standardize the overall style of the page, for example:

:root {
    --main-color: # 369;
}

p {
    color: var(--main-color);
}
Copy the code

But instead of customizing CSS properties, some people prefer to use their own variable system, which has a much more concise syntax, if the project uses pre-compiled CSS(such as SCSS) :

$mainColor: # 369;

p {
    color: $mainColor;
}
Copy the code

However, these precompiled CSS will eventually be compiled into native CSS, and these so-called variables are simply copy-pasted values defined for them, and do not actually function as variables.

Unlike pre-compiled CSS variables, CSS custom properties are actually a variable that can be controlled by JavaScript, CSS Animation, and CSS Transition.

If you have the flexibility to master CSS custom properties, it will overturn everything you have learned about CSS, so that your CSS can also be interface, custom.

Example: Make a simple progress bar

Let’s start with a simple example. For example, we need to make a progress bar, as shown below:

First, we define an HTML element figure and give it a class named progress-bar.

<figure class="progress-bar"></figure>
Copy the code

For CSS, let’s first build its basic framework:

.progress-bar {
    position: relative;
    
    display: flex;
    align-items: center;
    justify-content: center;
    
    width: 80vw;
    height: 4rem;
    
    border-radius: 5rem;
    border: solid 2px # 333;
    background-color: # 888;
    
    overflow: hidden;
}

.progress-bar::before {
    content: ' ';
    display: block;
    background-color: orangered;
    position: absolute;
    top: 0;
    left: 0;
    width: 50%;
    height: 100%;
}

.progress-bar::after {
    content: '50%';
    z-index: 1;
    color: white;
    font-size: 1.25 em;
}
Copy the code

These are some basic CSS, and without going into too much detail, can be explained as follows:

  • Using theflexThe layout centers all its elements.
  • Pseudo-elements are used::beforeResponsible for rendering the fill part of the progress barwidth50%, that is half, and the background color is temporarily set asorangeredDynamic color we’ll deal with that later.
  • Pseudo-elements are used::afterRender progress bar text section, content temporarily forcibly specified as'50%'.

Our progress bar now looks like this:

For now, our progress bar is only at 50%. We want a single variable to control all the behavior of the progress bar, including the length and color of the fill.

This is where the CSS custom property, which we’ll call — Progress, comes in.

.progress-bar {
    --progress: 0.25;
    
    / *... * /
}
Copy the code

We specify that it will be a value between 0 and 1:

  • When its value is zero0, the progress bar is empty and the color isred.
  • And when its value is zero1, the progress bar will be full and the color isgreen.
  • And when its value is at01When is, the progress bar will fill the corresponding interval and the color isRed to green.

Controls the length of the progress bar

To allow –progress to control the length of the progress bar, we rewrite width ::before to:

.progress-bar::before {
    / *... * /
    width: calc(var(--progress) * 100%);
    / *... * /
}
Copy the code
  • Use CSS custom properties wherever you need themvar()Wrap it otherwise CSS will not recognize it.
  • var()Can be used to calculatecalc()Methods.
  • If the variable has no units (that is, pure numbers), multiplying it by any property with units yields its units.

Since our width is a percentage value and –progress is just a pure number, we need to use calc multiplied by 100% to convert it to the corresponding percentage value.

We defined the –progress property to be 0.25 in.progress-bar, so the result should be width: 25%; , the actual effect is as follows:

Just a quick visual check, it should be 25%. As for the current text still shows 50%, we will solve it later.

If you change –progress, the length of the progress bar will change accordingly, and the length of the progress bar will be resolved.

Controls the color of the progress bar

So let’s think about it first, we want –progress to be 0, we want it to be red; — Progress is 1, the color should be green. For values between 0 and 1, its color should also be between red and green.

At this time, if RGB is used to control the color, the effect will not be ideal, because it is difficult to control the corresponding value of three colors with one value, and the calculation is also very troublesome.

Here I recommend using HSL for color control:

  • H(Hue) : Hue
  • S(Saturation) : Saturation
  • L(Lightness) : brightness

We can imagine that the saturation and brightness of the color we need should stay the same and only change to red ↔ green. If we can use “Progress” to control the hue, it will just solve our needs, won’t it?

For HSL color control, you can search for its specific usage, which is not the focus of this article, but only a brief introduction.

  • HTheta is an Angle between theta and theta0deg360degIn between.
  • H0deg, the color is red.
  • H120degWhen (1/3), the color is green.
  • H240degWhen (two-thirds), the color is blue.
  • SIs a percentage value,0%Is unsaturation,100%Is the maximum saturation.
  • LIs a percentage value,0%As the black,100%Is white, and only in between can you see hue and contrast.

Therefore, we can know that we need the value of H to be between 0deg and 120deg. At this time, we put a formula to convert 0 ~ 1 into 0deg ~ 120deg:

.progress-bar::before {
    / *... * /
    background-color: hsl(calc(0deg + var(--progress) * 120deg), 100%.35%);
    / *... * /
}
Copy the code

–progress = 0.25, 0.5, 0.75

Now that the color control is complete, if you change the –progress value, the length and color of the progress bar will change accordingly.

Control other properties

We did the same thing, using –progress to control properties like border and box-shadow, so our progress bar looks exactly like it did at the beginning of this article.

Complete CSS code:

.progress-bar {
    --progress: 0.25;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 80vw;
    height: 4rem;
    border-radius: 5rem;
    border: solid 2px hsl(calc((30 + var(--progress) * 60) * 1deg), 100%.15%);
    box-shadow: 0px 0px 2rem hsla(calc((30 + var(--progress) * 60) * 1deg), 100%.50%.var(--progress));
    background-color: # 888;
    overflow: hidden;
}

.progress-bar::before {
    content: ' ';
    display: block;
    background-color: hsl(calc(0deg + var(--progress) * 120deg), 100%.50%);
    position: absolute;
    top: 0;
    left: 0;
    width: calc(var(--progress) * 100%);
    height: 100%;
}

.progress-bar::after {
    content: '50%';
    z-index: 1;
    color: white;
    font-size: 1.25 em;
}
Copy the code

At this point we’ve achieved a single CSS property value — Progress controls the various property values for this element, and a simple CSS property wrapper is complete.

Control text display

Unfortunately, CSS custom attributes don’t control the content of the pseudo-element, and you’ll find that writing like this doesn’t help:

.progress-bar::after {
    content: calc(var(--progress) * 100) The '%';
    / *... * /
}
Copy the code

This is because Content only accepts strings and attr(), and CSS has no way to convert values to strings, so we’ll have to start with JavaScript.

As an aside, hopefully CSS X will fix this.

We specify an HTML Attribute named data-progress, and when we use JavaScript to set its CSS custom Attribute –progress, we also set data-progress:

<figure class="progress-bar" data-progress="50"></figure>
Copy the code
.progress-bar::after {
    content: attr(data-progress) The '%';
    / *... * /
}
Copy the code
[...document.querySelectorAll('.progress-bar')].forEach(e= > e.addEventListener('mousemove', ({offsetX, target}) => {
    // progress, values between 0 and 1
    const progress = offsetX / target.clientWidth;
    // Set the CSS custom properties
    target.style.setProperty('--progress', progress);
    / / set the Attribute
    target.setAttribute('data-progress'.Math.abs((progress * 100)).toFixed(0));
}));
Copy the code

We used mouse position controls –progress and data-Progress so that we could see the status of the progress bar in real time:

* Animate CSS custom properties using CSS Houdini

If you want to animate –progress using Transition or animation, you can define it in js as follows:

CSS.registerProperty({
    name: '--progress'.syntax: '<number>'.inherits: false.initialValue: '0'
});
Copy the code

This way the browser knows that progress is a number and can correctly parse keyframes as follows, otherwise the default is to jump directly from 0 to 1 and vice versa.

@keyframes load {
    from {
        --progress: 0;
    }
    
    to {
        --progress: 1; }}Copy the code

In view of the current support and stability of CSS Houdini is not particularly good, here is only a simple overview, if interested, please refer to the relevant literature.

conclusion

With that, we have basically covered everything we need to cover in this article. If it’s too much, try playing around with it. For example, you can define a few more custom properties and use them to control more properties. This will definitely improve your understanding of custom properties.

Thank you for reading to the end, I hope this article is helpful to everyone’s front-end knowledge, and I will write similar blog about front-end knowledge irregularly in the future, with you.

Full project CodePen: Codepen. IO/Wheatup /pen…