Sitemaps and DOM structure from nested unordered lists

Image for post
Image for post

“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.)

Update, March 2020:

Pavel Tomas contacted me, to suggest that I should make the tree view editable. It’s such a good idea, I couldn’t resist, so here’s a version where you can create your own trees. Note that nothing is saved, so as soon as you refresh the page, all of your work will be lost (the only way I can think to save your trees is to use the DOM inspector). I’ve also converted the CSS to SCSS (with CSS3 variables) and fixed a “magic numbers” rule in the original CSS.

Knight-errant Web Developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store