Tuesday, April 26, 2011

Tri-state checkbox with CSS

[update 10/23/2014: new blog post on this topic]
[update: see this new post from the always helpful Chris Coyier.]

There is no good way to represent a tri-state checkbox in HTML.
I’ve been googling and hacking around today on this topic. We can at best approximate the tri-state checkbox in HTML, and the methods I’ve found have their pros and cons. I will offer a pure CSS method, which too has its pros and cons. All require some javascript in order to function.

Method 1: Use Images

Here are two examples that simply use images to represent the various states of the checkbox:
You can count on these checkboxes always looking the same, no matter the browser, and no matter the version or the browser. It’s going to work and be consistent.

The jquery tristate-checkbox is available for use with jQuery, which has mainstream use.
You give up the native look and feel of the checkbox. This is even more apparent when the images are on a page along side native checkboxes.

You also give up the nuanced “hover” behaviors of an actual native control. To get this right, the following states should be accounted for:
  no-hover, unchecked
  no-hover, mixed 
  no-hover, checked
  hover, unchecked
  hover, mixed 
  hover, checked
  clicked, unchecked
  clicked, mixed 
  clicked, checked
  disabled, unchecked
  disabled, mixed 
  disabled, checked

Method 2: Use Opacity

In this suggestion, Pau Moreno offers to dial down the opacity (like gmail does somewhere?) to represent the “mixed” state.
You get a purely native checkbox no matter what browser you use, as long as opacity is supported. (Opacity support does go back pretty far, which surprised me. Here’s an example of cross browser opacity css.) A “dimmed” checkbox does not convey the meaning of “mixed” state very well.

Method 3: Use CSS

This is my suggestion, which uses only native HTML checkbox and CSS. Here is a prototype with some hardcoded jQuery.
Here’s what it looks like on XP. (From left to right: Chrome, Firefox, Safari, IE8)
You’ll have to look at the sources and stylesheets. Basically the input tag is followed with a couple of inline div tags which use the CSS relative/absolute position attributes to position a 7x7 green div square atop the checkbox to its left. It is just CSS. The javascript has to interpret the click event on the 7x7 square and “click” the checkbox.
You get a purely native checkbox no matter what browser you use.

It is just CSS, so you can modify the “square” that represents the “mixed” state.
The CSS to position the square is browser dependent. This demo works in Chrome, FF, Safari, and IE7+. However, conditional stylesheets had to be made for IE.

I don’t have a Mac, or X-windows based browser, but I suspect the native checkboxes onthose platforms could be a pixel off in one direction or another from the overlying square. (Give me feedback…)

The overlying square masks the hover event from the native checkbox, so you lose that UI visual nuance when your mouse is over the square.

I’d like to hear some feedback from you, specifically if you see inconsistencies in the demo on other browsers/platforms.

Update 27 APR 2011

First, for the image-based solutions, I found another implementation (by Ryan Morlok) that covers the 12 cases I wanted.  http://softwareblog.morlok.net/2010/06/20/tri-state-checkbox/
Second, a friend sent me a screenshot of the CSS proof of concept rendered on a Mac. (From left to right: Chrome, Firefox, and Safari)
Clearly, separate CSS styles would need to be maintained for multiple platforms, in addition to multiple browsers.
Also, some googling revealed to me that to Mac users, a native tri-state checkbox is rendered with a “dash” rather than a “square”. This is possible to emulate since it is just CSS. Instead of a green 7x7 square, it would be a black 6x2 rectangle.
I also tried loading the proof of concept page on browsershots.org and found many of the unix platforms render the square in the wrong place as well. I’m not surprised.
I’d say this is a big issue for the “Cons” column. The number of platforms and browsers are large, but finite, and you could design the code to minimize the pain of adding new platform/browser offset information. But actually doing the legwork to maintain these nuances is very difficult; even with testing platforms like browsershots.org (and its contemporaries) getting this “just right” is still difficult. But if someone did maintain it, then I think I would really like this solution.
Meanwhile, I’ll vote for any future HTML standards that include a tri-state checkbox.

Sunday, April 3, 2011

Using svn:externals for javadocs on my website

I use subversion to version a simple website. I also use subversion for another project (twilio4j) hosted on Google code. The javadocs for the latter project are kept in the twilio4j repository at Google code.

Lately I have just been manually copying the javadocs directory to my web project, and versioning them there too, then rsyncing my web directory into production like I always have. Today I shortened the number of steps in this task by employing the “svn:externals” property in subversion. It is not a “push one button” build solution, but it is an incremental improvement in my life.

Here’s what I did.

cd /path/to/website
svn propedit svn:externals twilio4j


The twilio4j directory already existed and contained materials pertinent to the twilio4j project. However, the twilio4j dir did *not* have a doc subdirectory – we don’t want it to have that subdirectory since we are going to grab that directory from the google code repository.

Next, the propedit command let me edit the properties of my twilio4j directory with my editor. I added one line to the properties, namely:

doc http://twilio4j.googlecode.com/svn/trunk/twilio4j/doc


I exited my editor, and performed an svn update, which began fetching external content:

svn update

Fetching external item into 'twilio4j/doc'
A    twilio4j/doc/serialized-form.html
A    twilio4j/doc/stylesheet.css
A    twilio4j/doc/allclasses-frame.html
A    twilio4j/doc/overview-frame.html
A    twilio4j/doc/overview-summary.html
A    twilio4j/doc/package-list
A    twilio4j/doc/overview-tree.html
A    twilio4j/doc/index-files

   ... etc ...


I committed my changes to the twilio4j directory (only the properties of that directory were changed).

After committing, an svn status shows that the doc directory is an external source.

svn status
X       twilio4j/doc


With this technique I can quickly and easily update my javadocs to match what is in the twilio4j repository and rsync my website into production.