Tuesday, July 5, 2016

CSS in JavaScript

In this talk, Michele Bertoli goes through the main problems with CSS at scale and he shares some interesting JavaScript-based solutions, from Inline Styles to CSS Modules. Are you ready to enter the magical world of CSS in JS?
This talk was part of the Front-end London (FEL) May 2016 event.

Introduction

I’m Michele. I’m a frontend developer at YPlan. I’m a member of WEBdeBs and if you like React JavaScript and CSS, follow me on Twitter. Most important, I’ve got the CSS-in-JS skill on LinkedIn, so you should trust everything I say this evening. A lot – like 20 people, crazy people – ignored me for that, I don’t know why. One year ago, more or less, I had to start a new project and a lot of people were talking about writing CSS in JavaScript, so I wanted to try that technique, so I created this repo, where I basically try all of the libraries to deal with CSS in JavaScript, in general. Most of them are related to React, others are not. When I started, there were only five libraries. Now, today, we have 32 different techniques to use CSS in JavaScript and that’s the reason why we love open source. I couldn’t find the right one yet because I guess there is not the right one, but it’s super exciting because most of them are solving the problem in a very, very smart way. Maybe you can find the right one for your project. There is no “the right one” in the absolute way.
When you approach writing CSS in JavaScript, you should have the right mind-set, because if you start saying, “Okay, I’m okay with sass, I don’t want to learn anything new” it’s not going to work. You have to give it five minutes to try it before you say it’s wrong. You have to be prepared to unlearn everything because it’s something you have to do if you want to write CSS in JavaScript. Why if you write CSS in JavaScript you have to unlearn what you learned in the past 15 years? Because the way we write web application today is completely different from the way we were used to write web application. We used to have one HTML file, one CSS file, one JavaScript file. Now, we write our application as a mix of components. There are more components; Atomic components, so writing the CSS in the same language you write the logic could make sense. Let’s see.

Cascading Style Sheets

Before going into the topic, it’s important to understand why people are trying to find new ways to write CSS, because CSS has some problems – we all know. This is a slide from vjeux, one of the creators of React and it gave a talk in 2014 saying these are the seven problems that we had with CSS and we solve all of these problems with in-line style, so let’s see. You might have one of these problems in your life.
The first one is global namespace. No matter if you BAN, if you use nested selector, whatever, you are polluting the global namespace every time you write CSS. That’s bad. It’s bad in many languages, it’s bad in CSS as well.
It’s also really hard to define dependencies between your component and the CSS. For example, if you have a button you cannot easily say, “This button depends on this, this, and this CSS”.
Dead code elimination is pretty hard, it’s pretty scary because you never know what’s going on if you delete one single line of your site. There are some tools that can spot a new CSS and stuff, but it’s always hard to know exactly what to delete without breaking the codebase.
Minification of class names in the JavaScript CSS and HTML is hard as well, sharing constantly between your application and your CSS is not easy. You can do that, even using different languages, but obviously if you use the same language it’s going to be easier.
Non-deterministic resolution is a bigger problem because if you go to your CSS asynchronously, the order matters, so sometimes you don’t know what’s going on because you loaded CSS before the others. If you go in a section of a website and you load the CSS asynchronously, you can have some surprise.
Isolation. No matter how good you are at writing CSS, someone else can always overwrite your style and that’s pretty bad. If you work on a button, someone else can overwrite the style that you are applying to that button. You are not sure that’s going on. What is going to be the result?

Inline Styles

