Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vertical Tree with CSS and HTML

I Am trying to draw a vertical tree like structure with HTML and CSS. I have done it to some extent.

Fiddle

<!--
We will create a family tree using just CSS(3)
The markup will be simple nested lists
-->
<div class="tree">
    <ul>
        <li>
            <a href="#">Parent</a>
            <ul>
                <li><a href="#">Child</a>
                    <ul>
                        <li><a href="#">Grand Child</a></li>
                    </ul>
                </li>
                <li>
                    <a href="#">Child</a>
                    <ul>
                        <li><a href="#">Grand Child</a></li>
                        <li><a href="#">Grand Child</a>
                            <ul>
                                <li><a href="#">Great Grand Child</a></li>
                                <li><a href="#">Great Grand Child</a></li>
                            </ul>
                        </li>
                    </ul>
                </li>
            </ul>
        </li>
    </ul>
</div>

In my case, a node can have maximum 2 childs, not more than that. I have got it working for the first child node. In case of second child, am not getting the vertical line to 100%(till its parent node).

I have tried doing some tweaks but none of them worked. What could I change to my CSS, so it will get all the nodes connected and looks like a tree?

Is it possible to do with CSS itself? or is it possible to by adding some javascript?

like image 644
Naga Avatar asked Aug 13 '15 17:08

Naga


1 Answers

If you have a limited set of possibilities and not looking for something very dynamic, one thing you could do is add classes with different top and height for your :after pseudo element and apply classes in your html to you li elements depending on what each need. Something like that for example:

.tree li::after{
    content: '';
    position: absolute; top: 0;

    width: 3%; height: 50px;
    right: auto; left: -2.5%;

    border-bottom: 1px solid #ccc;
    border-left: 1px solid #ccc;
    border-radius: 0 0 0 5px;
    -webkit-border-radius: 0 0 0 5px;
    -moz-border-radius: 0 0 0 5px;
}
.tree li.two-step::after{
    top: -100px;
    height: 150px;
}

.tree li.three-step::after{
    top: -180px;
    height: 230px;
}

https://jsfiddle.net/g2ue3wL5/1/

EDIT:

Handling :after pseudo-elements dynamically isn't so easy (at least not for me...). There's not really a way to handle them directly, you have to go through their actual element, and even then you need to work with CSS. So a dynamic solution with :after wouldn't be the best approach I think.

But you could replace them with span, and work with jQuery. This gives you a relatively small and easy solution. First, add a span to each a element:

<li><a href="#">Child</a> <span></span>    
<li><a href="#">Grand Child</a><span></span>

Then, in your CSS replace :after with > span:

.tree li > span {
    content:'';
    position: absolute;
    top: 0;
    width: 3%;
    height: 50px;
    right: auto;
    left: -2.5%;
    border-bottom: 1px solid #ccc;
    border-left: 1px solid #ccc;
    border-radius: 0 0 0 5px;
    -webkit-border-radius: 0 0 0 5px;
    -moz-border-radius: 0 0 0 5px;
}

And you go through each of these span and make some calculations to set height and top depending on the parent:

$('.tree li > span').each(function () {
    var thisNewTop = $(this).closest('ul').offset().top - $(this).offset().top; 
    var thisNewHeight = $(this).offset().top - $(this).closest('ul').offset().top + 50;

    $(this).css({
        top: thisNewTop,
        height: thisNewHeight
    });
});

https://jsfiddle.net/g2ue3wL5/3/

The equivalent solution in plain javascript would be much longer, I think it's the kind of situation where jQuery can save a lot of time.

like image 139
Julien Grégoire Avatar answered Nov 11 '22 20:11

Julien Grégoire