CSS Variables Coming to a Browser Near You

- Next up, we have a small, emerging bit of CSS, but I think an increasingly important one. I feel a lot of the influence on the way CSS is going will come from preprocessors like Sass and LESS, I guess above all, Sass, which seems to have kinda won that day. So our next speaker is a core contributor to the LibSass and Node Sass projects. Started life as a humble web-developer that does a lot of work with C++, and at this low-level as well. He's gonna talk about variables in CSS, and if you use preprocessors, you know about variables, but they're actually coming into your browsers. And we're gonna learn about the similarities and differences, and what we can do with them. So Michael Mifsud, if you know MelbCSS, or CSSConf down here, you'll know him. He's kinda heavily involved with styling and organising both of those. Made a lot of contributions. He's at 99designs as a kind of front end guy and has been for many years, and it's a great pleasure to have him here, speaking on our stage to tell us all about CSS variables. Please welcome, Michael Mifsud. (applause) - Hey, so, this talk was originally titled "CSS variables "Coming to a browser near you", but the web moves fast, and in that time, CSS Variables have come to the browser. Just in recent versions, Chrome, Firefox, Opera, Safari have dropped CSS Variables in the latest Stable channels, and I bumped the priority just this week. So instead, this is "CSS Variables and Why you should care." And I must confess, this talk was originally much shorter. I figured I just get up here on stage, introduce myself, and say something like, "CSS Variables are here!" There'd be a moment of silence, but then, then you'd all start clapping and cheering. You'd rise up out of your seats and start high-fiving each other. You'd just hug and congratulate all the other fellow humans around you, for this technological breakthrough you've just experienced. And then, as the cheering died down, and you wiped away those tears of joy from your eye, I'd just walk off the stage in style. (laughter) How amazing would that have been? However, to my dismay, the street parades full of fireworks and cotton candy for CSS Variables never came. So instead, hi, I'm @xzyfer. We're all friends now, so you can call me Michael, and I do Performance Engineering at 99designs, and as John said, I work at the community stuff. I started MelbCSS, and I'm part of the CSSConf AU team. And I do some open source work with the Sass core team, where I lead LibSass, Node Sass projects. This is not a Sass talk. I'm not up here to try and convince you that Sass is awesome. But most of us would've invented our mental model of how variables in CSS should work from something like Sass. So we'd have a variable like this, your BADASS red. You set it to your background, and SimpleModal is that red would then be replaced with the value it was at that current time. Pretty simple, not dissimilar from most programme languages. You'd have something like following here, your BADASS background. And it also gave us the idea of Selector Scoping, in that, you know, you'd set a variable, and, inevitably, a design to make you change it later. And this is important, because sometimes your red are BADASS, but then sometimes, your reds are SAD, but your red should only ever be SAD when the reds are SAD. And we get something like this. And none of this is like un-obvious. We kinda get the gist from reading the code. But preprocessors all have their own limitations. It doesn't matter which one you use, LESS, Sass, you know PostCSS, they're all kinda tied to this idea that you only know about your styles, and that can really tie your hands. So let's explore some limitations. Preprocessor variables are static. You know, we look at this code and kinda ensure what we think would happen. You know, we set the colour variable, you know. Our background is BADASS and then, as we get a larger viewport, our backgrounds become SAD. We look at this and ensure kinda what it could mean, but in reality that doesn't happen. You know, Sass has kindly removed that empty Media Query because it produced them upward, and you don't want that cruft in your code. So the moral of the story is you're about us. Sass Variables or primitive variables don't cascade. You know, the same idea as before, we see our background. You know, our background's BADASS and then, if there's danger, you know, it becomes BOO. You know, danger's bad. And for the same reason, Sass kindly removes and other preprocessors kindly remove that danger for you because it produces no output. It's just bloat to your users. And preprocessor variables aren't live. It's one pass, your history's immutable, you know. At the point where you substitute colour into the background, it is that colour, and if you change it later on, it only matters for code following it, and we end up in this case. Moral of this story is Sass has your back. Your code stays BADASS. So you might be wondering what this has to do with CSS Variables, and it's kind of important to understand our history so we don't repeat it. We have almost a decade now of Sass out in the wild, and it's good to think about what we've learnt from this. You know, Sass has a lot of powerful primitives, whether it's functions, variables, mixins, it allows some really powerful things, like creating Lodash in your browser or reading and parsing JSON in CSS. But it's important to look at the primitive CSS already gives us. Now it's very hard to change, add new things to CSS, to fundamentally change the scope. And CSS is relatively powerful. There's a lot going on in this little piece of code. Here we have our selectors. We have properties, property values, declarations, and directives or At-rules. These are some fairly powerful constructs in and of their own. So let's consider one of these. Let's take a closer look at properties. CSS Properties do cascade. This kind of fall is a mental model of if our body starts as BADASS, and in danger, it'll become BOO, you know, if we ever change our mark-up, you know, that becomes BOO. It's what we expected to happen. You know, it's the general cascade we're all familiar with. Now, CSS Properties are live. If we set the background colour, if we start off with a BADASS background colour, and later that background colour becomes SAD, you know, it becomes SAD. And one of their most useful features is Media Queries, you know. This kinda shows us how live this is, and it's important to note that although all my code samples are in Sass, like this goes for all preprocessors. I'm not biassed. I think all these tools have their place. So kind of a mental model of how this should work in that when a screen gets a certain size, it becomes God-like in Media Queries, and then BADASS when it goes big. And we do have one variable, one idea of what a variable could be like, and IE brought this in very early days, it's currentColor. Sara touched on this yesterday, so I won't go into much detail, but essentially, this value is whatever the inherited colour value is at that time. So if your body was the colour, and then you have a tag, that tag will inherit whatever the previous colour was. And it's useful setting things like borders to match your text or box shadows, without explicitly setting a box shadow, and this came in really useful. So recently, at 99designs we relaunched our brand, and part of it was these things all over our main page, is our big heroes. And the idea was, we'd have all these elements that would change to match prominent colours in the images, and this ends up being a little harder than you'd expect. You know, obviously we iterate every possible colour, but that's a lot of colours. So we ended in this case where we have text and text cascades of body colour. Like, it's pretty general, but in the case of a button, you don't wanna cascade the colour, you wanna cascade the background colour. And this is a kind of case where currentColor kind of comes into it's own. But in the case that we have a variation of the body, because our hero, for example, is always changing, you wanna get our button background colour to match to also be red. And there's a lot of variations in here, sure, we can make it mixin, an iterate, but there's a lot of colours going on. So in this case, we can use currentColor, and just always inherit that background colour from the main body colour. And in this, we can see, and we see, it changes colour once, and we have an infinite variation, essentially, but this is only one variable, and it can be very limiting. So it really kinda makes you think. Some of closed primitives we have are really powerful, and the Standards Bodies realise this. So they didn't give us CSS Variables, they gave us CSS Custom Properties that allow us to have Cascading Variables. But we as Web Developers saw variables, we used preprocessors and just ran with it, and obviously ignoring the convenient part of CSS Custom Properties, which is kind of the big deal. It's not until you stop thinking of variables as variables and variables as Properties that you kind of get a sense for those cotton candies and the street parades, and wondering where you robbed yourself. And the really powerful thing is, if you look at Properties have DOM Scoping, which is wildly different from Selector Scoping, and it's really just a fancy way of saying the C-word. You know, it's a dirty word these days, the cascade. So let's have a quick anatomy of what Custom Properties really are. So they're no different from a normal property in that we just prefix it and invent a name. So, in this case, we decided the call. We've instructed what will eventually be our button background colours to button fill. Like, it doesn't matter that it's been assigned to a background colour, but it's a language we can share with our designers and with our other Devs, like this is the fill, this is what we think of the background and our text. And by prefixing it with a double dash, the browsers that don't support variables will simply ignore it, because there are parse invalid Properties. So then in our button, we can set our background colour to that value, and we use the var function as a way of saying, "Extract the value from this Property". This is what makes Custom Properties variables. They're not variables in and of their own, but we can read them this way. And then, in a hover, say we create a variable and give a fall back. So we're saying var give me the value of the button-h-fill, which doesn't exist, so that'll set initial value, which in this case, doesn't exist, but we've let it fall back to SAD. So our BADASS button gets SAD on hover. And then, we have this really cool thing where as part of the fall back, your variable can be another variable. So you can say our button has a hover text, but if that's not set, then let's just assume that the current button text we have is fine. And this can be really powerful in constructs like mixins, where you only wanna change one part of it. And you often see stuff like this in a lot of code, and it's root element. And it's root element is essentially just your HTML Doctor, the top, root-most element. So think of it as our global variable in Sass or in JavaScript Window Object. It's not necessary, but it gives you a wider scope, where as in the previous examples, those variables are just scoped to the button. And that's exactly why in the hover state, you can read that variable, 'cause it is scoped to the botton DOM and not the button selector, which is an important difference. So let's have a look at the basic variable usage. Now, we can see the variables are live. Now, I can change the background colour in the body, and because of the cascade, and because they're live, I can go from BADASS to God pretty quickly. And the same case, they do cascade. Like, this is pretty obvious, we know how this kinda thing works. Basic cascade. We set the background colour to red to set the background colour to a background colour variable, and in this case, we spelt it correctly, correcting an injustice in CSS. And we have added the danger class and let it change that, and as we add that in, that value's always live, and our cascade's back up to the variables, global values pulled out of the current variable. And they're also dynamic. Like, this is a really nifty use case where we've set the background colour to BADASS, but on really small viewports, it becomes Godly. And we can do cool things like math if we're used to the Sass world. You can set your gutter, and then in your typical grid pattern, or set your container to set gutter, having your rows be half of the negative version at the pull-in. So you can see here, we can turn 30 pixels to negative 15 by dividing it by two. It's pretty bad ass. And this allows a really important thing called the Open closed principal, which is a fundamental principal in Engineering, that states that you should be open to extension, but closed to modification. And because we write CSS, we're all Engineers, don't have a way of taking it differently. So if we have a button, our typical BEM style pattern would be like, here's our button and we have a variation where we can change the background colour. And in this case, kinda just reaching into it and just changing it, and this can get really nasty. Really nasty if you have (mumbles) mistakes, say you're using a colour function that was like 10% lighter than the background colour, you have know all these internals of how this thing works. With using variables, Sara allured to this yesterday, is you can give yourself extenture points and these are things that I want you to change, and then I can do things with it later. So we can do operations, we can maybe change parse and a padding, and then divide that padding by two or do something with it. But we're saying these are the things, kind of like a function declaration. These are Properties we're letting you change. Here they are. And for people who use React, this is the very same pattern, this kinda props. You parse in things, and they trickle down. You figure out how that thing should be based, based on the properties you've given it. So that's a pretty powerful concept of it's own, and it allows us to, it becomes really powerful when used with like mixins. You know, in this case, we have a button, and we have the Properties of a base button of the background and the colour, and I set extension points. So we have a mixin of a coloured button, and say we have our theme of a different bunch of colours, we're saying given the danger button here, our full background is BOO, but on a bright button, our fill is yellow and our text goes black. And in this case, we can just iterate over that crowd of BEM style classes and pull the coloured mixin, and all that mixin does is set those Properties for us. So if your later then using things like Sass colour functions to lighten and darken, you have access to those, and you can set those to the hover variables of say previous button-h-fill. And it means you don't have to add the internals, but just the things it exposes, kinda like API processors. And this is largely unexplored territory. These features are relatively new. Like, they've just dropped in latest versions of browsers. There isn't a lot of writing out there, and people aren't really using it, and part of it is the Polyfill is really inefficient. You pretty much can't do it, and if you can, it's fully in JavaScript. And then so, it's a really interesting thing. So there's part of main Custom Properties that weren't tied to being CSS. So one of the classic examples you'll see is something like this, where they just set the value of Custom Property to some Javascript that really means nothing, but in your JavaScript, you can then pull that value out and do something with it. So this example, we see a lot, and it's not really useful, in my opinion. What I think was really powerful if you can do message passing, you can have a way of clearing your break points once for the very first time. Define all your break points as variables in CSS. You know, we say here, our body by default is pretty not great, it's BOO. But you know, when you add some punch, some power, you get some whoa, it becomes BADASS. So with some JavaScript, we can fetch the value of that Media Query, and then using things like the resize event and matchMedia, we can say, "Hey, when this hits our small break point, "you know, "it goes from BOO to BADASS." And we can see this in action here. So this is kind of the first time we can have a way of declaring variables, Media Queries once and passing between both the wraps, rather than like duplicating in CSS or in JavaScript. I haven't seen an HTML that reads on meta tag. And this is a powerful concept. I think there's more unexplored territory to go here. And it's interesting use case of Performance Optimizations because if you know, if you can say, declaratively, these are all the places variable is used, and you kind of have the freedom to just start changing them, you know. In the case of here, you know, our variables, we see the little variables (mumbles) as any kind of JavaScript modification. As long as they're only used in the script for this file, you can do whatever you want with it. Well, you get the point. There's some big questions that have come out of this from the community that I think are worth addressing. And the first thing is sure, this is awesome, but where are my parades, cotton candy and fireworks? The second one, is this a preprocessor killer? And my answer is no. It's part of the way there, but we don't have any replacement for things like Rich data types of lists and maps, or in JavaScript and LESS, even the more express data types like WeakSets, and there are no expressive APIs for dealing with these things. If you ever used a CSSOM, you get a string value back you can't really deal with, you got a parse, units out of your numbers, it's pretty painful. And it's getting better, but it's not there. You don't have colour functions, which is kind of a big deal, and really give a lot of power to these variables in mixin case. And you don't have Interpolations. You know, these are Custom Properties, not variables, so you can't do the Sass style thing of putting it in your Selectives or putting your variable as the Property, not just a value, like, it's a really limited use case. And you don't have Static variables, which actually can be really powerful. If in the mixin case, you want the Static variable in that isolated scope. You don't always want your things to be global on leak. This other question is what is with the double dash? There seems to be a lot of outrage. I feel like some of the other Developers you are disgusted or angry at the syntax, and they never actually use it because you hate double dash. I don't understand, but the other thing is why is there a var function? Why can't we just have the Sass style thing of declare it with a dollar sign, or use it with a dollar sign. And this is kind of an important part of what they call Custom Properties in that the double dash is a user space. It's this is your space, Other spec authors will never touch it. Do whatever you want. Put a double dash in there, browsers will just read it, and then you can figure out what to do with it later. And we may add more ways of using it, so the var function's a way of pulling the value out. But things like Houdini are extending this to add custom mixins, built-in mixins and built-in functions into your CSS this way. So the double dash is kind of an extension of Vendor Prefixes. They get one dash and a Vendor Prefix, we get double dash for our author space. Put whatever you want there. Browsers will ignore it if they don't understand it, and if they do, they'll just hide it away and you can read it later. So why not use something like a dollar sign, like the Sass style thing? This was briefly considered, but it kinda comes down to the two fundamentally different concepts. Preprocessor style variables are macros, and there's, you know, really simple shrinks obstrusions, and it's putting it in places where you can't use Custom Properties. And having two things with the same syntax is pretty much always bad for everybody. So what can you do? Get educated. There's a lot of misconception about what variables are compared to what Sass variables, people kind of (mumbles) the model, and there's a lot of difference here. Read the spec, really. It's like one page. It's super simple. You already know how Properties work, so there's nothing really to learn there. Get inspired. There's a really great article with Phil Walton on a bunch of use cases. Some I've covered here, some more advanced. Get creative. How can you use variables? Like, no one's using it, so you can be the first to do pretty much everything with these things. And make your voice heard. Go to the IE uservoice, vote on the feature. IE builds features as you ask for them, so the more interest you have, the more likely they'll build it. They have an open forum for it. Just click the vote button. It's almost doubled in votes in the last couple months. Thank you, I'm @xzyfer. (applause) - Thanks so much Michael. Again, while we're setting up for our final presentation in this session, we'll have a time for a question or maybe two. So any question for Michael on variables. Once again, I forgot my glasses, so I'm gonna have to squint. Alright, at the back, just to make life difficult. - Cheers, Michael. Thanks a lot for that. How would you see, sort of, I guess in a real world scenario, if you're working on a particular piece of, perhaps in the future a little bit, where you would mix in something like the CSS Variables there with perhaps Sass or LESS. Do you think that would be a practical thing to do, or would it sort of be a bit more selective, you do one or the other? - So, some of the set cases we're using is, like I showed, the Open closed principal. We have, all our components have extension points, and this way, so rather than having a mixin, where you pass in a tonne of variables, you know, it's kinda hard diverging these things. You don't know how they all work. In this case, you have extension points kinda trickle down, and one thing to note is that with the variables, as far as preprocessors are concerned, they're just strings. Like, all you see is the variable name, which can't always be useful, so you'll often pass in a raw value with one of the preprocessor Reach data types, like an actual colour or a string, and manipulate it. So you'll pass a colour through lighten, and then assign that value to a variable. So it's until CSS has those things built-in, it actually becomes, you know, you kinda limit yourself what you can do with variables like the Custom Properties, but you can't really do the manipulation that you want at the Sass level you're used to. But it is a way, for one, one thing I really like about it is the Performance Optimization, in that you don't have to overwrite so much. You have a typical button, it has hover states, it has active states, you have all these different states you have to account for, but you can actually trickle those down with very simple Properties, and not know all the fall decoration. - Alright, so if you got any more questions, please come find Michael. He's been around last couple days. It's always great you're glad to chat, and make sure you check out MelbCSS as well. In fact, we're doing a meet-up tonight. Sadly, completely full-up. Tomorrow night, with MelbCSS and a couple other local groups where we've got some great speakers. But they've got fantastic things every month just over in Richmond, right near the station. Too easy to get to. Let's once again, thanks Michael, for a fantastic presentation. Thank you Michael. (applause)