Dynamic CSS with Custom Properties (aka CSS Variables)

Dynamic CSS with Custom Properties (aka CSS Variables) Numbers, Lengths, & Variable Values

Learning Paths:
Check out a free preview of the full Dynamic CSS with Custom Properties (aka CSS Variables) course:
The "Numbers, Lengths, & Variable Values" Lesson is part of the full, Dynamic CSS with Custom Properties (aka CSS Variables) course featured in this preview video. Here's what you'd learn in this lesson:

Lea provides an example of what happens when trying to abstract dimensions into a variable, discusses that variable values cannot contain parts of tokens, and what are considered tokens. Valid and invalid syntax examples, how to create single property mixins, and a recommended practice when using variable values are also provided in this segment.

Get Unlimited Access Now

Transcript from the "Numbers, Lengths, & Variable Values" Lesson

>> So now let's talk a little bit about numbers and lengths. This is essential to almost any code that uses custom properties. So to demonstrate the point I want to make here, we have a rather contrived example where we use a width and height that is set in viewport units so that we could display what shape your viewport is currently in.

[00:00:23] Yeah, I know, not something you do very frequently but bear with me for a bit. And notice that since I'm using viewport units, every time I resize this, it adapts. So, Someone who's very, very much into avoiding repetition could say I don't like repeating this number, I wanna set a variable.

[00:00:45] So the first attempt might be to use a variable, let's call it P with a 50, and then go here and do something like this. This is very common in people that have used SAS a lot. And now it doesn't work. Why doesn't this work? So the reason this doesn't work is because variable values cannot contain parts of tokens.

[00:01:32] If you write something like that, the browser actually understands 50 and vw, not 50vw. So what are tokens? Tokens are the most essential parts of CSS values. The most basic syntax components that cannot be broken further, essentially, the atoms of CSS syntax. And variable values are token lists, they can contain one token, they can contain more tokens, but they cannot contain half a token.

[00:02:08] So what is a token in practice? Cuz saying that they are essentially the atoms of CSS syntax is a little hand wavy. So these examples are taken pretty much directly from the spec, so tokens are keywords such as none, for example, or any other keyword that CSS includes.

[00:02:30] Numbers, lengths, but notice that numbers and lengths are distinct tokens. If you have a number token, you cannot combine it with something else and make a length token. Degree angles, percentages, all the punctuation that property values include, like commas, slashes the opening part of a function, like the function name and the opening parenthesis.

[00:03:00] The closing parenthesis is an individual token, a hash is a token. A string is a token. And there's a very special case that the URL function is an entire token. It's not URL and the opening parenthesis that is a token, unlike any other function, the entire URL is a token.

[00:03:26] This is because when CSS first started, URLs could be either be quoted or unquoted. So to enable this feature, the entire functional had to be a token and cannot be broken further. And lastly, white space is a token. So here's a quiz, and obviously, I don't expect you to know the answer, but what do you think makes sense?

[00:03:56] If you have linear gradient and an opening parenthesis, can you store it in a variable and then just use a variable to control the gradient type? Do you think this is valid or invalid CSS?
>> One person said valid, one person said invalid.
>> Yeah, so opinions are split.

[00:04:15] Based on what I've told you so far, it should be valid. However, it is not because there is an additional rule that custom properties cannot contain opening parenthesis, opening braces, opening square brackets, any of these structures. And actually not only is this invalid, but what actually happens is really weird, so let's open this in a new tab.

[00:04:43] So notice that actually no background gets applied. Let's inspect and see what's going on here. So notice this here, the next declaration was actually consumed as part of the value. So not only can variable values not contain unmatch parenthesis, square brackets, and curly braces, but they actually break kind of badly when they do.

[00:05:17] Now here's a slightly different example, also with gradients, where the stops are stored in a variable. And then we use that variable and the gradient, and notice that the stops variable also contains a trailing comma. What do you think? Would that be invalid?
>> You used it earlier, so I would say yes, valid.

>> I used it earlier but not with a trailing comma. Anyway, it is actually valid because comma is just another token, so all we have here is still a list of tokens. There's white, there's comma, there's black, there's another comma, that's fine. What about this? We have the two keyword in a custom property, and then we're using that.

[00:06:10] It's kind of contrived, but still kind of interesting. So I'm just gonna go ahead with this one and it is still valid, it looks really weird, it looks like it ought to not be valid, but it is. And this means that we could actually have custom properties that fill in as much as we want from a property.

[00:06:31] Like here we have a 3D with shadow custom property that if we set it, it invokes this entire thing and whatever we want to fill in here as the last layer. So we could invoke it by just setting it to whitespace and then we essentially have a pointless last layer.

[00:06:52] We could set just the color, Rebecca purple, and then we still have a last layer, it's just not very visible. Let me zoom in and you'll see that a tiny bit of purple there, or we could also fill in, A blur. Like as many tokens as we want.

[00:07:19] So essentially that way we can create single property mixins in a sense. Kind of like function currying for whoever knows that, well, that is in JavaScript. It's like when you backfill function arguments. So let's go back to our original broken example. What can we do here to fix it?

[00:07:44] How can we actually use 50 and then get viewport units? It's a little more verbose but we can actually do it. All we need is to use calc and multiply the 50 by one of whatever unit we want. And there we are, and now we can change the P in one place and it just adapts.

[00:08:18] Now some people might be wondering what if we tried to simplify it a little bit by setting p to 45vw, for example, that we can just use directly here. And then here we will divide it first by 1vw and then multiply it by 1vh, so that ought to work, but it doesn't work yet.

[00:08:41] Like I said, we do plan to eventually allow division by length, but right now that doesn't work in any browser. So we're stuck with multiplying numbers to make units everywhere, we cannot divide. The fact that we can not divide means that if we have a number, we can convert it to a unit by just multiplying with one of that unit.

[00:09:10] But if we have a number with a unit, say a length or an angle or something, we cannot get a number or any other unit, we cannot go anywhere from that. If we have a length, if we have, say, ten pixels in a variable, that's all we can use, we can't convert it into anything else.

[00:09:30] So I would strongly urge you to use variables for pure data not CSS values, unless they are like intermediate helper variables that you're using for something. But especially for the API that you're exposing to people customizing, your components, your CSS, try to use pure data as much as you can.

[00:09:49] Cuz you can always convert them to whatever you need, but you can't go back once you have length.