So you have to write some CSS

I get it. You’re a python/ruby/java engineer, and you’re building your awesome webapp. The problem is, a webapp needs CSS. And you know… just enough to realize how little you know.

CSS is complicated. It’s not a programming language strictly speaking, but you would probably rather it was; you have learned new languages in the past. But CSS is off in its own little world, a wildly complicated set of rules. Sure, you can usually make a page do what you want. Other times leave you completely baffled and out of your element. You wish you had time to read up on how to do it well, but you have code that needs writing.

So here you go. Here are a handful of nice and easy rules for you. Follow these, and your CSS should be… more presentable than if you didn’t. It will be more maintainable into the future, and that front end engineer your startup will hire as soon as it can afford to will thank you. (Because that engineer may be me!)

  • Make your selectors as generic as possible — Use the shortest selector you can, and apply rules as universally as is reasonable. Say you’re adding a dialog box on your billing page. Don’t specify #billing .dialog if you’ll likely want the same CSS for dialog boxes later on; just use .dialog. (This isn’t completely absolute: if you know you’re dealing with an exception to the rule, keep it specific.)
  • Don’t use !important — Like tribbles, these things are born pregnant, and will multiply faster than you can imagine. Instead, take five minutes to learn how selector specificity works and use the browser dev tools to see which rule is overriding the one you want.
  • Minimize duplication — You organize your code into reusable functions; do the same with your CSS. This is kind of a corollary to the two points above.

    Say you have generic dialog box .dialog { color: blue; }, which is overridden on your billing page with a special rule #billing .dialog { color: red; }. If you later find yourself adding another rule like #account .dialog { color: red; }, STOP!

    Instead, make something reusable: .dialog-important { color: red; }. Then you don’t need to touch your CSS yet again when you encounter a third page that needs the same thing!

  • CSS must be refactored — Just like your code, CSS rots. Don’t be afraid to tear down and restructure as things evolve.

The DOM as Global State

Let’s look at a common scenario: somewhere, deep inside your module, you need to do something to the DOM. Maybe something like, $("#my-id").show();. Find an element; make it visible. It seems like no big deal, but I want to make an observation:

You just used a global variable.

The DOM is a global state. This is stupidly obvious when I say it this way, but I have never thought about it in these terms before. I’ve seen a lot of code–and written a lot of code–littered with jQuery selectors grabbing elements from all over the page and manipulating them.

Using global state is generally considered an anti-pattern. And yet, I would venture the vast majority of web applications in the wild use it liberally: modules full of functions that reach into the DOM and manipulate various elements. In most applications, this sort of thing would be considered a side-effect. The readability and testability of code are compromised, because there’s no real way to know what a certain function does unless you also know the current state of specific elements on the page. And yet in the web world, it is commonplace.

Considering how much effort we’ve spent getting around the global namespacing problems of JavaScript, it’s pretty ridiculous to realize we’re not much further than where we started. Let’s fix that.

Dependency Injection

Thankfully, the solution here is the same as any other code: Pass the relevant data in as a function parameter. Then your functions and objects can do all they need to do, while acting only on items they are given references to. So instead of this:


function foo () {
    $("#my-div").doSomething();
    $("#my-div .baz").somethingElse();
}
foo();

I have begun structuring my code more like this:


function foo (element) {
    element.doSomething();
    element.find(".baz").somethingElse();
}
foo($("#my-div"));

(For an example using the module pattern, see my answer to this Stack Overflow question. It’s still contrived, but a little bit closer to real-world code. In more complex modules, I generally pass the element into an init() function or an object constructor)

Yes, you still have to perform the global selector, but now the real meat of your code is not dependent upon it. Your code is also able to handle more changes the the DOM without breaking, and in your unit tests, you can now pass in a mocked up element, instead of setting up a specific global state.

You stopped using global variables when you picked up the module pattern and other namespacing tactics. Now stop using them inside your namespaces as well.

My Very Favorite Things

I’ve come across two articles in the past several days that take critical views against something I love and believe in. JavaScript is the new Perl is skeptical of the recent surge in the popularity of Javascript. Five Reasons Why Responsive Design is Wrong for Your Business is skeptical of RWD.

Obviously, being a front end web developer, my someone-is-wrong-on-the-internet alarms started going off, and I “had” to comment on each. Both authors were kind enough to respond to my comments graciously (and left me hoping I didn’t come off as too much of a jerk). They also both clarified their stance a little to say, essentially, “just because tool X is cool and popular right now, doesn’t mean it’s the right answer for everything.” And as much as I love Javascript and RWD, I had to agree.

It’s easy to get absorbed in the excitement of new shiny things. It’s also good to step back and make sure you aren’t blinded to their limits.

It’s also very refreshing to see reasoned discourse on the internet. I don’t think there can be too much hype behind that.

Making QUnit play nice with RequireJS

I finally decided to dive into QUnit. I downloaded it, added it to a project, and punched out a trivial test.

It didn’t take long to discover that it doesn’t exactly work in conjunction with RequireJS. I searched for an answer to the problem, and found several pages suggesting setting QUnit.config.autostart = false after loading QUnit, and calling QUnit.start() after all tests have been loaded.

It didn’t work.

No matter how I reshaped my code to look exactly like the many examples I found, I kept getting “0 of 0 tests passed, 0 failed,” or worse, a blank page.

After several hours of fiddling around, I was on the verge of tossing QUnit entirely and going for a different unit testing framework. Then I stumbled across a mention of QUnit.load(). With nothing left to lose, I tossed it in to my code, and tadow! It worked! So this is the structure I have settled on:

define(['qunit'], function(qunit) {
    var testFiles = ['test', 'modules', 'here'];
    require(testFiles, qunit.load);
});

So what’s the story? QUnit does not like being loaded asynchronously. From what I can tell, this is because it registers an onLoad event. When all sources are loaded, QUnit fires off and runs all the tests that have been queued. Since RequireJS is loading QUnit asynchronously, the onLoad event has already fired, and, depending on how you loaded what, either does nothing, or immediately runs tests, of which there are none.

I haven’t dug into the QUnit source, but my guess is this QUnit.load() method is invoked with the onLoad event. Word of warning, this method is not documented at all in QUnit 1.10.0. So no promises on whether this approach will work in future versions.

Web Platform Docs

Paul Irish just announced the debut of Web Platform Docs, so I had to go check it out. This looks pretty cool. It strikes me as the Mozilla Developer Network meets Wikipedia meets Stack Overflow.

It’s obviously young—a lot of content is pretty minimal at this point, and almost every article I’ve opened is flagged for things like “cleanup” and “missing relevant sections”—but I think there is a lot of potential for this to become the de-facto resource for documentation and help on front end web development. Which is exactly what their stated goal is, and I hope they can achieve it. As it is, I’ll be making some edits to help flush things out.