Dynamic CSS with Custom Properties (aka CSS Variables) Images
Transcript from the "Images" Lesson
>> And let's talk a little bit about images as well. So far we've spoken about numbers, lengths, colors, strings, let's discuss images briefly. Just a few gotchas that there are when using images. So here we have a single line of code that sets a background to a photo of a cat, pretty ordinary stuff.
[00:00:22] And at some point, we wanted to use a custom property to control which image is shown from that folder. So when I tried this, my first guess, about how to do it, was to do something like this. And then go here and concatenate it like that, but as you can see that doesn't work.
[00:00:46] My second guess at this point, I had given up on having the folder name be shared, I said okay, if I specify at least the folder name, would that work? And obviously at this point I was just investigating cuz this is not that useful. But even that doesn't work.
[00:01:05] What works, is if I put the entire URL token In the custom property and use that, and this does work. The reason my two attempts didn't work is different. So the reason my first attempt didn't work is a CSS limitation. There's actually no way in CSS to concatenate two strings.
[00:01:32] We're familiar with concatenating strings from the content property, because in the content property we can just put strings next to each other and the content property concatenates them. However, that's specific to the content property, there is not CSS wide. We can't just put strings next to each other anywhere in CSS and expect that to work.
[00:01:52] We are actually discussing a function for this, a text or concat function, but it's a way out. So unfortunately right now there is no way to concatenate strings to compose a URL, which is really unfortunate because this would be so useful, especially with data URIs that contain SVGs.
[00:02:10] We could create parameterized SPGs, but unfortunately we can't. The second one is a CSS bug, and, I'm sure you've heard of browser bugs before, but you probably haven't heard of CSS bug. So this is a bug with the CSS language, this should work. It should be possible for this to work.
[00:02:28] But because URL started off as not just a simple function, but the URL function is weird, it accepts a string as a parameter. But also you could provide unquoted URLs. And unquoted URLs are its downfall. It means that we need to have all these weird parsing rules. So if you try to use a var reference, in a URL function, the browser basically has to parse this as a URL.
[00:02:57] The browser thinks that you have a URL which is var open parenthesis, --img, close parenthesis, like that's your URL there. And the whole thing fails, because that's an invalid URL If this was a regular function, if we were specifying it today, then it should actually work. Every other function in CSS accepts var references inside it, except URL.
[00:03:26] We are actually planning to add a function that is just like URL except it only accepts strings. I think we decided to call it SRC, it's a fairly recent resolution like less than a year ago. But right now that's obviously not supported anywhere. And lastly, the only thing that works is if the entire URL token is in a variable, but that can still be useful.
[00:03:49] You can provide icons for things, and so on, By assigning them to custom properties. So, one thing to remember is that custom properties can only contain entire URL tokens, not parts thereof for now. There are still some gotchas even with that, let's say, we have two separate style sheets, one of them sets, these sets images and the other one uses these images.
[00:04:21] So, a.css sets an image custom property to a certain URL, and b.css reads this custom property. What happens, how do they resolve? Do these URLs resolve relative to a.css or b.css? Do they resolve at the point where we specified them, or do they resolve at the point of usage?
[00:04:46] Let's find out. So I've prepared a demo here, where we have a.css that specifies exactly that, and has a cat.jpg that is relative to that file. And then a b.css that imports the first stylesheet and uses that variable and has a different cat image. So depending on the cat image we get, we could tell which one it's relative to.
[00:05:19] So let's preview it and see. So we actually get this one, it's relative to b.css. The reason, it's relative to b.css is because given that this is not a registered property, the browser just treats it as an unknown token essentially. So it's just substitutes it at the point of usage and that's only when it interprets it.
[00:05:47] Theoretically we should be able to register it, and then it would resolve at the point where we specified it, which is what we want in most cases. However that doesn't work right now. I do have an index hyphen registered dot HTML here, but it doesn't work, that part doesn't appear to be, I think that part is not implemented yet.
[00:06:13] There is a Chrome bug about it. So relative URLs and custom properties resolve at the point of usage, and registering them as URLs or images will allow us to change this, but not yet.
>> Can preprocessors help for this CSS bug?
>> Yes, so, the thing is, preprocessors can help as long as it's a preprocessor variable and preprocessor variables are not reactive like that.
[00:06:41] So, they could help if all we're doing is concatenating like if we just want to eliminate repetition within the style sheet. But if we actually want the dynamic aspects of custom properties then there is nothing we can do. Like if we want to have, some sort of dynamic calculation and then we wanna plug in an SVG data URI to make custom icons, that sort of thing that won't work.
[00:07:06] But if we just wanna have like sass variables within our sass stylesheet and set them there, then of course we can concatenate them in URL functions like people have been doing this for years. In fact when I wrote my book, I had an entire library of sass functions to concatenate variables with, to create like the SPG data URIs
>> Is there a way to set the URL as part of the HTML like in an attribute or other type of element?
>> So, there is an add function that you might be familiar from the content property. So you can use this attribute function in the content property and we've had that for many many years.
[00:07:49] And it just returns a string that gives you the value of the attribute in that individual element. However, if you assign the attribute function on a custom property will just resolve at the point of usage. So what you actually read that property, so if you specify it on a parent, and then you try to read that custom property on a descendant that won't work.
[00:08:16] Because the attribute function only gives you the attribute on that element, it doesn't inherit. And also there were some plans in CSS values to extend this attribute function so that it can be used anywhere in CSS. And it can return any type of value not just strings, so that it would return numbers and so on.
[00:08:37] Unfortunately, that was never implemented. There's a lot of people pushing for implementation of this, but browsers don't seem to be interested.