Writing Efficient CSS


CSS can be really helpful, but if you don't think about how it works before writing selectors, you can seriously harm the performance of your page.


We all have strong opinions on CSS, whether good or bad. CSS can be really helpful, but if you don’t think about how it works before writing selectors, you can seriously harm the performance of your page.

In this talk, Joe Reeve introduces us to browser implementations of CSS selectors and what that means for your CSS.

This talk was part of JSOxford (May event).

[00:00:10] I’m Joe, Joe Reeve. Nice to meet you all. I just – shameless self-advertising – I help run a meetup called, “Marlow dev” in Marlow, which is halfway between here and London. That’s where I live and work. If any of you want to speak or attend, just let me know and we can organise something, because we’re looking for speakers.

[00:00:35] The actual content is about CSS. This is mostly about how we treat the browser’s selector engine. Rather than we’ve got stuff moving around and it’s crazy, this is more about how do we make it easy for the browser to figure out what we’re talking about. The selectors will be talking about themselves. I’m going to give a brief history, which may end up being a little bit of an overstatement because it’s stuff that I’ve found from Google.

[00:01:05] Has anyone ever written a line of CSS that looks like this and then sat back and being like, “I’m so good at CSS. I am amazing at CSS. All the other guys in the office, they’re not as good as me because I wrote that line of CSS.” This is bad, you should definitely not write code like that because it’s bad. We’ll get to that. When I had this talk accepted, we’re going to talk about CSS, I figured I may as well start from the basics and refresh my memory of what is CSS. I used the define keyword on Google and said, “What is CSS?” The answer I got was: A cascading stylesheet is a webpage derived from multiple sources with a final presence. All that stuff. Basically, from this really rubbish description all I learned was that you should never trust online sources. I’m assuming you guys know what CSS is, right? Yes. No, you don’t? Say, yes, no?

[00:02:11] You know what CSS is? Good. There are three levels of CSS. First of all, if you’re next to a W3 guy, a W3C guy, and you say, “Three versions of CSS”, they’ll slap you around the face. It’s three levels of CSS. Level one was originally made in 1996 or originally specked out in 1996 and then it was updated in 1999. Level two was actually started before they finalised level one, which was a bit weird, and that was finalised in 2003. CSS three was finalised in 2006. That is not when it went into browsers, that was when the specs were standardised. This is a little graph. As you can see, when Chrome one was released, and Chrome 49. In a tiny space of time, we’ve got – is it 50 now? Well, we’ve got 50 versions of Chrome, which is insane considering we had the dark ages back then, like before I was born.

[00:03:14] Getting on to performance, which is what I was supposed to be talking about. Basically, the specs have nothing to do with it. It’s always fun the bash the guys who write the specs because it’s always a bit annoying when we realise that they’ve made a mistake or they’re updating something and now we’ve got to relearn stuff. Unfortunately, the CSS specification has nothing to do with how fast or slow the CSS is, it’s to do with the guys who write selector engines and the rendering engines. In this case, the selector engines.

[00:03:39] What I’m going to say is slightly different in loads of different browsers. It’s not one rule fits all but a lot of it is applicable to most of them because you’ve got something like WebKit, everybody is going to look at WebKit for how the open source guys are doing it, because hopefully they can copy and paste the code. Like I say, IE is slow no matter what you do but then you’ve got Chrome which can limp along even if you do some really horrible stuff. That was a Rick and Morty gif. There are four different types of – I really should connect to the internet – four different types of rules. You’ve got ID rules, everyone knows what an ID is, what an ID rule is, I presume. You’ve got class rules, tag rules, and inverse rules, but the thing is, we’ve got this thing called “a key selector”. A key selector is just a bit of jargon that we’ve assigned to the last part of a selector. In AIMG it’s IMG, in DIVP it’s P and yes, that’s pretty easy. When I use the word “key selector” that’s what I’m talking about. With ID rules for example, we’ve got a key selector back button, the whole thing in this case is the key selector, so that’s an ID key selector. Then at the end we’ve got our, my cell: active key selector.