They said, we’ll solve all of these problems with inline style. Let’s see what it means to write inline style today.
This is the only React related slide. It works like that in any other languages, basically, you can do same in Angular and whatever. When you write inline styles, in JavaScript you define an object later on where all the keys are the rules. In this case, you have to use the colour case, for example, background image is colour case. A good thing is that you can use variable and then you just decide this object to the style attribute of the element – that’s it. You write your component like this.
There are some good things in using inline styles in this way. I tried it and these are the things that I found pretty good. The first thing is that you can re-compute your style on the fly. You can, for example, if you have input element, you can set the font size of the input element according to the value of the input itself. The value is 30, the font size is 30. Something you cannot do with CSS, with static CSS. The fact that you use object literals is great because you have the full power of JavaScript, so you can use fractions, variables, merged objects, whatever. It’s great. You can do crazy calculation and that’s great as well. The application state. When you write your application with inline style, it’s not about writing all the CSS with inline style, because that’s crazy, but you have to find which part of your application you have to write with. You could write with inline styles, because, for example, grades, base fonts, base style, they are okay to write them with classic CSS, but for example, for the application, so for example, if you show an error with JavaScript, the logic of showing and hiding the error is made with JavaScript. You can do the same with the style, so the error is red, you put the colour red inside your JavaScript with inline styles. That’s the thing. You are already, basically, handling the state with JavaScript. You just have to accept that the style is the state as well. Testing becomes easy. You can test both the behaviour and also the style. For example, colour red, you can test an object with the colour and it’s been applied.
Obviously, there are a lot of downsides. A lot, as always with a computer site. Pseudo classes and pseudo elements don’t work; media queries don’t work as well. Unless you do some weird tricks. Unless you apply, for example, instead of using hover, you listen to browser events and you apply and remove the style according to the JavaScript vendor, that’s pretty crazy. You cannot have style fallbacks. You are using a JavaScript object so you cannot have the display attribute twice, so display, flexbox and display, or whatever. Animations don’t work. You have to always override the style using !important that’s bad. It breaks the separation of concerns. If you are used to have the CSS separated from HTML separated from JavaScript because obviously you move your style into JavaScript. Performance is there with a question mark because I could find a blog post or a benchmark that clearly says, apart from ours, but obviously if you render on the server side and a lot of elements with a very, very long style string, the page is going to be bigger. No one can tell you what performance it was but they are. It’s easy to think that they’re going to be worse.
Debugging is crazy. This is a real-world example. When you’re using inline styles, obviously you’re going to see something like this in your dev tools. This is pretty, pretty hard to debug. First of all, it’s hard to find the element that you want to change. If you want to change the change the style, it’s really hard to find it because you usually use class names to find elements. Also, if you have a list and you change the style for one item, you’re going to change the style only for that item, not for all of them. That’s very, very, very bad as well.

[00:29:36] Aphrodite

Basically, inline styles are not the answer. Even at Facebook they’re not really using. Even if this guy says, “We solved all the problems with inline style.” I don’t know, in the Facebook website they’re not using inline style. They use inline style in React Netted, which is a thing, but not on the web.
Let see if there are any other solutions or different solutions to solve the same problem in a better way. The first one is Aphrodite. I choose a couple of libraries which are like the newest ones, basically, and they are not related to React. The first one is this one and you basically import the style set object and the CSS function. You define an object, as we saw before. You define the style as a JavaScript object. You have the full power of JavaScript; you can use variables, functions, whatever you want. You create the style sheet like this. Then you assign the style you just created to the CSS function. The good thing is that you can also use hover and media queries because in the end, Aphrodite is inline styles that work. It’s not inline styles. In the end, they render like classes but they call it inline styles because you can co-locate the style with your component and it’s an object.
The good features here are that you can use pseudo selector; you can use media query. Smart style injection means that if you have a very, very big object to define your style but you apply only one small piece of the style, they’re going to inject on the page only the CSS that you’re actually using and that’s pretty good. The autoprefixer is included, which is also good because you cannot have a pre-processing or post-processing, you have to have something in the browser.

CCSX

Another library is CSSX. It looks like this. It’s a little bit different. It’s very smart. You basically define a style sheet but on the JavaScript. It’s completely different from inline styles or whatever. You basically create a new sheet like that and you add all the classes that you want. For example, here we are adding the button and we say the button is going to be red and you can also update the class you created with another colour, for example. The result of this is going to be a CSS injected in the head of your page with the colour green. This is great because – obviously, you don’t use it like this – you update maybe the colour according to some events or something that happened on the page.
If you are very brave, you can use a syntax, which is like HTML, CSS, and JavaScript all together. It’s basically JSX for CSS, instead of transpiler. This is good. In this case, you cannot use – I mean, you can use JavaScript function if you concatenate the streams and stuff, but if you want to use the full power of JavaScript, you can use object leader like this this to define your styles.
CSSX is just a set of tools to write CSS in JavaScript, obviously. It comes as a guard task, post-CSS, plugin, CLI, transpiler, so you can use it in any project.
The benefits of it are avoid additional state classes, so instead of adding – for example, you usually have classes like ease error active, is warning, is something. You can remove all of those classes because with the CSSX, you change the CSS. You don’t add or remove classes to the DOM element, so you don’t touch the actual DOM element but you update the CSS. You apply just the button class but the button class before had the colour red and then when you click, the colour becomes green in the CSS, so you don’t touch the DOM element and it’s basically real dynamic CSS, because you change the CSS on the fly. With both libraries you can export, obviously they are not dynamic anymore, but you can even export the CSS at build time. You can have a base CSS exporting and putting the CDN or whatever.

CSS Modules

