Dynamic CSS with Custom Properties (aka CSS Variables) Inheritance
Transcript from the "Inheritance" Lesson
>> The first part is about inheritance, and what do I mean about inheritance? Let's take a look at this demo, this is using three color variables and all three are setting colors, and then we're using them in this like extremely cut down version of a blog. So notice that even though I'm setting my variables on the root element which as we've said, is just the HTML element.
[00:00:24] They're actually available on the heading here, they're available on the the article here, let's take a look at the actual HTML that we have. It looks like this. So let's go back to the CSS, these variables are available basically everywhere, and the reason they're available everywhere is because they inherit down.
[00:00:48] But what does that mean in practice? So notice that in every blog post of sorts here, we are using this primary color. And in our HTML, we have applied a class of alt to the second one because we wanted it to use the secondary color. So we could actually go to our CSS, and do something like this.
[00:01:21] We can set primary color to secondary color. And it just all adapts. After that point, everything inside article is just inheriting this primary colour instead of the one from root. Because that's just how CSS inherited properties work. So the first thing to keep in mind is that CSS variables are not just actually CSS properties, they're inherited CSS properties.
[00:01:52] And anything that applies to any other inherited CSS property applies to CSS variables as well. One of the major ways we can take advantage of this inheritances is media queries. We can only override a few variables in the media query, and have all our styles adjust instead of rewriting a bunch of rules.
[00:02:11] So let's see how this works in practice with a dark mode version of this website. So something you might not have seen before is the media query for dark mode, which has prefers Kohler scheme dark. And anything you put in here only applies when your user has selected dark mode in the row S.
[00:02:39] And we can override any variables we want here. I'm gonna copy them and edit them. Another thing you could do for dark mode, and I'm just gonna add styles here, because like we said it's fine. So another thing you could do is, if you set the color scheme property to light and dark, it means that your CSS adapts to light and dark mode just fine.
[00:03:08] So then, let me set my OS to dark mode. Notice that the background already adopts, that's because I use the color scheme property to say, hey, this is okay, you can modify my website for dark mode. So notice both the background and the text color have adapted. So all we need to do is fill in the gaps to make this look better.
[00:03:35] We can change the heading to instead of white, we can use Canvas, and that makes it change to black and dark mode. And now, let's change the tinted background because it looks awful like that. And we're gonna change our colors to make them lighter. And instead of having a tinted background that is white, semi transparent white, we're gonna have a semi transparent black.
[00:04:10] And there it is, we just overrode three variables, and we have a very basic dark mode. Obviously, if you were creating an actual dark mode for a website, you would need to tweak it a lot more, but for like one minute of coding, we already have something. And if we weren't using custom properties, we would have to override a lot more rules.
[00:04:38] So in case you haven't seen the Canvas and Canvas text keywords, these are actually relatively new, although they're supported very widely. They are CSS system colors, they actually existed in the specification for a long time, but we recently changed how they work. So the way they work is, if they were custom properties they would look like this.
[00:05:00] Canvas basically means whites in light mode and black in dark mode, and Canvas text is the opposite. So, they're quite convenient in the sense that you don't have to define your own custom properties for these you just use the existing keywords. But you have to use color scheme like dark to enable this.
[00:05:20] And Canvas and Canvas text are actually the default background and text colors these days. So in some cases, inheritance is actually a problem, usually it helps, as weve seen it can be very convinient. Why wouldn't we want the inheritance? Well, here's an example. So here, we've used corner size on the universal selector, so we can just set the corner size custom property on any element and it introduces a corner.
[00:05:53] This is a very useful pattern because it means that we can have our own properties that just apply certain effects when we set them. And we don't have to apply the usage, the code that uses them on multiple rules. We just set them in one place and then we use them wherever we want.
[00:06:13] And it's basically the same clip pass code that we've seen before it, except that this time it's applied on everything. But as we see here, the fact that it's applied on everything means that it also means that when we set it on an element, it inherits down on elements that we don't actually want to have a cut corner.
[00:06:34] Here, our code is a paragraph with an inline element inside it, a mark element, but it could be anything. Could be a call and it could be a code element or whatever, and we obviously don't want to cut out the corner of the inline element, we only want it to apply the cut out corner on the paragraph.
[00:06:53] And imagine in a real website you would have an entire structure in there, and you most definitely don't want cut out corners on every single element inside. So what can you do? One way to disable inheritance is to just set the property itself on the universal selector and just set it to initial.
[00:07:16] So initial is a CSS wide keyword that returns a property to its initial value, not its initial value from the browser style sheet, its initial value from the CSS specification basically. And for custom properties, this means that they don't really have a value. So the clip path property is not applied, this is a little hand wavy not even not really have a value.
[00:07:40] But we're gonna see it in a lot more detail in later in this workshop. So this works, and it's fine and we can always opt in inheritance on a case by case basis if we wanted, if we actually wanted our mark element to have a cut out corner, we can just apply in here.
[00:07:59] It's because like we said, there regular CSS properties. Everything that applies to other CSS properties applies to custom properties as well. So one thing to remember is that you can disable inheritance by setting the property to initial on the universal selector or always in the selector that you're actually using this.
[00:08:18] In some cases the custom property only makes sense for example on form elements, so we would we would put the declaration that sets it up to initial on the same rule as well. There is actually a newer more explicit way to disable inheritance and it's called the Add property rule, it looks like this.
[00:08:41] And the property rule allows us to do a ton of useful things with custom properties, we're gonna be seeing it throughout this workshop. So this is just scratching the surface. But it comes with a syntax descriptor, which here we're gonna set two star which means anything goes, and inherits descriptor which we'll set to false.
[00:09:05] And an initial value descriptor which is not actually useful here. So, let's remove this rule where we made it explicitly inherit, and we don't actually need this rule anymore either. And see we've added this rule and it stopped inheriting. If we remove this rule it will start inheriting again.
[00:09:57] Like for example, you forgot the initial value property, which is required if the syntax is not star. But if you use the Add property rule, you don't get any feedback, you just sit there, looking at your code, wondering why it's not working, I've done that a lot of times.
[00:10:14] So, the downside of that property is that it's not actually very well supported today. That's the one thing that we're going to mention today that is not widely supported, but I still felt that it's important to discuss A, because it solves so many use cases. And B, because even though it's only supported in chromium and chromium powered browsers, today, for better or for worse, this actually gives it a very significant market share.
[00:10:42] Take a look at this, even though it's only supported in Chromium, or chromium powered browsers, that still gives it a 70% market share. And there is no opposition from other browser vendors about implementing it, it's just a matter of doing the work. And Safari has already said that they have plans to implement it very soon.
[00:11:06] But wherever possible, we are going to discuss workarounds as well, so that we can do certain things without our property whenever that's feasible.