Making Custom Properties (CSS Variables) More Dynamic | CSS-Tricks

Last updated: 06-28-2019

Read original article here

Making Custom Properties (CSS Variables) More Dynamic | CSS-Tricks

CSS Custom Properties (perhaps more easily understood as CSS variables) provide us ways to make code more concise, as well as introduce new ways to work with CSS that were not possible before. They can do what preprocessor variables can… but also a lot more. Whether you have been a fan of the declarative nature of CSS or prefer to handle most of your style logic in JavaScript, Custom Properties bring something to the table for everyone.

Most of the power comes from two unique abilities of Custom Properties:

Even more power is exposed as you combine Custom Properties with other preexisting CSS concepts, like .

You can use Custom Properties to do effectively what variables in preprocessors like Sass provide - set a global or scoped variable value, and then use it later in your code. But thanks to the cascade, you can give new property values inside a more specific rule.

This cascading can lead to several interesting approaches, as shown by Violet Peña with an overview of the key benefits of variables and Chris with a roundup of site theming options.

People have been discussing these benefits from the cascade for a few years now, but it often gets lost in the conversation despite being a key functionality that differentiates it from preprocessors. Amelia Bellamy-Royds discussed it in the context of SVG and in 2014, and Philip Walton noted a lot of these general cascading benefits in 2015, and last year Gregor Adams showed how they can be used in a minimal grid framework. Taking advantage of the cascade is likely the easiest way to start working with Custom Properties with progressive enhancement in mind.

Okay. Now that we know Custom Properties can natively give us some functionality preprocessors have and some new uses thanks to the cascade - do they give us anything we simply never could do before?

All of the properties that have multiple parts are able to be used differently now. Multiple s can be separated, and multiple s can be broken out individually. Instead of taking a rule like you can set one rule with several custom properties and change the values independently thereafter.

It takes a bit to initialize, but then that little bit of extra effort up front sets you up to modify each transform function independently based on the needs of the class/selector rule. Your markup can then include any or all of the classes defined on each element and the will update appropriately, as the demo based on this code sample shows.

While independent transform properties are coming (and at that time , , and will be first level citizens), they are currently only in Chrome behind a flag. With Custom Properties you can get this functionality today with more support (and the additional ability to define your own order of functions, since is different than , for example).

If you are okay with them sharing the same timing options, they can even animate smoothly when using when changing any of the variables. It's kind of magical.

See the Pen CSS Variables + Transform = Individual Properties (with Inputs) by Dan Wilson (@danwilson) on CodePen.

You can build on these concepts when combining with . Instead of always setting variables as above with units ( or ) you can drop the units and use them in more places with a relation to one another. Now the values in our Custom Properties can be more dynamic than they already have been.

While has been around for a few years now, it has arguably been most useful when trying to get a result from adding values with different units. For example, you have a fluid in percentage units that needs to be shortened by 50px ( ). However, is capable of more.

Other operations like multiplication are allowed inside to adjust a value. The following is valid and gives us a sense that the transforms and filters are related to one another since they all use the number 10.

This likely isn't as common a use case because it is a calculation you don't need the browser to compute. will always be so the calc gives us nothing. It can be useful when using a preprocessor with loops, but that is a smaller use case and can typically be done without needing CSS .

But what if we replace that repeated with a variable? You can base values from a single value in multiple places, even with different units as well as open it up to change values in the future. The following is valid thanks to unitless variables and :

See the Pen Single Custom Property, Multiple Calcs by Dan Wilson (@danwilson) on CodePen.

The single value can be taken (initially 10, or later changed to 80... or any other number) and applied separately to units or units for a translation. You can convert it to for a rotation or a .

You don't have to drop the units on the variable, but as long as you have them in your you can, and it opens up the option to use it in more ways elsewhere. Animation choreography to offset durations and delays can be accomplished by modifying the base value in different rules. In this example we always want as our end unit, but the key result we want is for our to always be half the animation's . We then can do this by modifying only our .

See the Pen Delay based on Duration by Dan Wilson (@danwilson) on CodePen.

Even cubic beziers are up for Custom Properties modification. In the following example, there are several stacked boxes. Each one has a slightly smaller scale, and each is given a cubic bezier multiplier. This multiplier will be applied individually to the four parts of a baseline cubic-bezier. This allows each box to have a cubic bezier that is different but in relation to one another. Try removing or adding boxes to see how they play with one another. Press anywhere to translate the boxes to that point.

See the Pen Spiral Trail... Kinda by Dan Wilson (@danwilson) on CodePen.

JavaScript is used to randomize the baseline on each press, as well as setting up each box's multiplier. The key part of the CSS, however, is:

If you are viewing this in certain browsers (or are wondering why this example has an class) you might already suspect there is an issue with this approach. There is indeed an important caveat... magic does not always work as expected across the browsers. Ana Tudor has long discussed the differences in browser support for , and I have an additional test for some other simplified calc use cases.

The good news: All the browsers that support Custom Properties also largely work with when converting to units like , , , and other linear distance units inside properties such as and .

The not-so-good news: Firefox and Edge often have problems with other unit types, such as , , and even in some contexts. So the previous and properties would be ignored. They even have problems understanding in certain cases so even remaining unitless (such as inside ) can be a problem.

While all the browsers that support Custom Properties will allow variables inside our , not all of them allow at any level. I feel these issues are the main limiting factors with Custom Properties today… and they're not even a part of Custom Properties.

There are bugs tracked in the browsers for these issues, and you can work around them with progressive enhancement. The earlier demos only do the modifications if it knows it can handle them, otherwise you get the baseline values. They will erroneously pass a CSS check, so a JS Modernizr-style check is needed:

Custom Properties are great for what they provide in CSS, but more power is unlocked when you communicate via JavaScript. As shown in the demo, we can write a new property value in JavaScript:

This will set a new value for a globally defined property (in CSS defined in the rule). Or you can go more direct and set a new value for a specific element (and thus give it the highest specificity for that element, and leave the variable unchanged for other elements that use it). This is useful when you are managing state and need to modify a style based on given values.

David Khourshid has discussed powerful ways to interact with Custom Properties via JS in the context of Observables and they really fit together nicely. Whether you want to use Observables, React state changes, tried-and-true event listeners, or some other way to derive value changes, a wide door is now open to communicate between the two.

This communication is especially important for the CSS properties that take multiple values. We've long had the object to modify styles from JavaScript, but that can get complicated as soon as we need to modify only one part of a long value. If we need to change one background out of ten that are defined in a rule, we have to know which one we are modifying and then make sure we leave the other nine alone. This gets even more complicated for rules when you are trying to only modify a and keep the current unchanged. With Custom Properties you can use JavaScript to modify each individually, simplifying the state management of the full property.

See the Pen Dance of the Hexagons and Variables by Dan Wilson (@danwilson) on CodePen.

The unitless approach works well here, too. Your calls can pass raw numbers to CSS instead of having to append units, which can simplify your JavaScript in some cases.

As Custom Properties are now in the latest browsers from Mozilla, Google, Opera, Apple, and Microsoft - it's definitely a good time to explore and experiment. A lot of what is discussed here can be used now with sensible fallbacks in place. The updates needed in some of the browsers are further out, but there are still times when you can reasonably use them. For example, if you work on hybrid mobile apps that are limited to more recent iOS, Android, or Windows versions you will have more room to play.

Custom Properties present a big addition to CSS, and it can take some time to wrap your head around how it all works. Dip your toes in, and then dive in if it suits you.


Read the rest of this article here