CSS Rant - 1 year later
Back in February I wrote a post complaining about some common css issues that I was running into. I’ve now spent more than a year maintaining and working on the same app, and I have a few things to add. This post is organized by phase, in order of how I did CSS.
Phase 1: Team fail and screen.css
My app initially was written by three people who were not in communication with each other. This lead to a screen.css file that was nearly ten thousand lines long. Everybody except me used arcane-sounding acronyms like “mtb1” that nobody else used because they didn’t want to waste time finding out what things meant.
This resulted in screen.css bulging entirely out of control.
Lessons
Use coherent naming. If we had used names that made sense to humans, we might have been able to share more classes.
Don’t stick everything at the bottom of one file. As we went through building pages, everyone would just stick all their css at the bottom of screen.css. Since nobody was thinking beyond their work, none of the classes we were writing were really applicable to other pages. This meant that screen.css was doomed to keep growing.
Don’t let business people be in charge of design. If the final word on whether something has a rounded corner or not doesn’t belong to the person who actually has to make the corner round in html/css, you’ll end up with massive fail.
In an early-stage startup, the person who has to actually deal with complexity should also be the person making decisions about whether something should be complex or not. Otherwise, you end up with stuff that just was not worth 10 hours getting to work in ie6, that nobody even cares about 3 months later, and then gets deleted 8 months later. Those 10 hours could have been used on something more important, like figuring out how to make something that people will pay for.
Phase 2: immaculate body ids
After a few months of screen.css, I decided to do things much cleaner for a marketing page redesign that we decided to do. I decided that divs were ugly, and basically did everything without them. To deal with the problem of collaboration, I eventually just had everyone make their own css file and put their stuff in it.
Lessons
Start with text, then add markup where it makes sense. This is a great way to do html. Rather than starting with divs, just write all the text. Then add header tags, and uls and divs only where it really makes sense.
Be a little bit sloppy. Coming up with perfect div-less styles that work in every browser is great. But it really sucks to make changes to. If you’re working in a situation where other people have approval power over your work, you should wait until the last minute to get everything clean. Otherwise you’ll want to kill anyone who asks for a change because it means you have to re-test everything and some of the abstractions that you used have to be broken.
Your css does not work in ie7 just because you think you are smart. During this phase, I also worked with a few other developers. Lots of designers and developers love to talk about how they write “clean, cross-browser CSS.” When you actually hire them though, they pretty much all fail to even have crossover or wine installed. The best way to deal with this, I found, was simply to not accept their work until it worked in ie. Over time, they figured out how to test.
Breaking up CSS by developer doesn’t work. This is the wrong way to collaborate on css. You end up having to edit each others files, and the styles for a single page end up getting spread out between multiple developers’ files over the course of several months.
Phase 3: Inline everything
After about 7 months, we now had tens of thousands of lines of CSS. This was entirely too much to deal with, so I just started inlining all the styles on everything.
By this point, I was leading product development, which meant that I made decisions about complexity. This meant that inlining everything really wasn’t that bad, since the site basically consisted of green buttons and black text.
Lessons
Inlining everything isn’t that bad. This actually doesn’t suck that much. Especially when your design is relatively simple. The fact of having to see all your css in the html is a good motive for keeping things simple. It also solves several problems that are hard to solve otherwise, like collaborating on a page and dealing with stylesheet bloat of tons of half-used classes. If everything is just on the page, a lot of complexity goes away.
Inlining everything makes pages hard to read. On the other hand, pages with entirely inline styles become pretty messy and hard to read. While this isn’t the worst thing, it seemed unnecessary.
Phase 4: Rails like organization
After catching a talk by Ryan Singer, I started organizing CSS like I would Rails view files. This strikes a happy medium between inlining and trying to write styles for all occasions.
A global h2 style probably isn’t going to last more than a month before everyone starts changing it inline or by id. This means that global styles end up getting in the way 8 months down the line.
On the other hand, inline styles are ugly. The best solution to this is to put your css into the same structure as your views.
For example, if you have a users_controller, then you would have a users.css file. If you’re really style-heavy, then you might have a users folder in stylesheets, and new.css, edit.css and show.css inside the folder.
This is a really great way to organize things, because it allows for both using outside css files, but also for controlling bloat because it keeps everything nice and modular.
Major Lessons
Don’t write too many global styles. Abstract styles just end up being over written. You know this is a problem when you starting having to use !important everywhere.
Top down is the wrong way to do CSS. Like everything else in programming, trying to plan out what your pages are all going to look like leads to fail. This may be easy for web shops that get to build an app, give it to the customer, and forget about it, but when you have to deal with something for a year you realize that planning ahead for what future pages will look like (e.g. every page will have a “tips” section) is idiotic.
Having lots of files doesn’t really matter. Plugins like asset_packager make it trivial to bundle and compress multiple stylesheets in production.
The person doing the ui should be the person in charge of the details. Statements like “let’s make that line darker,” lead to massive time sink. If you want something changed, either make a really compelling case for it, that would make a difference in an a/b test, or do it yourself.
By keeping CSS modular, and using REST conventions, you get the best of all worlds. It’s much easier to collaborate on users/edit.css than it is to collaborate on lines 8000 to 8500 of screen.css. It’s much easier to find which styles are being used in a 100 line css file than a 20k line one. It makes much more sense to have styles organized by domain than by function. For example, trying to keep all of your “layout + grid” styles in one place doesn’t make sense of the grid is changing over time and is different for different areas.
October 26, 2009
