JS Tree

by Ivan Gerasimenko

HTML

<ul class="Container">
    <li class="Node IsRoot ExpandOpen">
        <div class="Expand ExpandOpen"></div>
        <div class="Content">Root</div>
        <ul class="Container">
            <li class="Node ExpandLeaf">
                <div class="Expand ExpandClosed"></div>
                <div class="Content">Item 1</div>
            </li>
            <li class="Node ExpandLeaf">
                <div class="Expand"></div>
                <div class="Content">Item 2</div>
                <ul class='Container'>
                    <li class="Node ExpandLeaf">
                        <div class="Expand"></div>
                        <div class="Content">Item 2.1</div>
                    </li>
                    <li class="Node ExpandLeaf">
                        <div class="Expand"></div>
                        <div class="Content">Item 2.2</div>
                    </li>
                </ul>
            </li>
            <li class="Node ExpandLeaf">
                <div class="Expand"></div>
                <div class="Content">Item 3</div>
            </li>
        </ul>
    </li>
</ul>

CSS

.Container {
        padding: 0;
        margin: 0;
}

.Container li {
        list-style-type: none; /* убрать кружочки/точечки */
}

/* узел отодвинут от левой стенки контейнера на 18px
    благодаря этим отступам вложенные узлы формируют иерархию
 */
.Node {
    margin-left: 18px;
    zoom: 1; /* спецсвойство против багов IE6,7. Ставит hasLayout */
}

/* Корневой узел от родительского контейнера не отодвинут. 
   Ему же не надо демонстрировать отступом, чей он сын.
   Это правило идет после .Node, поэтому имеет более высокий приоритет 
   Так что class="Node IsRoot" дает margin-left:0
*/ 
.IsRoot {
    margin-left: 0;
}

/* иконка скрытого/раскрытого поддерева или листа
    сами иконки идут дальше, здесь общие свойства
 */
.Expand {
    width: 18px;
    height: 18px;
    /* принцип двухколоночной верстки. */
    /* float:left и width дива Expand + margin-left дива Content */
    float: left; 
}

/* содержание (заголовок) узла */
 .Content {
    /* чтобы не налезать на Expand */
    margin-left:18px;
    /* высота заголовка - как минимум равна Expand 
        Т.е правая колонка всегда выше или равна левой.
        Иначе нижний float будет пытаться разместиться на получившейся ступеньке
    */    
    min-height: 18px; 
}

 /* все правила после * html выполняет только IE6 */
* html .Content {
    height: 18px; /* аналог min-height для IE6 */
}

.Expand:after {
    content: '';
    border: 2px solid #cccccc;
    display: block;
    width: 14px;
    height: 14px;
    position: relative;
    left: -4px;
    top: 1px;
}

/* открытое поддерево */
.ExpandOpen .Expand {  
    /*background-image: url(/forum/img/minus.gif);  */    
}
.ExpandOpen:before {
    content: '';
    display: block;
    width: 10px;
    height: 2px;
    background-color: #aaaaaa;
    position: relative;
    top: 12px;
}

/* закрытое поддерево */
.ExpandClosed .Expand {
    /*background-image: url(/forum/img/plus.gif);*/
}
.ExpandClosed:before {
    content: '';
    display: block;
    width:...