Search code examples
cssnodestreenodeangular-ui-tree

Angular-ui-tree shows an extra line when last child has children


I have tried different CSS tricks and hacks but can't seem to get my way around this. So, I have a UI tree with connectors as shown in below:

https://jsfiddle.net/jqaw41mo/

div.panel:first-child {
  margin-top: 20px;
}

div.treeview {
  min-width: 100px;
  min-height: 100px;
  max-height: 256px;
  overflow: auto;
  padding: 4px;
  margin-bottom: 20px;
  color: #369;
  border: solid 1px;
  border-radius: 4px;
}

div.treeview ul:first-child:before {
  display: none;
}

.treeview,
.treeview ul {
  margin: 0;
  padding: 0;
  list-style: none;
  color: #369;
}

.treeview ul {
  margin-left: 1em;
  position: relative
}

.treeview ul ul {
  margin-left: .5em
}

.treeview ul:before {
  content: "";
  display: block;
  width: 0;
  position: absolute;
  top: 0;
  left: 0;
  border-left: 1px solid;
  /* creates a more theme-ready standard for the bootstrap themes */
  bottom: 15px;
}

.treeview li {
  margin: 0;
  padding: 0 1em;
  line-height: 2em;
  font-weight: 700;
  position: relative
}

.treeview ul li:before {
  content: "";
  display: block;
  width: 10px;
  height: 0;
  border-top: 1px solid;
  margin-top: -1px;
  position: absolute;
  top: 1em;
  left: 0
}

.tree-indicator {
  margin-right: 5px;
  cursor: pointer;
}

.treeview li a {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}

