In our last post, we built a simple pure-CSS tree from a nested list. That tree was horizontally oriented, but what if we wanted a vertically oriented tree? Today, let’s build that.
We left our tree last in this state:
See the Pen css-tree__8 by Stephen Margheim (@smargh) on CodePen.
Let’s take that same HTML, the lessons we learned from our horizontal tree, and start over to build a vertically oriented tree. We can start with our basic .tree
styles, our node styles, our our li
styles; however, we will need to flip the flex-direction
of the li
s:
.tree { list-style: none; &, * { margin: 0; padding: 0; } li { display: flex; flex-direction: column; align-items: center; } span { border: 1px solid; text-align: center; padding: 0.33em 0.66em; }}
See the Pen css-tree-vertical__1 by Stephen Margheim (@smargh) on CodePen.
This gets us heading in the right direction, but we need to have siblings on the same horizontal row. Well, in our HTML, how are is a sibling group defined? As a list (either a ul
or ol
). And if we want a group of elements to be rendered on the same horizontal row, we can use the flex-direction: row
property. So, let’s apply that to all of the lists (both the top most .tree
list and any descendant lists):
.tree { &, ul, ol { list-style: none; display: flex; flex-direction: row; } // ...}
See the Pen css-tree-vertical__2 by Stephen Margheim (@smargh) on CodePen.
Now that is starting to look good! Let’s now add our parent-to-child connector, which we want to render down from the bottom of a parent node. Since all we are doing is rotating our tree, we should be able to simply “rotate” the CSS used for our horizontal tree:
.tree { // .... ul, ol { padding-top: 2vh; position: relative; // [connector] parent-to-children &::before { content: ""; position: absolute; top: 0; left: 50%; border-left: 1px solid; height: 2vh; } }}
See the Pen css-tree-vertical__3 by Stephen Margheim (@smargh) on CodePen.
Next, let’s go ahead and add the child-to-parent connector:
.tree { // ... li { // ... position: relative; padding-top: 2vh; // [connector] child-to-parent &::before { content: ""; position: absolute; top: 0; left: 50%; border-left: 1px solid; height: 2vh; } }}
See the Pen css-tree-vertical__4 by PMACS Team X (@smargh) on CodePen.
Once again, we need to remove any parent-related connectors from the root node:
.tree { // ... > li { padding-top: 0; &::before, &::after { display: none; } }}
See the Pen css-tree-vertical__5 by Stephen Margheim (@smargh) on CodePen.
Finally, we simply need to add the sibling connector:
.tree { // ... li { // ... // [connector] sibling-to-sibling &::after { content: ""; position: absolute; top: 0; border-top: 1px solid; } // [connector] sibling-to-sibling:last-child &:last-of-type::after { width: 50%; left: 0; } // [connector] sibling-to-sibling:first-child &:first-of-type::after { width: 50%; right: 0; } // [connector] sibling-to-sibling:middle-child(ren) &:not(:first-of-type):not(:last-of-type)::after { width: 100%; } }}
See the Pen css-tree-vertical__6 by Stephen Margheim (@smargh) on CodePen.
The only major bit we will add for now is some vertical spacing between children nodes by adding
padding-left: 0.5vw;padding-right: 0.5vw;
to the li
selector.
See the Pen css-tree-vertical__7 by Stephen Margheim (@smargh) on CodePen.
Since our vertical tree is really only a “rotation” of our horizontal tree, in our next post, we will consolidate these two components into one .tree
component with two modifiers.