Getting Reactive with CSS
Watch on YouTube (JSConf)
What is this talk about?
“In Internet Explorer 7, we had something called CSS expressions, and this is where we put JavaScript inside of CSS, so it's actually sort of the complete opposite of doing CSS.”
“Came out with its own JavaScript stylesheets, where instead of using CSS, it just used plain JavaScript in order to style anything.”
From the opening of the talk.
Key takeaways
- For years, I challenged myself to create these complex interfaces and even animations like this box, using only CSS. 2:00
- In Internet Explorer 7, we had something called CSS expressions, and this is where we put JavaScript inside of CSS, so it's actually sort of the complete opposite of doing CSS. 7:00
- When you're using CSS variables, the more you use it, you're going to discover that Cal is going to be your best friend with CSS variables. 9:00
- If we move styling over to CSS and use JavaScript only for sending over values, then we could potentially replace JavaScript and CSS with any source in any medium. 25:00
Quoted from the transcript.
Full transcript
From YouTube auto-captions. Punctuation and capitals were restored automatically. Technical terms were normalized; some errors remain. 4,179 words.
0:00 Introduction
[Music] Hi everyone. I prepared this because the Wi-Fi was screwing up on me, so, actually, I wired in and now it works. So, my name is David Khourshid and I'm excited to be here for two reasons number one. I get to share this stage with so many amazing, talented women and men in the CSS community. So that's pretty awesome. And also because today we're going to be exploring some areas of CSS that we frankly, never thought was possible before. I work for Microsoft, so I'm obligated to tell you that edge does not suck, okay, and it, if it does. I'm not on the edge team, so it's not my fault. Year and a half ago I entered a hackathon with my friends. It was an Angular 2 hackathon, which almost sounds like fun. And there were two main goals. Number one was learn the basics of Angular 2, which I think right now is on version 5 or 13.
And also build a useful app using Angular 2, so something like a to-do list or a weather app. So we built Tinder for goats, this was our app idea. You, you know, not really viable, but I was delegated as the CSS person for doing this project and everyone else did the Angular, which I was thankful for, and they were thankful that I was doing the CSS. Because, as you all know, the maximum number of CSS developers that could work on a stylesheet without messing it up is between zero and one. And so I was at one, and I managed to make the interface look as close to the attend interface as possible. With the exception of one thing, and that's the whole swiping thing now. I had only 2 hours to do this, so I was trying to frantically figure out how do I do the whole swiping interaction. So I was looking up tutorials and they said, here's this jQuery thing you could use, here's, this ionic thing.
But none of those were going to work in Angular 2 just because Angular 2 was so new. And, so this to a lot of questions first and foremost, how are goats going to use this app? And secondly, how do you create interactive experiences in, you know, CSS, and. JavaScript. So for years, I challenged myself to create these complex interfaces and even animations like this box, using only CSS. And by doing that, I, I got to see how much CSS could actually do. Because one, your constraints to thinking inside the box instead of outside the box, you get to know the box really well.
3:00 You all might know that, CSS is awesome, but…
So, by doing this, I got to, you know. Look at all the ins and outs of CSS and all the little tricks that you could use in order to create complex things. But eventually, working in just CSS. You hit a wall, right, and you discover that CSS is not powerful at all. You know, you, you need JavaScript to do complex interactions, but I also discovered that CSS not being powerful is a good thing. And, there's a principle of least power that the W3C has, where it says to use a language with the least power in order to express what you want to do. So CSS would be that language for styling now. CSS, HTML and JavaScript are pretty much the bread and butter of web apps, which is complet completely different than Android apps or iOS apps. Where it's, Java and Swift or Objective C. And we're in an age right now where Progressive web apps are becoming more and more important, and the lines between web apps and native apps are being blurred.
And because of this, micro interactions are crucial, not only because users come to expect it. Because users wants to be able to play with an interface in, move it and pan it and do all sorts of stuff with it, but also because it reduces cognitive load. So what if, what? If web apps felt like native apps? And I? If we could think about that, how exactly can we get there? Now? Android and iOS have a slight advantage. You know, you have core animations, you have layouts, you have property animations, and they. They handle native interactions like touch and voice and all sorts of stuff natively within their APIs. The web is playing catchup, but it still has a little while to go. So think about this. What if interactive web user interfaces were easier to make, right? and what if they were easier to make with CSS? So you all might know that, CSS is awesome, but, some people don't think so.
Some people are like, Eh, no, CSS has its quirks, right? And the there's, you know, tons of things that we sometimes struggle with CSS. But the thing is, if you, you know, read the spec for once in your life, you could fix a lot of these problems. But that doesn't stop people from thinking that CSS is just awful. So instead, today, what I want you to do, at least for the next 24 minutes and 13 12 seconds, is to think of CSS as fun. And we're going to make it fun by introducing functional and reactive programming. All right, and the techniques I'm going to show you are, you know, going to be applied anywhere? So we're going to be talking about CSS variables and functional and reactive programming. What we're not going to be talking about is CSS and J script that comes later, and we're not going to be talking about. Frameworks such as React, Angular and View and other things that you might be using to build web apps.
The reason is because the techniques I'm going to show you can be applied anywhere. So, as you might know, you know, on the subject of CSS and JS, there's only two hard things in computer science, you know? Of course, the first one is naming things. Now CSS and JS aims to tackle this one naming things. So how many of you have actually used something like, CSS modules, or I don't know any of the other million CSS and JS things? How many of you used it? All right, so you, you might know how it works, right? You have a stylesheet, or you have something where you define Styles, and it takes whatever class name you give it. And it turns it into complete gibberish. And, this way, it tackles the naming things problem, and it also tackles the problem of global styles by isolating it, by creating unintelligible names. Not farts, and also, there is, uh.
There were some solutions that were proposed a long time ago. In Internet Explorer 7, we had something called CSS expressions, and this is where we put JavaScript inside of CSS, so it's actually sort of the complete opposite of doing CSS. And JS and over here is code to vertically Center this div in the body, so this goes to show you how hard it is to vertically Center. Something in Internet Explorer, where we have to add all of that, and Netscape, you know, not wanting to be left out of the party? Came out with its own JavaScript stylesheets, where instead of using CSS, it just used plain JavaScript in order to style anything. And if you're wondering why Netscape died, it's because of this. But now today, we have CSS variables, also known as CSS custom properties. But let's be honest, no one's ever going to call it that. And thankfully for all the browsers that we care about, it's supported, which is really, really awesome.
Unfortunately, in Internet Explorer, if you have to support an Internet Explorer, variables aren't supported, variables don't work, but that's okay, CU, nothing else works. And there's also Opera Mini, too. All right, so how many of you actually know what CSS variables are? I, I would assume most of you, right? Because you're at a CSS conference. You want to, you know, be up to date on the latest and greatest, so here's a CSS variable. In case you don't know. It starts with two DAS, and the reason it starts with two dashes is actually a really important reason. I, I don't know what that reason is, but it's, I'm sure, it's important right now. This does nothing until you actually apply the variable inside of a V statement like that. And so this 150 pixels is applied to the transform, and so it moves 150 pixels to the right.
But what if we do this? What if we took the unit out of the variable? Right now, we have to use Cal. And, when you're using CSS variables, the more you use it, you're going to discover that Cal is going to be your best friend with CSS variables. Here's why we did this. It's because you could set CSS variables using JavaScript. All you have to do is you take the elements, the node, you do the node. style., set property. And then you could set that CSS variable to N any number or string that works inside of CSS. So in this case, I'm using a library called Hammer. And I love Hammer because Hammer handles, touches, pans, Taps, any interaction with your fingers. So, it emulates mobile experiences really well. And over here, I'm just setting it to recognize. When I pan left and right, I take the Delta X from that and I set it to that Delta X.
Variable, and so now I could use set variable inside of this transform. There's one problem here though, and that's when I do pan end, I set it to zero. Because obviously we're not panning anymore. And just jumps to the middle. This is where the magic of CSS comes in. We could set another variable called panning and do sort of like a Boolean CSS. Where. We set it to one if we are panning, and we set it to zero if we're not panning. And over here, down at the bottom, don't know if you could see, but uh. We set the transition duration to 600 milliseconds if we're not panning, and we set it to zero if we are panning. Because the movement is controlled with our fingers. And, you might see this complex formula over here, and this reverses, whatever. I passed into panning, so if I am panning -1 * 1 plus + 1 is 0, so it's the opposite.
If I'm not panning, 1 * 0 + 1 is 1, so I am panning I. I like to call this Boolean Styles, also known as BS, not to be confused with the other BS, you know, bootstrap. So here's, I'm just kidding, by the way, here's, the real example over here. And so I'm just using my mouse to just go back and forth and you could see it works pretty well if you're clapping at that. I'm really excited because there's more. You might be asking, why did I use CSS variables to do this? Why couldn't I just set it directly, using JavaScript? So there's a few reasons if you've ever tried to use media queries in JavaScript. It's a complete pain. Like, especially trying to detect when the window resizes, listening for that, putting it in a request animation frame so it doesn't block your UI all the time.
13:00 You could use them however you want in your CSS files…
And there's also things like Prefers reduced motion, which, you know, I don't even know. How to do it in JavaScript? But I'm sure that there's a way, and so you could use media queries in order to control your CSS variables. This is great because that means that whatever values you're sending through JavaScript, you're not married to those values, you're not committed to them. You could use them however you want in your CSS files, and what this also means is that you could use them in pseudo elements. I recognize, I said pseudo selectors over here. I was wrong. I'm sorry, don't attack me on Twitter or anything. But yeah, you could use them inside before and after, which makes things really easy. Of course, you could sort of emulate before and after elements in JavaScript, but don't do it, please. There's also performance. It's much, much, much faster to set a CSS variable on a parents container that is inherited by all of its child and, descendant elements.
Then, having to go through each and every single one of those elements that has that style and set them one by one. And so here's, a benchmark where it shows it more than twice as fast as doing it within line Styles. If you don't believe me, you could just click this link, but don't tweet it because I will get in trouble. And there's also inspection, too you could open up your Dev tools and you could immediately inspect these CSS variables. Applied through anywhere, just so you could see that. It doesn't matter where these values are coming from, right? You could just modify them directly and be able to visually see immediately what's happening when you change those values. Which is much harder to do in JavaScript. So what if?
15:00 Animations are sort of the same way
Instead, you wanted to react to any event at any time that could come from anywhere? In order to create Rich interactive user interfaces in an expressive, declarative way. So this is where functional reactive animations come in. I could tell you're really excited, so hold on. Boom reactive Anim. Here's what reactive animations are. They are, animations that involve discret changes due to potentially continuous events. So if you're a musician, one of the best ways to think about this is sheet music. Sound is conceptually continuous, right? You play a note, it goes on and it's basically an. Infinite series of sound waves. However, sheet music is like, you know, single dots on a page that represents what you play. And animations are sort of the same way. Animations are conceptually continuous, right? But there's specific key frames where you define all of these animations. And so that's where the discrete changes are now. This idea is not new, it's actually really, really old, coming from 1997, a year after, what was it?
CSS or the web was born, or something like that? And in this paper, which is very much an academic paper, there's one quote where it says. By allowing programmers to express the what of an interactive animation, one can hope to automate the how of its presentation. And I quoted this because it's the only paragraph I understood in this entire paper, but also because it, and this is her website, by the way, this is what they did with reactive animations. We're not going to be doing this. This is just weird, but it's important to understand this because it blurs the lines between development and design, which is really good.
17:00 What we're going to be talking about today is observables…
So in JavaScript, we have what's called a value, which could be anything, it could be a number, Boolean value, it could be an object, and if we have multiple, you know, a multiple collection of these values, we have an array or an iterable. Now this is the the spectrum of things that happen immediately, we get this value immediately, we get each of those values in the array immediately. Now, what about things that happen over time? A single value can be represented as a promise, you get a value, but it doesn't come immediately, it comes eventually, maybe after 3 seconds. What we're going to be talking about today is observables, which are multiple values, just like an array, that all occur over time. So, we're going to be implementing observables with RxJS, and, this is a library that follows the observable spec. So this is something that could very well be a native part of the web.
But this is essentially a polyfill with a whole bunch of goodies built into it. So if we do, observable from events, we could, represent. Mouse moves, for example, on the box by grabbing the client X and the client Y and being. Able to observe each one of those positions on the mass. We could use RX. observable from event pattern for doing the same thing, and this is for things that are not natively DOM elements. So if I'm using Hammer..js, then I could, I could grab the Delta X and Delta Y values by passing in a call back into this from EV vent pattern. And here's why this is so powerful it's because we could operate and compose these observable values. So if you think of this as an array of values that happen over time, and we get all of these events, represented as balls, we could map each of these balls that's one of the operators and transform it into something else, such as a square.
But because we're working over time, we could also delay. Or do other Tim like Transformations, such as debouncing and throttling and buffering. Things that you can't do with an array, because an array exists at only a single point in time and not over time. There's also filtering, of course, just like an array. And there's a important operator called Scan, and what scan does is it takes the previous value and it combines it with the current value. So over here, I'm just adding 1 + 1 is 2, 2 + 1 is 3, 3 + 5 is 8 and so on. And this is a this is an operator that I use a lot when use. RxJS. So these are called marble diagrams, and um. They're fun to play with because you could visually see on this website, rxm marbles..com. How observables work together with different operators. I personally like to call them observables.
So, subscribing to observables is where the magic actually happens once you have an observable. If you hit do subscribe, you get each value as they come in, so it's sort of like a call back. Except by doing this, you could isolate all of your side effects and changes into one do subscribe and the observable. The other good thing about it is you define it, but it doesn't do anything unless it absolutely has to. So it's really lazy, sort of like me, all right. So here's an example of using observables to get the get something else, get a change value from this.
21:00 If we move styling over to CSS and use JavaScript only…
This range over here, and the reason I'm doing this is because I got a comment on this pen. That said, this dog is a little bit hyperactive, but it's cool. And so I added a range slider in order to slow the animation down, and you could see where I'm doing that. Over here. I'm grabbing this value and I'm using it to define each of the durations. I didn't realize. I also made so that it goes super fast though, too. So yeah, now we could also add physics. All I'm doing is adding a DYN Dynamics. JS library in order to create a physics observable. Every time I stop panning, so when I do that, instead of just going smoothly back to the location, it bounces right back. This is being controlled entirely with CSS variables. The only thing that JavaScript's doing is sending over the values. So now we have complete control of styling and we could use those values however we want.
Here's another example where I'm actually using request animation frame in an observable in order to. To tilt this clock in a smooth way, and so you could see that over here, smooth mouse. So if I changed this and I just used mouse, then you're going to see that it's very, very rigid. And this is one of the beauties of being able to compose observables, and, control them declaratively, just like you do with CSS, all right. Here's another example that I did recently, where I'm using linear interpolation to smoothly go from one place to another. And this is also being controlled with CSS variables as well. So, I have a bunch of things that I'm listening to, right? Touches, touch, ends, numbers, which is whenever the number changes in the range. And I'm making it smooth by using Lurp, where? By the way, if you don't know what lurp is, linear interpolation.
It's just if you're going from one place to another, instead from jumping from one place to another. You go part of the way there and then a little closer and then a little closer, so you get this really smooth effect going on here. And one of my last things that I made is this app, which uses a lot of observables and a lot of CSS. Variables, too, and this is one of the reasons that I'm using CSS variables is because, for example, that Delta X value for going left and right. That's the only value that I need to send in JavaScript. In order to control so many, many things. For example, I'm controlling the gradient in the background, I'm controlling the content inside, and I'm also controlling the text inside here. So there's a lot of things and a lot of moving parts that are happening with, just that single value, that single, CSS variable. Now, there's a really good reason why we want to move to CSS, VAR or not CSS variables.
But observables and be able to, express, rively and declaratively, define these animations and these interactions, uh. This is a charts by the Material Motion team at Google, and it shows the typical process for what happens. When we create a motion design, designers prototype it, they get feedback, they use that feedback to continue the prototyping, and eventually they hand off that motion design to a developer. Or a team of a, a team of developers. And from there, that's when the engineering starts. Instead, we could narrow that cycle and have the prototype be an actual working prototype, using real code that both engineers and designers can work on in Tandem. And by doing this, and by allowing the feedback cycle to be part of the development instead of just part of the prototyping. You ship faster, and that's one of the main goals, right, right. Because right now, the way we're sort of doing things in JavaScript for dynamic styling is we apply the Styles directly in JavaScript.
But if we move styling over to CSS and use JavaScript only for sending over values, then we could potentially replace JavaScript and CSS with any source in any medium. Which means that these important values can come from anywhere and they could be applied to anything. So, instead of CSS, think of it as canvas, OR think of it as WebGl, or think of it as platforms such as Android or iOS. So one team is doing this right now, which is material motion. This is something that is very much in progress. They're making a, animation library using observables, just like we talked about, and they're targeting us. I with swift Android. And the web? It's still a few months out, but they have a lot of documentation on it and some really cool examples already. So I definitely invite you to check that out. And when doing this, I also think of the future of what could be done with prototyping.
If any of you have used, Facebook Origami Studio, then this might look familiar to you. Where we define these, these little fragments that you could connect to other fragments and what these are like. Sort of a function where you connect one function to another, and then you could control exactly what happens dynamically, when creating your motion designs for apps. The beauty of this, though, is that it could be translated directly to code, and so that way we blur the lines between design and development. So what will you make with CSS variables? This is an example of something that someone made with, CSS variables and observables. Where? When I move my mouse, it's actually changing the HSL values and it's sending the Delta X position of the mouse over to CSS. And so the JavaScript is not controlling this, all JavaScript's doing is sending over the values. And, yeah, there's a whole collection of CSS variables that I've, collected over Codepen because Coden sort of my addiction, but I really invite you to play around with CSS variables.
See what you could make, and see how using observables can really help your interactive user interfaces in both design and development. So thank you, thank you. Okay, so we're going to have a break for lunch, we have.
Related talks
-
Reactive Web Animations with RxJS
Nordic.js 2017. 29:15, 2.6K views -
Reactive Animations with RxJS (@keyframers 1.2.0)
CodePen Houston meetup (@keyframers 1.2.0), 2018. 36:34, 1.2K views -
The Observable Future of Animations
DevFest Florida 2017. 30:47 -
Reactive Animations with CSS Variables
JSConf Iceland 2016. 31:03, 18.2K views