CSS Classes State Machine Puzzle

It is quite nature to code CSS classes as “states” in a web applications. Say if you have three <div class="view">s within the <body> tag, you can easily toggle the class of the body to show/hide the views, with one-off CSS animations as view-to-view transitions, right? Wrong.

It turns out, it works with two states even with transition/animation, but not so much if there are three states. For two states like A & B, there is only one possible route to get into each state, A→B for B, and B→A for A. However, if there are three states, A would have routes B→A and C→A, and so on. It’s basically n*(n-1) for n states.

How do you specify two different CSS animations for the two routes? This doesn’t sounds like a common question, but I have personally encountered twice in different projects, and I bet sooner or later this would happen to everyone as we moved from DOM animation to CSS and rely more and more on browser to run the animation smoothly.

One way to look at it would be that this is a design flaw of the CSS language. There should be some pseudo-class like :was() to specify what exact route to match against. However, inventing a pseudo-class just for the animation property doesn’t sound like a great idea.

The other way, and a more practical approach is to look for solution with what we have right now. Inevitably, to distinguish route B→A and route C→A, one should introduce immediate states, making the routes B→A’→A and C→A”→A. Yet, this further complicate things if one would like the scripting part stay as a clean finite-state machine: First, the transition of A’→A will depend on animationend event, which couples the CSS code with Javascript code. Second, and the bummer that makes the solution incomplete, is that the animationend event will never fire if the state changes again during the A’ or A” state, which make it necessary to handling the changing in Javascript code again ourselves. Good luck on codify all the A’→B, A”→C, A’→C, … transitions.

Now you know how hard it is to write a mobile OS window manager with Javascript + CSS. There might be some obvious answers I overlooked, if you would like to give your solutions, feel free to comment here or post it on your own blog.

Unintended consequence and path dependence

In To understand the command line… (highly recommend to read thoroughly), the author quoted Rob Pike, who wrote about the dot files convention in the early days of the Unix environment:

I’m pretty sure the concept of a hidden file was an unintended consequence. It was certainly a mistake.

Coincidentally, it’s been said in a comment of the article What No One Told You About Z-Index, that early CSS design decisions is, in fact, driven by how Netscape’s layout logic in the Mozilla code base had worked at the time.

I wouldn’t know if the statement about CSS history is true or not. However, it’s true that many of the cornerstones we have on web development, like some of the designs of the DOM, CSS, HTML, are unintended consequences, amplified by path dependence.

Mozilla, just like Netscape, or Bell Labs, does not float in the haven, where the developers have infinite time and knowledge to foresee everything. We have our partners and schedules to answer to, too. However, I do feel that working in Mozilla as a web developer is a privileged role, that we should, to the best of my knowledge, avoid unintended consequences, like what Rob states vividly above.

Sort things out: code, project, and open source

As a pet project that kind of fit into the end-of-year mood, I spent some of my personal time re-releasing my previous code projects. In this post, I will announce the repositories I created and try to document additional works I did on those projects.

The projects are:

All these repositories are created with original commit history. Battling with git filter-branch is quite challenging but fun. I disassemble the work done in HTML5 Word Cloud in order to achieve maximum re-useability; by re-useability, I am also referring to having the code understandable and fixable by others. I’ve already use the Google OAuth 2 Login in an unannounced project and it works great. My goal is to eventually rewrote HTML5 Word Cloud and have it use the libraries from these individual repositories, with slick, better UIs.

These are the things I learned, and implemented:

Coding style, comments, and variable naming

One of the first thing I learned from working in Mozilla is to express thoughts to people, not computers, through code. In fact, in collaborative project like Mozilla, having people understand your code is way more important than having computers run them effectively. To achieve that, code written should be:

  • Promote shared understanding through unified coding style. Avoid magical syntax that could confuse the reader.
  • Also, promote shared understanding by annotating the work with comments. David Flanagan (Yes, the David) did amazing work in the Gaia code base on this, but sadly we failed to catch up that.
  • No secretive variable names; this is particularly rampant in the wordcloud2.js, and I haven’t been able to fix them all.

Testing and continuous integration

No, I’ve never wrote automatic tests for my projects until this commit. Before that, all the test is done manually by try out the actual product, or on manual test pages.

In WordFreq and Google OAuth 2 Web Client, I (re)wrote QUnit tests for most of the functionalities. The test coverage is not quite there yet, and for Google OAuth 2 library there are no automatic tests in PhantomJS because some tests must be done with a logged-in session.

I’ve also hook up automatic tests of WordFreq to Travis CI. It’s nice to know such service exists that could further reinforce the fork-commit-pull-request contribution cycle on Github. Unfortunately WordFreq fail randomly on the Travis CI testing VM.

Beyond browser context

Javascript does not just live the the browser. With WordFreq, I tried node.js this time. WordFreq is rewritten in a way that it comes with a synchronous interface and a asynchronous interface (powered by Web Workers). With synchronous interface, WordFreq is available as a npm package and is accessible on the command line. node.js is fun, I would love to use it for more stuff and move away from shell scripting. 🙂

Toward a real collaborative open source project

Putting your work on Github is easy, but nurturing that to a solid free software project is hard. You would just need to learn and adopt some software engineering practices besides writing great code, in order to effectively contribute to the free software ecosystems. These are my baby-steps toward that; feedback and contribution welcome!