Movatterモバイル変換


[0]ホーム

URL:


Skip to main content
CSS-Tricks
Search

Making Custom Properties (CSS Variables) More Dynamic

Dan Wilson on

Get affordable and hassle-free WordPress hosting plans with Cloudways —start your free trial today.

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:

  • The cascade
  • The ability to modify values with JavaScript

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

The Basics

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 anoverview of the key benefits of variables and Chris witha 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 inthe context of SVG anduse in 2014, and Philip Walton noted a lot ofthese general cascading benefits in 2015, and last year Gregor Adams showed how they can be used ina 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?

You bet!

Individualizing Properties

All of the properties that have multiple parts are able to be used differently now. Multiplebackgrounds can be separated, and multipletransition-durations can be broken out individually. Instead of taking a rule liketransform: translateX(10vmin) rotate(90deg) scale(.8) translateY(5vmin) you can set one rule with several custom properties and change the values independently thereafter.

.view {   transform:     translateX(var(--tx, 0))    rotate(var(--deg, 0))    scale(var(--scale, 1))    translateY(var(--ty, 0));}.view.activated {  --tx: 10vmin;  --deg: 90deg;}.view.minimize {  --scale: .8;}.view.priority {  --ty: 10vmin;}

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.view element and thetransform will update appropriately.

While independent transform properties are coming (and at that timetranslate,scale, androtate 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, sincerotate(90deg) translateX(10vmin) is different thantranslateX(10vmin) rotate(90deg), for example).

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

See the PenCSS Variables + Transform = Individual Properties (with Inputs) by Dan Wilson (@danwilson) onCodePen.

Going from No Units to All the Units

You can build on these concepts when combining withcalc(). Instead of always setting variables as above with units (--card-width: 10vmin or--rotation-amount: 1turn) 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.

Whilecalc() 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 fluidwidth in percentage units that needs to be shortened by 50px (width: calc(100% - 50px) ). However,calc() is capable of more.

Other operations like multiplication are allowed insidecalc 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.

.colorful {  transform:     translateX(calc(10 * 1vw))    translateY(calc(10 * 1vh));  filter: hue-rotate(calc(10 * 4.5deg));}

This likely isn’t as common a use case because it is a calculation you don’t need the browser to compute.10 * 1vw will always be10vw 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 CSScalc() .

But what if we replace that repeated10 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 andcalc:

.colorful {  --translation: 10;  transform:     translateX(calc(var(--translation) * 1vw))    translateY(calc(var(--translation) * 1vh));  filter: hue-rotate(calc(var(--translation) * 4.5deg));  will-change: transform, filter;  transition: transform 5000ms ease-in-out, filter 5000ms linear;}.colorful.go {  --translation: 80;}

See the PenSingle Custom Property, Multiple Calcs by Dan Wilson (@danwilson) onCodePen.

The single value can be taken (initially 10, or later changed to 80… or any other number) and applied separately tovw units orvh units for a translation. You can convert it todeg for a rotation or afilter: hue-rotate().

You don’t have to drop the units on the variable, but as long as you have them in yourcalc 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 wantms as our end unit, but the key result we want is for ourdelay to always be half the animation’sduration . We then can do this by modifying only our--duration-base.

See the PenDelay based on Duration by Dan Wilson (@danwilson) onCodePen.

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 PenSpiral Trail… Kinda by Dan Wilson (@danwilson) onCodePen.

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:

.x {  transform: translateX(calc(var(--x) * 1px));  /* baseline value, updated via JS on press */  transition-timing-function:     cubic-bezier(      var(--cubic1-1),      var(--cubic1-2),      var(--cubic1-3),      var(--cubic1-4));}.advanced-calc .x {  transition-timing-function:     cubic-bezier(      calc(var(--cubic1-1) * var(--cubic1-change)),      calc(var(--cubic1-2) * var(--cubic1-change)),      calc(var(--cubic1-3) * var(--cubic1-change)),      calc(var(--cubic1-4) * var(--cubic1-change)));}

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

The good news: All the browsers that support Custom Properties also largely work withcalc when converting to units likepx,vmin,rem, and other linear distance units inside properties such aswidth andtransform: translate().

The not-so-good news: Firefox and Edge often have problems with other unit types, such asdeg,ms , and even% in some contexts. So the previousfilter: hue-rotate() and--rotation properties would be ignored. They even have problems understandingcalc(1 * 1) in certain cases so even remaining unitless (such as insidergb()) can be a problem.

While all the browsers that support Custom Properties will allow variables inside ourcubic-bezier , not all of them allowcalc at any level. I feel thesecalc 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 thecubic-bezier modifications if it knows it can handle them, otherwise you get the baseline values. They will erroneously pass a CSS@supports check, so a JS Modernizr-style check is needed:

function isAdvancedCalcSupported() {  document.body.style.transitionTimingFunction = 'cubic-bezier(calc(1 * 1),1,1,1)';  return getComputedStyle(document.body).transitionTimingFunction != 'ease';  //if the browser does not understand it, the computed value will be the default value (in this case "ease")}

Interacting via JavaScript

Custom Properties are great for what they provide in CSS, but more power is unlocked when you communicate via JavaScript. As shown in thecubic-bezier demo, we can write a new property value in #"JavaScript">var element = document.documentElement;element.style.setProperty('--name', value);

This will set a new value for a globally defined property (in CSS defined in the:root 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 inthe 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 thestyle 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 abackground 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 fortransform rules when you are trying to only modify arotate() and keep the currentscale() unchanged. With Custom Properties you can use JavaScript to modify each individually, simplifying the state management of the fulltransform property.

See the PenDance of the Hexagons and Variables by Dan Wilson (@danwilson) onCodePen.

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

Is it Time to Use This?

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. Thecalc 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.

Psst! Create a DigitalOcean account and get$200 in free credit for cloud-based hosting and services.

Comments

  1. Gokul

    All the above are not working in Edge browser. Css Varable not work in Edge browser. How to solve this

    • Syed A.

      Edge 15 has limited support for this. Check this link for support of CSS Variables:http://caniuse.com/#search=var

    • Dan Wilson

      Edge requires the latest version that came out last month (v15) with the Windows 10 Creators Update. The article calls out a few caveats with it, though there is also an additional issue whencombining translate + variables + calc which prevents one of the demos from working at all. The Edge team is working on several of these less common CSS Variables issues for their next release.

This comment thread is closed. If you have important information to share, pleasecontact us.

[8]ページ先頭

©2009-2025 Movatter.jp