[00:05:08] Class rules, kind of the same. We’re getting there. Tag rules, tags, right? Universal rules are things like stars, anything without a proper selector. This is a key selector, a universal key selector. We’re going to talk about history now, this is where the history lesson part comes in. The way the selector engines work is they start at the end and then they work left. They find everything that matches div nth child one, all throughout your entire page, all of your HTML, everything in your DOM. Then they say, “Well, filter based on stuff that’s within a tab or a .tab and then keep going and keep going and keep going.” You can see now why I’ve said that was so bad earlier because you’ve put in so many jumps through. It’s brilliant is you want to have a little DOM as possible but if you want to make it as easy for the browser as possible, then that’s just super slow. You’ve got how many jumps when you could have just had one, if you had just given it a class. If you use universal rules, how many of you have or do use universal rules? A few of you. I won’t ask you to leave. The first tip I have is don’t qualify your ID rules with tag names or classes. That’s just adding extra layers for the browser to jump through. That’s the same in most cases, don’t add extra layers. Don’t qualify class rules with tag names, kind of the same thing, but this thing – I didn’t even realise tree cell was a thing before I made this talk. What is it? Does anyone know what it is? No. Apparently, it’s genuinely in the spec. Don’t do that.

[00:07:14] Yes, generally use the most specific form. Instead of doing something like this, you just give it a class because it’s so much faster for the browser to find. It just searches for everything that has that in it, and it’s easier for you as a developer to figure out what’s effecting what, which is helped by using something like BEM, where you actually namespace your classes. Then avoid the descendent selector, so that’s just the space. I don’t know if anyone does that but less compiler does that, you know less? The pre-processor. Every time you nest your CSS, that’s how it comes out, the top line. It comes out like this. Less makes it super easy to write bad CSS because you’re not writing CSS, you’re writing an abstraction, which compiles to really, really icky slow for the selector engine. Tag category rules should never contain a child selector. This, although it’s faster than having a space, it’s still pretty slow when you could just give it a class. There’s a theme here; give things classes because it does help. It does lead you on to having some issues of having too many classes, getting confused by what they all do but that’s why you adopt a namespacing system.

[00:08:40] Another tip is to rely on heritance. Instead of explicitly saying to the thing that’s contained by this guy, just set it to the top guy if it doesn’t matter so much. It’s not going to affect how it looks because it just follows through and that’s so much easier for the browser to figure out than doing that two-step jump. I pressed it once. Basically, be specific, give things classes and reference those, rather than giving it some huge, long chain to walk down.

[00:09:17] That was historical, what about now? Obviously, we’re supporting some old browsers, which have some really, really bad issues with those things. Now we’ve got super-fast phones in our pockets that can handle all of this stuff. Is it still important? This guy, no, no, yes, come one, we’ve already had like four people on the stage. Okay, so this is what Antti said, he said, “My view is that authors should not need to worry about optimising their selectors” and to me, that’s kind of dangerous. Well, if I don’t have to worry about what’s going on underneath the hood, that means when someone with an older browser isn’t fast or when you’re running on some XP machine in the middle of Kenya, your website’s not going to work very well. He does have a point, it’s not your job as a developer to write stuff that’s fast, it’s the compilers job or the interpreter or whatever it is, the systems job to figure out what you’re trying to say. Which is like, “Are you programmers or are we just translators?”. If it’s a translation, then we need to be really, really careful. If we’re programmers, we’re telling the computer what we want at the end, then surely we should just be able to say whatever want and it figures out the best way to do it. This Antti guy, this makes me really cool, I’m better than Adam – he’s nodding, don’t do that – because I mentioned a WebKit called, “Contributor” in my talk. Therefore, I must know what I’m talking about, right? I quoted him. These are the things we’ve done for WebKit: Style sharing, rule hashes, and sister filters, fast path, and these other things that go on for miles down there. He’s done loads and loads and loads of tiny, tiny optimisations and some bigger ones like the ones that are actually written there that make browser selector engines work so much better.

[00:11:12] The first one is style sharing, this one seems a bit weird, like, how can you give this guy credit for doing something sensible. This is just caching. He just says, “Well, instead of figuring out what the first one should look like and then figuring out what the second one should look like, figure out what both of those should look like at the same time” kind of. It’s basically just caching it, it remembers what the path is and says, “Well, you’re the same so I’ll give you the same thing.” Rule hashes are slightly more interesting. It’s just another form of caching. What it does is it gets all the key selectors and then creates this table or this hash of them and it says, “Well, every time I look at something that’s got p.legal, I’m going to compare it and see if it’s any of these things.” Which for a big page with loads and loads of selectors makes things so much faster, especially if you’ve got lots of long selectors. It covers your back on it because if you’ve got the same selector, the same long selector a few times or you’ve got lots of elements that are matched by one long selector, then it solves that problem for you, then it turns into one jump instead of five or six jumps.

