Know Your CSS

How many times have I had to fix a style bug... and had to untangle a jungle of CSS to do so? It happens far more often than not, I'd go so far as to say it's at least twice as common as opening a CSS file with only minor problems or inconsistencies.

I think this all has a lot to do with copy / paste programming. "I'm trying to make a spinnning cube with fancy arrows on the sides... Oh look, somebody wrote some code to make a spinning cube on SO... and here's a fancy arrow, SWEET! I'll just take that and paste the whole big chunk into my CSS file. Now change a few selectors, adjust some of the pixel values. Voila!"

-- CSS file length: 58 lines

Well, it's not quite right, but it's closer than you were before. So you start to make tweeks. Add some CSS here, adjust those values. Oh, this selector should actually be on the UL, no wait, the LI... okay, I get it now, it should be on the first child of the LI... and soon your selector looks like it deserves it's very own 4k block on the disk. But it works... so you leave it alone... and checkin right before heading home for the weekend. Maybe you have plans to simplify the selector later... maybe you just have plans to go home and have a beer. In any case, it's checked in, now. That code can and probably will live on in perpetuity.

-- CSS file length: 72 lines

A week later... or a month... or whatever, somebody wants to change how it appears... it should be taller, a little to the left, and the text should be bigger and *BOLD*. Oh can we make it all capitals, too? So they add some more styles, making them a little (or a lot) more specific than the previous styles. After all, they didn't want anything about how it currently works to be different... and that other code is just a horrible mess. You'll lay your pretty little overrides at the end of the file, where they can be applied last. Only, your overrides aren't overriding, your !importants aren't making a difference. Oh, why is this display: inline... one more override making it inline-block shouldn't cause problems. Now, it's working.

-- CSS file length: 103 lines

Let's do a quick run through and clean this up before I check it in. Then you get a call, it's your wife, or your brother, or your mom, or even your kids football coach. They need your attention, they want you to come home, to check out this web site, or this suspect email, or that craigslist ad, or why is their internet broken, or did you get to watch Game of Thrones last night? Eventually, you shift your attention back to the screen in front of you. You see your site... it looks just like the mock. Your checkin command is already typed, or initiated, or prompting you for a description. What did I change again? Oh, well... I guess... "Make adjustments per client requirement." That'll do... it's almost 5:30, for the love of Pete. Submit, commit, checkin, get that code into the repository so you're teammates halfway across the world can build on your progress.

It happens to the best of us. It happens or we go a week with only a single checkin to show for it... and we don't finish, because nobody could build anything without that piece of style being in the codebase. Well, we know not finishing isn't an option... so we checkin, we checkin often. We go fast and we make mistakes. We wear those mistakes like a badge of honor, until the code makes it to PROD and there's a P1, oh wait, they downgraded to a P2, since it only affects iPhones running the previous version of iOS. Phew...

Weeks go by... months... maybe even a year with only minor changes and bug fixes. So minor, that they slide right under your radar.

And now, NOW, the client's design agency has a marvelous idea... he's bounced it off of all of his design buddies, they all think it's brilliant. We need to soften the edges, square the corners, make the background a combination of 3 different gradients, and fix this obscure bug, that only ever happens on this one kind of device... but the client's buddy has one, and he was totally embarrassed when he was trying to show off what his brain hath wrought. So you dive back in...

-- CSS file length: 186 lines

So, now we go in and try to fix up some of the mess that we created a year ago... delete some lines that aren't actually doing anything, like the float: left on an element that has position: absolute in the same block. Let's go slow, do this right... we don't want anymore bugs. Refresh your browser, okay everything looks good. Proceed cleaning up code, adding styles where necessary to make the changes requested by the client (I can't believe I wrote this garbage... was I really that bad at CSS). Everything's done, the CSS isn't great... it's not even all that good, yet... but it's better than you found it. You check in.

-- CSS file length: 168 lines

UAT goes great, they saw a couple of issues, but they're not blockers, you'll have them fixed by the next release you promise, but we should be able to go live with what we have this week. WOOT! Things are looking up.

Release day rolls around. Your changes go out, the release is a success! Wait, your QA may have found an issue... but it might be configuration. Okay, yea it's an issue. The rotator that G-Team added to this same bit of code is no longer working. The layout goes wonky anytime it's turned on... and it's turned on for hundreds of sites. So you go into preprod and take a look... Yep it's broken... hmm, what could have caused this? What did I change that could have this effect? Eventually, you just back out your whole changelist (your lazy engineer mentality led you to checking the refactor and your features in the same checkin... so you backout everything. Rerelease goes great, though a great many teams are now giving you evil eyes for making them recertify the release.

-- CSS file length: 186 lines

Upon further investigation, you find that the code the G-Team added a couple of months ago overrides the position: absolute (with jQuery, of course) and depends on the float: left you took out. So you resubmit your previous changelist with that small tweak. You test extra in dev, before checking in... no bugs this time. Is this all the configuration for this widget? Send out an email to all teams. Please smoketest the style and functionality of this stuff. No need to fully regress, my team is taking care of it.

-- CSS file length: 171 lines (counting the 2 lines of comments with the float)

A little while later, another team gets a request for something very similar to what you created. The team asks for your help to untangle the CSS, and you do what you can... but it isn't enough. They can't seem to get their simple modification working without ten thousand little bugs in both the previous implementation and the new. So, they back out some of their changes (can't get them all, since other teams have already built other functionality on top of some of them).

-- CSS file length: 300 lines

We'll just build a *new* widget, they say. We'll do this one right! We are good at CSS!!! Not like that last guy... and the cycle starts again.

I honestly don't know how to fix this problem. I think front-end developers completely comprehending everything they type into their text editor will help, but that seems like an unrealistic goal. As a healthy, young field, we will have a constant influx of junior developers that are just getting their feet wet... most don't even know where to go to get good information on these different properties and rules (MDN is a great resource for this, BTW).

Having senior engineers, that do understand most of CSS carefully code review each checkin would be good, too. However, those senior engineers are working and building stuff, too... and there's just not enough to go around.

BEM and OOCSS are ugly... and they don't really fit with how CSS is intended to work. Cascading style sheets, cascading beautifully down the DOM. Also, I'm sure you eventually end up in similar snares... it may take a little longer, and your selectors may not turn ugly, but that doesn't help with the extraneous rules and override hell.

Also, to be completely honest, I'm a firm believer in the idea that you have to have a very firm understanding of the intended functionality before you can have the best written code. However, to have that kind of understanding usually requires you write some code, probably even a lot of code... try to get it working code.

So, maybe the best way to get this all to work is to require the code to be written twice for every piece of functionality.

  1. Write (or copy / paste) the CSS to make it work... be sure that you understand every line of CSS that goes into the file. Look up the stuff you're even partially unclear on.
  2. Verify you got everything working correctly, keep going until you do...
  3. Revert all checkins related to this feature.
  4. Write it again... no peeking at the previous versions. Use what you learned while writing it the first time. Write your classes to better reflect the problem space, now that you have a better understanding.

I think that could go a long way... but, ultimately, that also seems unrealistic. Maybe even more unrealistic than the other two options. In many cases, you have different people across teams on different sides of the world checking in changes on top of each others changes daily... and this only really works when it's a single engineer working on the problem.

@phillipwills #knowcss