The Road to Styled Components: CSS in Component-based Systems
(upbeat music) (clapping) - Okay, hello everybody, my name's Glen, thank you, John, for the intro.
Thanks Mark for setting up and kind of establishing half of my argument for me and also actually using some of my examples which I'll now have to skip. My name's Glen, that's me on Twitter.
I am freelancer, most of the time I make screencasts as well as John mentioned, but for the last couple years, doing something like that, doing freelance stuff, trying to make videos, trying to research, trying to come up with new ways.
It's been a good way to do other things as well and I've been lucky enough to be involved in a series of open source projects.
Mark already introduced CSS modules which something him and I worked on, in fact, if you're coming to CampJS this weekend, I know quite a few people are, I think it was two years ago at that camp where him and I were both trying to convince each other that our idea was better and then we realised that if we compromised and called it CSS modules and gave it a cool logo, people would use it.
So that was, that has been really good, styled components is what I work on, what I'll talk about most today. React snapshot is a new thing which I'll mention at the end, nobody cares about this; I care about it, I'm gonna talk about it a lot at CampJS so if you're not interested in that just try to avoid me the whole weekend, I think. (laughing) The reason I kind of put these three up here is because they kind of form, for me, a bit of a pattern, right, they're all kind of related in a way, and so my talk is the road to styled components but, really, what I'm gonna talk about is the road ahead, as well. Because I think it's much more interesting to talk about these things in terms of the trends rather than the individual libraries, 'cause they come and go. So, styled components, just for some sort of background, it's a CSS in JavaScript library, it's designed for React but it works with Preact, of course because Preact is dark wizardry and just works with everything. Styled components is great, it's the most popular of the alternatives at the moment, as of a few months ago, and it's starting to get numbers that are starting to get a bit weird, high, like 300,000 people a month, like a more than a million people download, which is a lot for code that you wrote not well, but it works. It has 9,000 stars on GitHub which is a big number, I don't know why people take that as, um confidence but Max always talks about how many stars we have, so I thought I should mention it as well.
But what I'm really pleased about is that we've been able to take contributions from 130 people, and we've been able to develop, extend our initial two person core team to add Phil in London, which is why so much been happening recently on the project so, it's been really good, Max is in Vienna, and I'm here in Melbourne, and together we make this, this library.
It is a CSS and JavaScript library, and Mark's already talked about why that might be important and I'm just gonna, kinda put the highlights here, I'm not gonna go into these but what I wanted to emphasise is even though I'm gonna be talking about something that I've worked on, something that I, you know, can help you with and I encourage you to try, the benefits extend beyond any one library. These are benefits of using JavaScript in the first place to do your style, and so I wanted to emphasise that, if you use styled components or any other library out there, you can get these benefits, and there are lots out there that are mature enough that you could put them in production right now.
So rather than talk just about the library and the features, I'm going to kind of focus on the reasons behind it like, why would you build a CSS-in-JavaScript library, and what do you put in it? I'm actually gonna do that in the opposite order, because kind of like the easy answer for why you would build it, is because the set of things you want to put in it doesn't exist yet, and it's like, oh I want the x,y,z, and w, so therefore I'm gonna make that a new library.
But, there's actually more it, and I think, with some stuff that Lea was talking about yesterday, the why you would add new libraries, what you're trying to accomplish by adding a library to the ecosystem. It is worth discussing, so, it's gonna start with design goals for the project and then kinda go community or ecosystem goals for my, the reason I want to contribute to this stuff. So, design goals, and I got kind of a list of things that I think are important and they're transferrable to other libraries as well, it's not just about my stuff. But I think the first thing that a library, the first job of a library, is to establish and kind of codify some best practises, something that works well at scale, works well for some particular task.
I mean, the idea of a best practise is that it starts as a convention, starts as a habit, somebody maybe then writes a blog post about how it's been working for them and then somebody comes along, puts it into a library, so that all the new people, who are doing it for the first time, don't have to learn the hard way. They don't have to learn the real pains of terrible CSS that you can only ever like write extra lines at the bottom because you're not brave enough to look up in the file, and they just follow something like BEM and it helps, right, and they have fewer problems, and so the idea of writing a library helps to make it easier for new people into the industry because, or into that part of the industry because they don't have to go through that pain. In UI, I think the big shift that's driving all of this is a change in conceptualization of what we would consider a separate concern. Now previously, and for the browser, it's a long language boundary, so the CSS, JavaScript notation, all they're different, because browser treats them differently, they have different properties, they're different languages.
What we as humans, though, think about, if you get a bug report from somebody, they don't say that the JavaScript's broken, they say that the log in button doesn't work.
They're talking functional units.
Design reviews, designers, design systems, all happen in terms of functional units and so changing our workflow to use a more component oriented method, methodology is really just following these boundaries that we're already there.
The first time I saw that was a talk by Nicholas Galle, or he's just been mentioned a couple times. He had, in Melbourne at CSS conf, couple of years ago, and he was talking about the very first step if you're gonna start working with components, is don't change anything about your JavaScript to your CSS, just split it up into multiple files and then concatenate it at the end or whatever. But, split it up and then put those files next to each other, so put your CSS and JavaScript in a directory structure. So, in terms of practises that you could adopt: changing your directory structure for your development is pretty light, like it doesn't require a lot of investment. And then his advice was, see how that makes you feel and how easy it is to move around and edit these things, and you realise that you're getting a lot of the benefit just by the colocation of the information between these two files, as well as assets like SPGs and JPEGs. So the libraries that come along and codify that, Webpack and React, and others, make it easier for you to just keep doing that by default and obviously you put them in the same directory.
Previously, you would have have CSS, you know, headline, headline, text, that's just in a big CSS file, you have a bit of markup, that's just been in a big HTML file.
The only thing that ties those two things together is the fact that they have the same name, but they just live in a global space.
With React and Webpack, you don't change the CSS at all, you don't have to, but you make a connection between the JavaScript markup, the jsx, imports the headline CSS.
And that import from one to the other is how you structure your application and its how it makes it easier for you to deconstruct your CSS in JavaScript into these little component files, and all across the edge. CSS modules, again, takes that step, takes that one step further now that you have these small CSS files matching small pieces of markup, it says why don't, you don't need to use a name that's globally applicable anymore, you can use something like wrapper and text because that's logical, that's semantic to the component you're working on, and then, as Mark has showed, you don't know exactly what that class is gonna generate, but the information's still there, it's really straightforward.
And as benefit, you get to generate these hash class names that will never collide, and therefore you have solved a huge problem of CSS maintainability but with taking only a really minor, incremental step of practise. Style components is the next step.
This is a website, a docs page; docs are actually really good since version two. It's well worth checking out right now, it's quite mature. Version three isn't gonna change too much, it's just gonna be faster.
It takes the idea of CSS modules and just says, well, you've got the CSS file, and it's really simple and it's really small, and you got this whole markup that references it, while why don't you just do that in one file, right? Why does it have to be a CSS file, and the JavaScript file, why isn't it all just JavaScript? And so, the thing I like about this example, is there's a direct kind of one-to-one of what you did before, what you do afterwards. The CSS doesn't change, you can copy, paste that CSS. Styled is just a JavaScript library.
The names wrapper and text now have more prominence in the random method; you have just this random method just describes the structure and the content of what you're rendering, and then all the styling is self-contained. You don't have any of this kinda, you don't make tag choices at the same time you're making name choices that happens up here, but yeah, really, it's a JavaScript library. Styled.header creates a component that will render a header with whatever CSS you give it.
Styled.h1 will, React component will render a h1 with whichever CSS you give it.
And what that lets you do is, it lets you make better use of you component building blocks.
One of Mark's last examples was quite similar to this. These kinds of names, these kinds of APIs aren't direct HTML names, but they're a lot better than working with what the HTML that requires, that gets generated by them. The HTML is more familiar to most people but I would say that the example on the left, the React components are more semantic because they're words, they're terms that are meaningful to you and your business and your team and the project and the goals of your project, rather than the set of HTML elements permitted by HTML. You could also intertwine the naming so that buttons or links can be renders as buttons or buttons could be rendered as links depending on their purpose, but really just the idea is that you've stripped away anything that's not relevant to the actual UI you're describing.
So that's the first goal, is to codify the best practises, decide on the things that you're trying to capture and the things that you're trying to expose, and the things that you're trying to make easy, so for me, it's encapsulation of the component, the semantic naming, and colocating all the styles.
So rewarding small components because if you're components nice and small, it fits in a one file real easily. It doesn't work so well if your components are huge, but you can break your component up into smaller components too.
So that's the first goal, the next ones' all a bit shorter, but that one's the kind of major one, and that's kind of applicable to all kinds of libraries, the rest are a bit more personal things that I wanted to see styled components do, and this in particular is the big thing I thought that differentiates styled components from other libraries for CSS-in-JavaScript. I have a question for you.
Who writes SAS in the audience? Yes, that's good, quite a few people.
Alright there's a trick question, who actually writes SAS, not SESS? SAS without, the one, two, three, four, so four and I think there was probably about 20, 25 people. This is, to me, a really good example.
SAS's first syntax was on the right, has no semicolons, (inaudible) but once it had introduced SESS, which is a super set of CSS, it took off in popularity and now it's the dominant form of SAS.
What SESS lets you, is it lets you take a CSS file and lets you change it's extension to SESS, and it works, and then you can incrementally change it.
You can start adding nesting, you can start adding variables, you can start adding x and y and z. To me that's an incredibly powerful concept. It says to people who are are already comfortable with CSS, here is one step; this is not like, you don't have to take your files and convert them and then move everything across and then suddenly you get some benefit, it is, take what you're doing now and then incrementally improve it.
And so I've, I was very strongly in favour of that sort of thing for CSS-in-JavaScript, the kind of current CSS-in-JavaScript descriptions that looks as similar, that's not something like an atomic CSS generator or anything like that. Looks a bit like this, you have, it's a JavaScript object, you have strings for all the values, but things are, what is that, camel cased instead of kebab case, which CSS is, which is delicious.
So, components lets you use the exact same text that SAS, or SESS, did, so rather than introducing, trying to match all the CSS values and properties, and selectors into what is valid JavaScript, issues a string, the backticks are a multi-line string in JavaScript and you write SESS.
Now we don't support of SESS but we do support nesting and the ampersand symbol.
Takes a lot of work to support even that much, but, for me, that was one of the most important parts of the offering. It also means that you can copy, paste your CSS across, which if you're going to experiment with this and you've got an afternoon to spike it out, you'll get a lot further being able to do that than having to go to the left-hand side.
And then hopefully, you'll see the benefits and you continue on with it.
But I talk about this as saying, bring people along because this is an explicit decision to make it easier for people who are already doing CSS to use this thing. And the value I see in that, apart from just being nice to those people, is it expands the number of people who can get value from your idea. We can get use out of it, and see the benefits that you're trying to offer straight away.
You put less barriers to entry.
I also think it's really important, the CSS-in-JavaScript and CSS in JS as a kind of nexus of those two because, historically, CSS has not been seen as real engineering, whereas anyone who's done CSS for long enough knows how difficult that is and how harmful that kind of sentiment can be. So if you design a JavaScript library for doing styling, and you don't respect the fact that people already know CSS, and the best people are doing UI, are the people who know CSS, then you are doing them a disservice and you're not gonna get them, not gonna get the benefit of their expertise.
So the next goal was to follow the path of least resistance. Now this is kind of indirect opposition to the previous one because this is valid styled components code if you have a button in two colours, you know option A, option B, then you can add in an extra class like you would in SAS or anything.
And then, use the &.primary to change something about the display of the second one.
In styled components, while the one on the left does work, the one on the right is what we recommend.
It lets you use what's native to React, which is the presence of these properties, like primary. Just use them as a boolean property that you add, and then you can use this interpellation which is the dollar sign, squiggly bracket, and then this function and this CSS block, which looks a little bit kinda new, it's certainly new, and looks a little bit wild but is a better way of expressing that kind of conditional logic.
The advantage of that is that that mechanism that interpellation is exactly the same way that you do everything else in styled components, so you have one mechanism by to inject variables: you can do this for mix-ins or functions, or anything. Always use this interpellation character to change something about the CSS.
It also means instead of reimplementing things like IF statements or something in SAS, which we could have, you now use JavaScript. And so if you're learning like, even though there's a one to one between some of the concepts in SAS and some of the concepts in styled components, learning the JavaScript way of doing things is more transferrable to the rest of your application. So, that seemed like a valuable trade-off to us. The other part of that, is that the, and as Mark has already touched on, is the platform is going to new places, the platform is doing things I know that most people will be aware that we'll actually run on iOS and Android devices using React native. Now I don't use React native, but it was not a difficult process to generate a native version of styled components because it's the exact same metaphor, it's totally transferrable.
And so here instead of styled.h1s and styled.divs and spans, you have styled.views, styled.texts, and again, using, was it yoga, the, the flex box you can use, flex box terms like justify content and line items, and on a native device, those are simulated flex box things. They've gone that far to make it as familiar as possible, which made my job a lot easier.
Now you can write styled components and generate stuff that runs on a phone.
Of course the important part of this, is that this code, this particular component has nothing that ties it to native at all, it just depends on a wrapper and a title, and in this case, that wrapper and that title are native components.
But it's quite easy to see a situation where you could have wrappers and titles that rendered the web, wrappers and titles that render to something else. Sharing these higher level components by pushing more things into encapsulated styled components means that your code potentially is more transferrable.
Mark already introduced ReactXP, I wish it was called ReactME, (laughing) the millennial edition was the best version of Windows. And also React Sketch app which is really, really cool. Styled components now supports React Sketch app through React Primitives.
That's recent.
This is all really cool, but I can skip over it and save some time.
So that's the idea following the platform, so don't trying to match something that's halfway between what's familiar and what's ideal for the platform. That's kind of like, so it starts, it's my attempt to hit that in the middle, and you know, you might think I missed one way or the other, and there's other libraries that aim at a different point, but that's something that I had in mind.
The next thing, and this is something I just put in yesterday because I actually really wanted to talk about it, but I don't really know what I'm gonna say. Everybody likes Webpack and Babel, right, but there is a certain problem.
Webpack and Babel have added a lot to what we do with JavaScript, but there is a certain problem when every team has a different Webpack and Babel configuration. The Babel stage zero presets are changing all the time, even between the same team with two projects could have completely different configurations and the amount of time that you can lose if it's not working is not ideal and it's not a worthy use of your time as a professional developer, I believe.
Thankfully there's been a shift, and about 12 months ago there was a project out of the Facebook team. It's the first time that Facebook have released an open source project that they don't personally use on some production app.
It's the only thing they committed to supporting just for the community for React.
And that's Create React app, which is a zero configuration React Webpack config, everything, it basically will let you build an entire React app that can be production ready without having to even open Webpack.
You can eject and configure and stuff but you don't have to; this is just my favourite thing in the world, and actually it's a big influence on styled components because previously I was doing CSS modules, but with Create React App, there's no way to introduce CSS modules, well there wasn't in the initial version, without ejecting and changing config.
I was like that's actually a really bad thing, so styled components started and is 100% JavaScript. Everything that you've seen so far is just JavaScript. It might look a little weird because it's using temp tag template literals, which you kinda knew and ES6, but it's just JavaScript and you don't need any Webpack or Babel changes at all.
There is a Babel plugin and the Babel plugin does some stuff that's just not possible with runtime JavaScript, one of which is dev tooling, so the class names that are generated can use variable names that you use elsewhere in your file. When the code runs, there's no way to get those variable names out, JavaScript just doesn't have a introspection API for the variables like that. So, you can use a Babel config and copy some strings around and so that the classes that are generated look a bit more similar to you, what you expect. It also has a really important effect on, so for rendering, if you're doing more complex app, most of the time it'll work okay but basically, if you're gonna do server end in your styled components, use the Babel plugin, everything's deterministic. And from v3 onwards, the whole, there'll be a whole precompilations step to get quite a significantly better performance.
Not that it's bad at the moment, it's just there's a whole thing and this isn't gonna be a standardised effort from Oleg from JSS who's sort of leading it, and hopefully all CSS and JSS things will be able to use the same thing, but that's what we have to talk about yet.
So, the last, I think this is the last thing I was gonna talk about, which is the design goal five, which is don't make things worse.
Alright, so you've gotta respect the fact that you've just asked somebody to download a library, and that library has size and it may mean that putting the CSS-in-JS is just more things in your JavaScript.
I don't have a tonne of time to talk about it, but there's this graph that really, I think, gets it across quite well.
Addy Osmani from Google did some research about just the parse time for a meg of JavaScript. This isn't a meg downloaded, there's about 250k or something downloaded but then images comes up to a meg, and that's how long that it takes just to parse, not to execute, and not to render anything that it rendered. On iPhone 5C, which is not an emerging market phone like some of the other ones, still takes 1.5 seconds, so even if the file is caged, it's 1.5 seconds just to load it.
So for me the strategy there, and this is kinda the area of my next work, is that, do as much stuff in JavaScript as you like, but always serve HTML.
As long as you're serving HTML, your end result will be good, and you can use as much tooling as you want behind the scenes.
All the CSS-in-JS libraries, all the fancy stuff in the world, if you serve HTML, you won't have gotten backwards, and that to me, is the baseline. There are three very good projects that I would recommend any of these.
Gatsby is a static site generator, which is well supported, the creator of Gatsby works full time on Gatsby because of community contributions which is great for an open source project to be able to do that. Next JS is fairly new, it's kinda more of a framework, it does server rendering.
Some things are a little bit trickier but it does work with styled components, does work with a lot of React stuff. It's definitely worth checking out.
React Snapshot is a similar thing except it's, without running a server, it simply boots up the app, takes a snapshot after it's rendered, and then serves that as a static snapshot.
So it'll crawl your entire app and generate a static file for every view on the page.
It gives you all of the prerendering benefits of server rendering but with no config changes. But that's still in process and I'll be talking more about that this weekend. I want to take my last five minutes and talk about why I was kind of motivated to do this, because yes, the easy answer is I wanted all these things in one library, and so I built a library that had all those things. But there's something else at play here, and it goes much broader into the community, into the industry. Lea said this yesterday, she said, "It should be easier. "These tools are marking things harder ..." Which is totally right; when every tool add an undue burden of complexity and configuration, when every tool opens a pandoras box of new things you could be doing but you don't know which one is responsible, they make it harder for developers to choose and to learn, and to be confident in what they're doing.
And if you make something accessible to novices, it becomes easier for everybody, and I mean like, you make something easier for anyone, it becomes easier for everyone, is something I've been trying to push towards with everything I'm doing.
She also put this great slide up, saying, showing the spectrum of web development, and as professional web developers, we kind of inhabit the left-hand end.
And we, all of our projects, kind of live in that small space on the left, and yet this, I thought, was a really nice way of looking at it broader. But even within that little bubble of our own work, the stuff that we have to build, I wanted to point out a dichotomy that I've seen really, really often in my work as a freelancer, which is the idea that there are certain tools that you happen to use for a web app, but then for a landing page and a marketing page, anything that has to be publicly visible, everything that has to be fast, you fall back to what you're most comfortable with. And so, your landing page will be static HTML and CSS, unobtrusive, no JavaScript, and then you actually take care of using your meta tags.
You might have simple build step, but the main thing there is performance is really sensitive.
For a web app, the performance isn't as sensitive as shipping new features, generally people have logged into your app and so therefore, if the app takes a couple of seconds to load, you're not gonna lose any customers, they're already signed up. It's only if the product does what they want, then they'll probably stick around.
Now, both of those are totally fine, and they're really reasonable solutions to a problem, they're both fit for purpose, but the problem I see is that sharing assets between, the sharing knowledge between them, the sharing staff between them, you might have people who are stuck doing your landing page, stuck doing HTML and CSS, who really wanna come over and learn React, but you're only doing React on the backend, on the web app.
You lose this ability for people to make a gentle increase in their skills, and you lose this ability for their knowledge that might be more design background to influence the web app, and so my goal with a lot of this stuff, is to encourage people to look for opportunities to unify that development. So try to build everything with the same set of tools, so that everybody can share knowledge and share assets. Static and interactive components built the same, so if the different components suddenly has to become interactive, it's not a huge step backwards. Share all the optimizations like using say an image CDN, or at least revision stamping of assets between all of your, between all of your products, and always ship real HTML and CSS, never take the easy way out if you can avoid it, and then you can share everything! In effect, something I'm gonna quote from Mark, this is from the text version of the talk he just gave, which was a great blog.
He was talking about sharing HTML, and the idea that we don't share HTML snippets, we don't use HTML imports widely, we share HTML-in-JS, we share them as React components, we share them as Jcrew widgets in the past, and really the movement is not CSS-in-JS, it's everything-in-JS, and to me, that is the most exciting thing, the idea of, it doesn't have to be JavaScript, it could be anything, but the idea that everything that we touch as developers and designers working on the web, could potentially be in one ecosystem that we can, yeah, that was more productive for everybody. So, they're the kind of the things, the unification of skills between design and engineering, the unification of of platform and making the platform able to produce marketing pages, web apps, native apps, sketch apps, VR apps, it could be anything, but the idea that if we can build everything towards this unification, we might all benefit.
So, I don't know what the unified UI language is gonna look like, I'm betting on the React community at the moment, that it's gonna be a lot of the great work that they're doing is gonna continue.
Those are the things I think are important to this mythical UI language, and that's all I've got.
Thank you very much.
(applause) (upbeat music)