[00:12:13] I forget who said this, I’m pretty sure it’s anti as well, “Use in moderation, everything will perform just fine from the style matching perspective.” Which is a bummer for me because I’m up here, on stage, talking to you guys and trying to tell you that you should write good CSS. Like I said, this is only for WebKit and a few of the other browsers that are starting to do similar things, which is getting to be quite a few. Which is good for us and good for the consumers but at the same time, we have to remember the poor starving children in Africa who have an XP machine that they get to turn on three times a day, no, three times a year and can browse the internet. If we’re slowing that down for them, then that’s a huge bummer to them and to our users. I’m here saying you can do some really horrible stuff to the browser but please don’t. Make your browser’s job easy because that’s your job.

[00:13:12] I haven’t really said much because in that case you can just go home and keep doing what you were doing because you guys are developers and you just Chrome, obviously, because who would use Edge? Yes, there’s nothing that you can go home me and say, “Right, now I know that I’m going to do something differently.” I thought I’d bring in some other projects that you guys can use to actually help your CSS now. CSS.benjaminbenben, say hello, Ben. It’s pretty cool; it draws lots of pretty lines over images. You type in Google.com and then it shows you all the selectors they use, which is quite a few, actually. Then it draws lines through all the elements that use those selectors, which is really cool because then you can see, well, actually, maybe I can just get rid of these couple of classes and squish them together and make my classes more composable. Who was it? Render? There was talk about that kind of thing, making your classes composable which is more structure than optimising. That means that you can reduce the number of selectors which reduces the memory load and selector engine issues.

[00:14:28] Then we’ve got stuff like framework, blank framework CSS in capsulation. This is surprising helpful because it makes things super explicit because it can grab the class name that you’re using and then say, “Well, instead of worrying about going to a global namespace and putting everything everywhere, I’m just going to make really, really super specific classes and IDs for all of your elements and your DOM.” This can really, really help and sometimes they do a lot of optimisations for you, like the Webpack CSS loader is really, really awesome. Then you’ve got things like Reactive.JS, React, and Riot; things with components in them that let you define components. You can usually give them some styles and they’ll figure out and namespace it for you. CSS is super repetitive, in case anybody hadn’t noticed that. Lots of similar characters and similar words, so gzip it on the server side is super important. It means that you download it a lot quicker and then it’s easier to cache as well. Just be careful that you don’t end up sending huge things with loads and loads of similar selectors and keywords when you could just compress it to nothing.

[00:15:39] CCS stress tester, this is fun even if it’s only just so you can click the button and watch your page shake around like crazy. What it does is it tweaks loads and loads of different global things, it changed the way your scroll is, what the zoom is really, really quickly, multiple times in a second and then tries to work out how fast your thing is rendering. This is just a bookmark and it gives you this huge report about everything you could improve. This is something you should run on every page you ever work on, ever. It’s just super useful and it takes like 30 seconds to run and it’s a bookmark, so you can go off and check your email and do whatever it is you were doing while looking at this pretty thing shaking around everywhere. CSS Shrink, now, this image was going to be the most helpful. CSS Shrink is incredibly smart in that it will say, “Right, you’ve got something here that says colour hash f000 and something here that says FF0000 and you’ve got something here that says red, so we’ll just turn everything into colour red.” It turns longer versions – even if you’re only saving a character, well, maybe loads of hex codes which can just be using a browser red word or a browser colour word, that kind of thing. It makes it so much shorter. I really wish I had the image, it explains it for me.

[00:17:07] Okay. Bibliography, writing efficient CSS. The story behind this talk was I read this thing and then I went onto the JSOxford GitHub thing and created a new issue saying, “I want to talk about this thing” because this is amazing. What I’ve learned from reading that is incredible. Then I get an email saying, “Hey, Joe. It would be great; can you do this talk soon?” Then I say, “Yes, sure.” Then I go back to this page and I see at the top there’s this yellow banner saying, “By the way, this was written ten years ago, could you go read this thing” which is talking about all the good things that have happened, which is Antti. This talk and that taught me a lot. I’d recommend you read that, even if it’s just for historical understanding of what you either used to do wrong or not can avoid for older browsers. This is the new one that it warned me about. This was even in 2011 and this is when some of the really awesome stuff started happening. There have been even more amazing things happening since.

[00:18:13] There are about 300 places that have tiny, tiny, tiny chunks of information about the history of CSS. You’d think going to the guys who write the specs, that have all the information about when the specs were written, there is some of that but it’s really spread out everywhere. I’ve got loads and loads of bookmarks. If anybody’s actually genuinely interested in that, I can compile a list. You can go home now. Yes, if anyone has any questions about either structuring CSS, as in BEM or functional CSS, that kind of thing, come grab me because that’s stuff I’ve been doing a lot of at work, which inspired me to look at more about this thing. For the record, lots and lots of classes that do one thing really well is actually quite fast because it’s just a really shallow lookup. Then just come grab me or ask me any questions. Awesome.