Geoff Garside

Jul 24 2008

Nicely wrapped lists

One of the projects I’m working on we have a model which can have a certain type. This type is essentially free form but at the same time we don’t want a huge long list types that were all nearly about the same. We also don’t want to go all out on the AJAX autocomplete yet either. So the obvious answer was a list or select box of the existing types. We also needed to accept new types, so we needed a text field as well.

Now I don’t know about you but I’m lazy, and if there was a select box and a text field, I’d probably just fill in the text field. So I opted for a list of radio buttons. The downside to this was that list could probably get wildly out of control very quickly if a large number of types existed.

Now I sort of wanted a way to have that list wrap around after a certain number of list items. I could have used fixed width floated list items and a fixed width ol element but this isn’t terribly flexible. Instead I opted to try out the :nth-child selector.

I started out with

/* Clears the padding so it doesn't wrap on the :after */
form fieldset ol.columned li:nth-child(3n) {
  padding-right: 0;
}
form fieldset ol.columned li:nth-child(3n):after {
  content:'';
  display:block;
}

which had the right effect in Opera 9.51 but not in anything else. Of course the support of :nth-child is presently limited to Opera 9.51 and Safari 3 so my testing options were at least contained.

So the goal was to get it working properly in Safari 3 so I threw it open to Tom and Andrew to see if they could get anywhere with it. A couple of minutes later Tom had a working solution with floats which had only one bug, the first line would have 2 elements, the rest would have 3. It also turns out Andrew had also reached this point but hadn’t let me know yet. So we had

form fieldset ol.columned li:nth-child(3n) {
  padding-right: 0;
  clear: left;
}

which was working with only the aforementioned bug. Fortunately I’d been playing with the :nth-child selector for a while at this point and was able to get the desired effect by changing the :nth-child function from 3n to 3n+1. So the final solution was

form fieldset ol.columned li:nth-child(3n+1) {
  padding-right: 0;
  clear: left;
}

Next I wanted the text field to be on a separate line from the rest of the options, fortunately with the wrapping cracked we only needed to tell the last li element to also clear:left;

form fieldset ol.columned li:last-child,
form fieldset ol.columned li:nth-child(3n+1) {
  padding-right: 0;
  clear: left;
}

and we had the desired effect, as you can see in the example below.

Nicely wrapped list

Now I’ve rather poorly tracked this on Gist.GitHub as well if any one is interested, but as you can see from the picture its working pretty well. I’ve got nice semantic list of types and controlled wrapping of that list to boot.

Now as I’ve mentioned the :nth-child selector is only supported by Opera 9.51 and Safari 3 at this time, Firefox 3.1 reportedly has support and is expected to come out in a couple of months. We can’t forget one other Inconvenient Exception which shall not be named. Fortunately this is for the admin side of this project so I can at least have some control over the list of supported browsers I have to tackle.

While I was doing this I thought about all the table rows I’ve ever cycled a class on and javascript functions I’ve written to re-stripe those rows when sorting. I look forward to the day when we can do away with those and just have a nice set of rules like this

table tbody tr:nth-child(even) {
  background-color: #f5f5f5;
}

and leave the re-striping of table rows to the more efficient browser CSS engine.

Comments
blog comments powered by Disqus