How to draw lines of a tree structure

Viewed 193

I used css grid to output the exact structure of the element which is shown in the image. Only thing that is missing is the lines as you see in the image below. Most important thing is that the code is concise, clean and DRY. I was thinking about using pseudo-element, only it will not help to write readable code.

Please don't use SASS

.three {
  display: grid;
  grid-template-rows: repeat(7, 100px);
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1em;
  
  grid-template-areas:
  
     ".  C  ."
     ".  .  B-1"     
     "A  B  B-2"     
     ".  .  B-3"
     ".  D  ."
     ".  E  .";
}

.A   { grid-area: A; }
.B   { grid-area: B; }
.C   { grid-area: C; }
.D   { grid-area: D; }
.E   { grid-area: E; }
.B-1 { grid-area: B-1; }
.B-2 { grid-area: B-2; }
.B-3 { grid-area: B-3; }

.unordered-list {
  background-color: lightgreen;
  list-style-type: none;
  display: flex;
  justify-content: center;
  align-items: center;
}
<ul class="three">
  <li class="unordered-list A">A</li>
  <li class="unordered-list B">B</li>
  <li class="unordered-list C">C</li>
  <li class="unordered-list D">D</li>
  <li class="unordered-list E">E</li>  
  <li class="unordered-list B-1">B-1</li>
  <li class="unordered-list B-2">B-2</li>
  <li class="unordered-list B-3">B-3</li>
</ul>

2 Answers

I tried to solve your problem in order to show you the way you can do it but notice that you're viewing or running it in snippet in full screen or expand snippet otherwise lines wont fit


.three {
  display: grid;
  grid-template-rows: repeat(7, 100px);
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1em;
  grid-template-areas: ".  C  ." ".  .  B-1" "A  B  B-2" ".  .  B-3" ".  D  ." ".  E  .";
}

.A {
  grid-area: A;
}

.B {
  grid-area: B;
}

.C {
  grid-area: C;
}

.D {
  grid-area: D;
}

.E {
  grid-area: E;
}

.B-1 {
  grid-area: B-1;
}

.B-2 {
  grid-area: B-2;
}

.B-3 {
  grid-area: B-3;
}

.unordered-list {
  background-color: lightgreen;
  list-style-type: none;
  display: flex;
  justify-content: center;
  align-items: center;
  width: 300px;
  position: relative;
}

.A::before,
.B::before {
  content: '';
  position: absolute;
  left: 300px;
  width: 200px;
  height: 4px;
  background: #ccc;
}

.B-1::before,
.B-3::before,
.C::before,
.D::before,
.E::before {
  content: '';
  position: absolute;
  right: 300px;
  width: 80px;
  height: 4px;
  background: #ccc;
}

.row {
  background: #ccc;
  width: 4px;
}

.second {
  position: relative;
  top: 166px;
  right: 79.3px;
  height: 230px;
}

.first {
  position: relative;
  top: 50px;
  left: 356px;
  height: 580px;
}
<ul class="three">
  <li class="unordered-list A">A</li>
  <span class="first row"></span>
  <li class="unordered-list B">B</li>
  <li class="unordered-list C">C</li>
  <li class="unordered-list D">D</li>
  <li class="unordered-list E">E</li>
  <span class="second row"></span>
  <li class="unordered-list B-1">B-1</li>
  <li class="unordered-list B-2">B-2</li>
  <li class="unordered-list B-3">B-3</li>
</ul>

This is my attempt using ::before and ::after:

.three {
  display: grid;
  grid-template-rows: repeat(7, 100px);
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 1em;
  width: 44rem;
  grid-template-areas: ".  C  ." ".  .  B-1" "A  B  B-2" ".  .  B-3" ".  D  ." ".  E  .";
}

li {
  position: relative;
}

.A {
  grid-area: A;
}

.B {
  grid-area: B;
}

.C {
  grid-area: C;
}

.D {
  grid-area: D;
}

.E {
  grid-area: E;
}

.B-1 {
  grid-area: B-1;
}

.B-2 {
  grid-area: B-2;
}

.B-3 {
  grid-area: B-3;
}

.A::after,
.B::after {
  content: "";
  position: absolute;
  right: 0;
  transform: translateX(100%);
  display: block;
  background: grey;
  width: 45px;
  height: 3px;
}

.B-1::before,
.B-3::before,
.C::before,
.D::before,
.E::before {
  content: "";
  position: absolute;
  left: 0;
  transform: translateX(-100%);
  display: block;
  background: grey;
  width: 20px;
  height: 3px;
}

.B::before,
.B-2::before {
  content: "";
  position: absolute;
  left: 0;
  transform: translateX(-23px);
  display: block;
  background: grey;
  width: 3px;
  height: 235px;
  border-top-left-radius: 5px;
  border-bottom-left-radius: 5px;
}

.B::before {
  height: 583px;
  transform: translate(-23px, 58px);
}

.unordered-list {
  background-color: lightgreen;
  list-style-type: none;
  display: flex;
  justify-content: center;
  align-items: center;
}

li {
  border-top-left-radius: 5px;
  border-bottom-right-radius: 5px;
  width: 200px;
}
<ul class="three">
  <li class="unordered-list A">A</li>
  <li class="unordered-list B">B</li>
  <li class="unordered-list C">C</li>
  <li class="unordered-list D">D</li>
  <li class="unordered-list E">E</li>
  <li class="unordered-list B-1">B-1</li>
  <li class="unordered-list B-2">B-2</li>
  <li class="unordered-list B-3">B-3</li>
</ul>

It's not responsive but it get's the job done. If anyone could make it responsive I'd love to see it.

Related