Sitemaps and DOM structure from nested unordered lists

“Tongue out” by Thom Quine on Flickr.

Recently, I was putting together a presentation for work based on my pure CSS select box (now featuring actual JavaScript!). It’s not a completely successful experiment (although, in my defence, as far as I know, no-one else has managed to do it before), so I was busy turning it into a sort of rambling shaggy-dog story, where the junior developers might learn a thing or two along the way, even if the final destination is full of fleas and smells of wee.

One of the concepts I wanted to cover was adjacent and sibling selectors. A nice way to visualise them is to show a tree diagram of the DOM, then indicate how interactions on one node could influence other nodes (long story short: a CSS selector on a child node cannot influence the parent). To create this diagram, I initially did a quick search which led to Draw.io. It’s fine, I suppose, but I wanted something which could convert input data — XML or JSON, for example — into a tree diagram automatically.

Next, I fired up Inkscape, but I just had to draw one text box and one box with curved corners before I lost heart and closed it down.

“Surely”, I thought to myself, “this is possible in pure CSS?”

This is probably how real programmers think all the time. “Did you fill in your timesheet this week, Alice?” “No — I didn’t like your timesheet software, so I’m rewriting it from scratch. Should be done by the end of next week”. That kind of thing.

Anyway, it worked surprisingly well:

“Surprising” because I initially assumed I’d have to use the poorly-supported Flexbox to achieve this layout. Turns out all I needed was display: table; and display: table-cell;. Lovely.

I used Pug because sometimes it’s better to learn a new HTML preprocessor in five minutes, in order to save yourself an hour later.

You might be wondering why I used outline for all those connecting lines, rather than border (actually, what you're probably wondering is "why not use canvas and JavaScript", but that's because you've not read my other posts). The reason I used outline is because it doesn't contribute to the width of the :before and :after elements, whatever box-sizing is set to. Plus no-one uses outline. I feel sorry for it.

Despite this, I’m a little annoyed at some of the fudge in the CSS. I originally wanted to specify the width of the connecting lines as 0.1em, but the actual screen dimensions of this seemed to change, depending upon where it was. Plus the .tree code:before {top: -.55em;} rule annoys me. Perhaps there's something I've overlooked.

Hopefully this code will be useful to someone. Unfortunately, it’s no use for generating a family tree, unless your family manages to reproduce asexually. Which is a dream we all share.

(I did look into getting it working for family trees. The problem is that getting the line to connect to the parent above suggests that the couple should be inside different list items, but getting the line to connect to the grandchildren below suggests they should be inside the same list item. I couldn’t see a simple, JavaScript free way to fix this, so all trees are asexual. There. I’ve finally said it.)

Show your support

Clapping shows how much you appreciated Ross Angus’s story.