The last library, and my favourite one, is CSS Modules. You already have it all here but I’m going to tell you very, very few, few things. With CSS module it’s basically real, real CSS, so you define them in a CSS file. For example, the common class and you say the colour is red, then you import your CSS and apply the class to the element – that’s it. The result of this is going to be something like this. CSS modules by default create a niche of the class names. They are scoped locally to the element where you imported them.
They start from a very, very simple point. They started with Webpack you could import the CSS as any other dependency, so they thought, “Okay, we can scope all the class and animations luckily.” Basically, you avoid the clashes in bit code base, that’s good. Also, it’s really, as you can see, it’s really, really clear how to define dependencies. If you look at this button, it depends on that CSS, that seat, you’re sure about that?
There is also one very, very cool feature. You will see how we are using it later. There is composition, so you have a class which is class name, colour green, background red, and you have another class name. The second one composes the first one. Composing doesn’t work as extend, where you would have other class name declaring the same style, but when you apply the other class name, the CSS module is going to add the two classes to your element. If in one of your elements you use other class name, you’re going to have other class name and class name as well. If you compose it with 100 classes, you’re going to have 100 different classes. Your CSS don’t change, what changes is the result on the browser.
Using it with Webpack is very, very easy. You just start a new loaded but there is also a plugin for Browserify. The coolest thing you can do is you can decide how do you want the CSS to be compiled or hashed? By default, they are hashed. This is a side of Glen Maddern, which is one of the agents of CSS modules, and using emojis. This is great. This is a reasons to use it. Okay. Almost finished.

Bonus

We had to start at YPlan a project a few months ago and we wanted to use CSS module, but then I came here to the Front-end London, and Richard Bray gave a talk about Atomic CSS. Atomic CSS looks like this. You define very, very small classes where every class has only one single rule. For example, mb0 is margin button zero. You define all the classes you want and then you use all of them in the end. As soon as I saw this I said, “No, that’s completely wrong and I’m going to use it.” I’ve seen a lot of smart people here at FEL saying, “No, it’s good.” I wanted to see why and I went a little bit deeper into it and I found out that there are bad parts and good parts.
Obviously, the bad parts are that there are too many classes. If you have an element with 20 classes, it’s really, really hard to see what’s going on, to predict which will be the style of that element. It’s very similar to inline styles. A lot of people can complain. Okay, you are using a shortcut, like mb0 but basically you are assigning a style with the class names. It’s very, very hard to maintain because you’re moving all the style logic from the CSS to the HTML, basically. When you have to change the style, you change the HTML, which is pretty bad.
We also found out that there are good things. For example, quick prototyping is very, very – as soon as you have all of your classes defined, so mb0, mb1, mb2, whatever. If you use some libraries that are already out there, it’s super, super fast for prototyping pages. The file size of the CSS, and that’s the greatest things, is it remains the same. Whenever you create the base CSS, so you define all the classes that you to use in your base. Whenever you add a new button, a new section, a new header, you’re just composing those classes. The CSS file is not going to grow. That’s great. We said, “Okay, how can we solve the bad parts and just have the benefits?” We are using – and we are trying – I’m not saying it’s the right solution, we are using Atomic CSS modules. Basically, we are using CSS modules to compose the classes. We keep the style on the CSS and we let the CSS module to do the bad job of adding like 20 classes to the HTML. Yes, it’s working. We had a couple of problems. The first one is that you cannot compose on pseudo elements, for example, so if you have title hover you cannot use composes, but we are writing a post-CSS plugin for that. Another problem is with the order of the import, so if you import fonts and margin in this order in this file, in another file you change the order for some reason, the compiler is going to complain. There are still some problems but I wanted to tell you this is a good thing. You can try it. It’s funny.

The End

Recap. Use the right tool no matter if it breaks the rule. Don’t start saying, “I’m using sass, I’m okay. I don’t want to change.” Try it. It’s really, really hard in the beginning because you are basically doing something that you learned was wrong, so first you have to accept that and then you can do it.
Inline style versus local scope, so inline style is here, CSS modules are here and in between you have Aphrodite, CSSX, you have a lot of libraries ready. If you use React, there are a lot, like 32 libraries. If you don’t use React, maybe ten, fifteen, but there are enough to have fun.
Appearance versus state, you have to really choose careful what do you want to handle with plain old CSS. For example, grids, layouts, codebase, and what you want to handle with JavaScript. For example, everything related to this stage should be JavaScript because you are already handling this in JavaScript, you are just using classes as well.
The state is managed by JavaScript and the most important, have fun, because when I talk with people about CSS-in-JS, a lot of people get angry, “You are saying something really bad.” No, there are a lot of libraries out there. Have fun. That’s it.

No comments:

Post a Comment