.treeview li button,
.treeview li button:active,
.treeview li button:focus {
  text-decoration: none;
  color: inherit;
  border: none;
  background: transparent;
  margin: 0px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
  outline: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->

<div class="container">
  <div class="panel panel-default">
    <div class="panel-heading">Treeview List</div>
    <div class="panel-body">
      <!-- TREEVIEW CODE -->
      <ul class="treeview">
        <li><a href="#">Tree</a>
          <ul>
            <li><a href="#">Branch</a></li>
            <li><a href="#">Branch</a>
              <ul>
                <li><a href="#">Stick</a></li>
                <li><a href="#">Stick</a></li>
                <li><a href="#">Stick</a>
                  <ul>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a>
                      <ul>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                      </ul>
                    </li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a></li>
                  </ul>
                </li>
                <li><a href="#">Stick</a></li>
              </ul>
            </li>
            <li><a href="#">Branch</a></li>
            <li><a href="#">Branch</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</div>


This look fine but the problem arises when the last child of a particular node has a child. The problem is recreated in the link below:

https://jsfiddle.net/3vxjerg2/

div.panel:first-child {
  margin-top: 20px;
}

div.treeview {
  min-width: 100px;
  min-height: 100px;
  max-height: 256px;
  overflow: auto;
  padding: 4px;
  margin-bottom: 20px;
  color: #369;
  border: solid 1px;
  border-radius: 4px;
}

div.treeview ul:first-child:before {
  display: none;
}

.treeview,
.treeview ul {
  margin: 0;
  padding: 0;
  list-style: none;
  color: #369;
}

.treeview ul {
  margin-left: 1em;
  position: relative
}

.treeview ul ul {
  margin-left: .5em
}

.treeview ul:before {
  content: "";
  display: block;
  width: 0;
  position: absolute;
  top: 0;
  left: 0;
  border-left: 1px solid;
  /* creates a more theme-ready standard for the bootstrap themes */
  bottom: 15px;
}

.treeview li {
  margin: 0;
  padding: 0 1em;
  line-height: 2em;
  font-weight: 700;
  position: relative
}

.treeview ul li:before {
  content: "";
  display: block;
  width: 10px;
  height: 0;
  border-top: 1px solid;
  margin-top: -1px;
  position: absolute;
  top: 1em;
  left: 0
}

.tree-indicator {
  margin-right: 5px;
  cursor: pointer;
}

.treeview li a {
  text-decoration: none;
  color: inherit;
  cursor: pointer;
}

.treeview li button,
.treeview li button:active,
.treeview li button:focus {
  text-decoration: none;
  color: inherit;
  border: none;
  background: transparent;
  margin: 0px 0px 0px 0px;
  padding: 0px 0px 0px 0px;
  outline: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
<!------ Include the above in your HEAD tag ---------->

<div class="container">
  <div class="panel panel-default">
    <div class="panel-heading">Treeview List</div>
    <div class="panel-body">
      <!-- TREEVIEW CODE -->
      <ul class="treeview">
        <li><a href="#">Tree</a>
          <ul>
            <li><a href="#">Branch</a></li>
            <li><a href="#">Branch</a>
              <ul>
                <li><a href="#">Stick</a></li>
                <li><a href="#">Stick</a></li>
                <li><a href="#">Stick</a>
                  <ul>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a>
                      <ul>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                      </ul>
                    </li>
                    <li><a href="#">Twig</a></li>
                    <li><a href="#">Twig</a>
                      <ul>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                        <li><a href="#">Leaf</a></li>
                      </ul>
                    </li>
                  </ul>
                </li>
                <li><a href="#">Stick</a></li>
              </ul>
            </li>
            <li><a href="#">Branch</a></li>
            <li><a href="#">Branch</a></li>
          </ul>
        </li>
      </ul>
    </div>
  </div>
</div>


As seen, the last twig has three leaves, the border-left on the last-child property did not help my case.

Is there any solution to this?


Solution

  • The line is generated by the border of .treeview ul:before pseudo element. Since its height is not defined it will have the height of the entire ul, and its border will be to the left of the entire ul.

    In order to shorten this border you can define the height of the :before pseudo element.

    If your HTML is static you can just add classes to the problematic ul elements and define a height to the .treeview ul.problematic:before selector.

    https://jsfiddle.net/kc5jx1wy/

    div.panel:first-child {
      margin-top: 20px;
    }
    
    div.treeview {
      min-width: 100px;
      min-height: 100px;
      max-height: 256px;
      overflow: auto;
      padding: 4px;
      margin-bottom: 20px;
      color: #369;
      border: solid 1px;
      border-radius: 4px;
    }
    
    div.treeview ul:first-child:before {
      display: none;
    }
    
    .treeview,
    .treeview ul {
      margin: 0;
      padding: 0;
      list-style: none;
      color: #369;
    }
    
    .treeview ul {
      margin-left: 1em;
      position: relative
    }
    
    .treeview ul ul {
      margin-left: .5em
    }
    
    .treeview ul:before {
      content: "";
      display: block;
      width: 0;
      position: absolute;
      top: 0;
      left: 0;
      border-left: 1px solid;
      /* creates a more theme-ready standard for the bootstrap themes */
      bottom: 15px;
    }
    
    .treeview ul.problematic:before {
      height: 238px;
    }
    
    .treeview li {
      margin: 0;
      padding: 0 1em;
      line-height: 2em;
      font-weight: 700;
      position: relative
    }
    
    .treeview ul li:before {
      content: "";
      display: block;
      width: 10px;
      height: 0;
      border-top: 1px solid;
      margin-top: -1px;
      position: absolute;
      top: 1em;
      left: 0
    }
    
    .tree-indicator {
      margin-right: 5px;
      cursor: pointer;
    }
    
    .treeview li a {
      text-decoration: none;
      color: inherit;
      cursor: pointer;
    }
    
    .treeview li button,
    .treeview li button:active,
    .treeview li button:focus {
      text-decoration: none;
      color: inherit;
      border: none;
      background: transparent;
      margin: 0px 0px 0px 0px;
      padding: 0px 0px 0px 0px;
      outline: 0;
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.0/js/bootstrap.min.js"></script>
    <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
    <!------ Include the above in your HEAD tag ---------->
    
    <div class="container">
      <div class="panel panel-default">
        <div class="panel-heading">Treeview List</div>
        <div class="panel-body">
          <!-- TREEVIEW CODE -->
          <ul class="treeview">
            <li><a href="#">Tree</a>
              <ul>
                <li><a href="#">Branch</a></li>
                <li><a href="#">Branch</a>
                  <ul>
                    <li><a href="#">Stick</a></li>
                    <li><a href="#">Stick</a></li>
                    <li><a href="#">Stick</a>
                      <ul class="problematic">
                        <li><a href="#">Twig</a></li>
                        <li><a href="#">Twig</a></li>
                        <li><a href="#">Twig</a></li>
                        <li><a href="#">Twig</a>
                          <ul>
                            <li><a href="#">Leaf</a></li>
                            <li><a href="#">Leaf</a></li>
                            <li><a href="#">Leaf</a></li>
                          </ul>
                        </li>
                        <li><a href="#">Twig</a></li>
                        <li><a href="#">Twig</a>
                          <ul>
                            <li><a href="#">Leaf</a></li>
                            <li><a href="#">Leaf</a></li>
                            <li><a href="#">Leaf</a></li>
                          </ul>
                        </li>
                      </ul>
                    </li>
                    <li><a href="#">Stick</a></li>
                  </ul>
                </li>
                <li><a href="#">Branch</a></li>
                <li><a href="#">Branch</a></li>
              </ul>
            </li>
          </ul>
        </div>
      </div>
    </div>

    However, if your HTML is generated dynamically you'll have to use JavaScript to calculate the needed height for each ul and apply the CSS with code.