Estructura de árbol con CSS y HTML

A veces viene bien poder representar datos en una estructura de árbol como la que produce el programa tree. El programa tree produce una salida de un árbol de directorios como esta:


✔ /var/www/html/Repos/Freak-Spot/freak-theme [master|✔] $ tree
.
├── static
│   ├── css
│   │   └── style.css
│   ├── genericons
│   │   ├── COPYING.txt
│   │   ├── genericons.css
│   │   ├── Genericons.eot
│   │   ├── Genericons.svg
│   │   ├── Genericons.ttf
│   │   ├── Genericons.woff
│   │   ├── LICENSE.txt
│   │   └── README.md
│   ├── images
│   │   ├── creativecommons_public-domain_80x15.png
│   │   ├── gnu-head-mini.png
│   │   └── questioncopyright-favicon.png
│   └── js
│       ├── functions.js
│       └── jquery-3.1.1.js
└── templates
    ├── archives.html
    ├── article.html
    ├── article_info.html
    ├── author.html
    ├── authors.html
    ├── base.html
    ├── category.html
    ├── index.html
    ├── page.html
    ├── pagination.html
    ├── period_archives.html
    ├── tag.html
    ├── taglist.html
    └── tags.html

6 directories, 28 files

Para representar la instrucción tal como aparece en una terminal he utilizado las etiquetas HTML <samp> y <pre> (<pre><samp>salida de tree</samp></pre>). ¿Pero que pasa si quiero incluir un enlace o utilizar otros elementos de HTML, o CSS? Entonces tendremos que usar CSS para mostrar la apariencia de ramas.

Vamos a usar la salida anterior como ejemplo. Esta se puede expresar así en HTML:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Lista en árbol</title>
  </head>
  <body>
    <div class="contenedor-arbol">
      <ul>
        <li>static
          <ul>
            <li>css
              <ul>
                <li>style.css</li>
              </ul>
            </li>
             <li>genericons
               <ul>
                 <li>COPYING.txt</li>
                 <li>genericons.css</li>
                 <li>Genericons.eot</li>
                 <li>Genericons.svg</li>
                 <li>Genericons.ttf</li>
                 <li>Genericons.woff</li>
                 <li>LICENSE.txt</li>
                 <li>README.md</li>
               </ul>
             </li>
            <li>images
              <ul>
                <li>creativecommons_public-domain_80x15.png</li>
                <li>gnu-head-mini.png</li>
                <li>questioncopyright-favicon.png</li>
              </ul>
            </li>
            <li>js
              <ul>
                <li>functions.js</li>
                <li>jquery-3.1.1.js</li>
              </ul>
              </li>
          </ul>
        </li>
        <li>templates
          <ul>
            <li>archives.html</li>
            <li>article.html</li>
            <li>article_info.html</li>
            <li>author.html</li>
            <li>authors.html</li>
            <li>base.html</li>
            <li>category.html</li>
            <li>index.html</li>
            <li>page.html</li>
            <li>pagination.html</li>
            <li>period_archives.html</li>
            <li>tag.html</li>
            <li>taglist.html</li>
            <li>tags.html</li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
</html>

Primero debemos establecer las reglas para que la lista y su contenedor no interfieran con el dibujo que haremos posteriormente utilizando la regla border de CSS.

.contenedor-arbol, .contenedor-arbol ul, .contenedor-arbol li {
    position: relative;
}

.contenedor-arbol ul {
    list-style: none;
}

A continuación cambiamos la posición de los pseudoelementos para tener espacio para las líneas del árbol.

.contenedor-arbol li::before, .contenedor-arbol li::after {
    content: "";
    position: absolute;
    left: -12px;
}

Posteriormente, utilizando pseudoelementos dibujamos las líneas horizontales (::before) y las verticales (::after).

.contenedor-arbol li::before {
    border-top: 1px solid green;
    top: 9px;
    width: 8px;
    height: 0;
}

.contenedor-arbol li::after {
    border-left: 1px solid brown;
    height: 100%;
    width: 0px;
    top: 2px;
}

El último retoque es hacer que la rama no se extienda de más en el último elemento.

.contenedor-arbol ul > li:last-child::after {
    height: 8px;
}

El resultado es el siguiente:

Abajo dejo el código completo. Obviamente, se pueden hacer modificaciones y cambiar muchas medidas para lograr una apariencia y una funcionalidad más personalizada.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Lista en árbol</title>
    <style>
      .contenedor-arbol, .contenedor-arbol ul, .contenedor-arbol li {
          position: relative;
      }

      .contenedor-arbol ul {
          list-style: none;
      }

      .contenedor-arbol li::before, .contenedor-arbol li::after {
          content: "";
          position: absolute;
          left: -12px;
      }

      .contenedor-arbol li::before {
          border-top: 2px solid green;
          top: 9px;
          width: 8px;
          height: 0;
      }

      .contenedor-arbol li::after {
          border-left: 2px solid brown;
          height: 100%;
          width: 0px;
          top: 2px;
      }

      .contenedor-arbol ul > li:last-child::after {
          height: 8px;
      }
    </style>
  </head>
  <body>
    <div class="contenedor-arbol">
      <ul>
        <li>static
          <ul>
            <li>css
              <ul>
                <li>style.css</li>
              </ul>
            </li>
             <li>genericons
               <ul>
                 <li>COPYING.txt</li>
                 <li>genericons.css</li>
                 <li>Genericons.eot</li>
                 <li>Genericons.svg</li>
                 <li>Genericons.ttf</li>
                 <li>Genericons.woff</li>
                 <li>LICENSE.txt</li>
                 <li>README.md</li>
               </ul>
             </li>
            <li>images
              <ul>
                <li>creativecommons_public-domain_80x15.png</li>
                <li>gnu-head-mini.png</li>
                <li>questioncopyright-favicon.png</li>
              </ul>
            </li>
            <li>js
              <ul>
                <li>functions.js</li>
                <li>jquery-3.1.1.js</li>
              </ul>
              </li>
          </ul>
        </li>
        <li>templates
          <ul>
            <li>archives.html</li>
            <li>article.html</li>
            <li>article_info.html</li>
            <li>author.html</li>
            <li>authors.html</li>
            <li>base.html</li>
            <li>category.html</li>
            <li>index.html</li>
            <li>page.html</li>
            <li>pagination.html</li>
            <li>period_archives.html</li>
            <li>tag.html</li>
            <li>taglist.html</li>
            <li>tags.html</li>
          </ul>
        </li>
      </ul>
    </div>
  </body>
</html>

Comentarios