Древовидный список на CSS
Как-то мне потребовалось сделать иерархическое представление структуры проекта, для реализации был выбран CSS.
Вот что получилось:
Это можно сделать за несколько простых шагов.
Для начала создаем желаемую структуру из вложенных списков и заголовков для них:
Узлы уровней создаются с помощью заголовков H1 — H6. То есть перед каждым новым ветвлением должен быть заголовок. Чтобы они все вели себя одинаково c точки зрения древовидного списка, добавляем им общий класс .header
.
Добавляем отступы и рамки, чтобы видеть структуру.
И вот теперь самое интересное: добавляем полоски, начнем с горизонтальных.
LI:before,
.header:before{
content: "";
display: block;
position: absolute;
left: 0;
bottom: .5em;
width: 15px;
height: 0;
border-bottom: 1px solid #333;
}
Они сделаны абсолютно позиционированными псевдоэлементами. Здесь можно было бы обойтись и inline-block
с вертикальным выравниванием, но position: absolute;
в сочетании с bottom
позволит нам сделать вертикальные линии, направленные вверх.
Чтобы полоски не выпадали из контекста, пунктам списка и заголовкам нужно задать относительное позиционирование, а чтобы они не заезжали на текст — паддинг слева тем же элементам.
LI,
.header {
position: relative;
padding-left: 1.2em;
}
Пока выглядит странно. Большинство полосок встало на места, но некоторые болтаются где попало, потому, что все горизонтальные линии спозиционированны относительно нижнего края элементов.
Теперь добавим вертикальные линии:
.header:last-of-type:before,
LI:last-child:before {
height: 1000px;
border: 1px solid #333;
border-width: 0 0 1px 1px
}
Получится лес вертикальных линий, от которого легко избавиться, задав всем спискам overflow: hidden;
, вот результат:
И теперь в структуре хорошо видно дублирование некоторых линий.
Оно происходит из-за того, что заголовки (.header
) находятся внутри элементов списка (LI
), таким образом они получают две направляющих.
Добавим спискам с заголовками класс .p-has-headers
и покрасим разные направляющие разными цветами, чтобы увидеть что происходит.
.p-has-headers > LI:before {
border-color: red;
}
.header:before,
.header:last-of-type:before{
border-color: green;
}
Направляющие обычных пунктов списка остались черными, направляющие списков с заголовками стали красными, направляющие заголовков — зелеными.
По красным хорошо видно, что некоторые из них находятся не там. Например, на крайней слева вертикали горизонтальные линии совсем мимо, потому, что линии спозиционированы от нижнего края LI
.
Это отлично работает в простом списке, но совсем не подходит для списка с заголовком, потому что в этом случае ветка должна начинаться на уровне заголовка, как это делают зеленые.
Именно поэтому стили прописывались и для LI
, и для .header
. Если есть заголовок — ветка вверх должна вести от него, а не от конца списка. Таким образом, в списках, пункты которого содержат заголовки и которые мы пометили классом .p-has-headers
, можно выключить направляющие для непосредственных наследников кодом вроде UL > LI
.
Код:
.p-has-headers > LI:before {
content: none;
}
Результат:
Получилась довольно простая конструкция, главное — не запутаться в тегах списков, и каждую новую ветку начинать с заголовка.
- Метки:
- эксперименты