Search code examples
htmlcssdynamiclinedraw

Draw dynamic lines using html and css


Is it possible to draw the following using html and css?

enter image description here enter image description here

I am interested only in lines part. Here is what I tried so far.

html:

<div class="outer">
  <div class="inner">
    <div class="topPart">
      TOP
    </div>
    <div class="middlePart">
      <div class="program selectedProgram">
        <div class="programName">
          foo program
        </div>

        <div class="modulesDiv">
          <div class="module">
           <div class="moduleName">
             foo module foo module foo module foo module foo module
           </div>
          </div>
          <div class="module">
           <div class="moduleName">
             foo short name
           </div>
          </div>
          <div class="module">
           <div class="moduleName">
             foo module foo module foo module foo module foo module
           </div>
          </div>
        </div>
      </div>
    </div>
    <div class="bottomPart">
      BOTTOM
    </div>
  </div>
</div>

css:

.outer {
  background-color: red;
  position: relative;
  margin: 0 auto;
  top: 40px;
  width: 200px;
  height: 2000px;
  background-image: url('https://mdn.mozillademos.org/files/7693/catfront.png');
  background-repeat: no-repeat;
  background-size: cover;
}

.inner {
  position: -webkit-sticky;
  position: sticky;
  top: 0;
  background-color: cyan;
  width: 200px;
  height: 400px/* 100vh */
  ;
}

.topPart {
  position: absolute;
  height: 10%;
  width: 100%;
  top: 0;
  background-color: pink;
  text-align: center;
}

.middlePart {
  position: absolute;
  height: 80%;
  width: 100%;
  top: 10%;
  background-color: yellow;
  text-align: center;
}

.bottomPart {
  position: absolute;
  height: 10%;
  width: 100%;
  top: 90%;
  background-color: #66aa11;
  text-align: center;
}

.program {
  height: auto;
  text-align: left;
  width: 100%;
  cursor: pointer;
  padding-top: 5%;
  padding-bottom: 5%;
  padding-left: 5%;
  padding-right: 5%;
  word-wrap: break-word;
  border-bottom: 1px solid #afadad;
  position: relative;
}

.program.selectedProgram {
  border-left: 4px solid #289efd;
}

.program .programName {
  display: inline;
  font-size: 110%;
  color: #484646;
  padding-left: 5%;
  vertical-align: middle;
}

.selectedProgram.program .programName {
  font-weight: bold;
  color: #289efd;
}

.program:hover .programName {
  color: #289efd;
}

.program .programName {
  white-space: pre-wrap;
  white-space: -moz-pre-wrap !important;
  white-space: -webkit-pre-wrap;
  white-space: -pre-wrap;
  white-space: -o-pre-wrap;
  white-space: pre-wrap;
  word-wrap: break-word;
  word-break: break-all;
  white-space: normal;
}

.modulesDiv {
  height: auto;
  width: 100%;
  position: relative;
  padding-left: 5%;
  padding-top: 5%;
  display: none;
}

.selectedProgram .modulesDiv {
  display: block;
}

.module {
  height: auto;
  text-align: left;
  width: 100%;
  cursor: pointer;
  padding-top: 5%;
  padding-bottom: 5%;
  padding-left: 5%;
  padding-right: 5%;
  word-wrap: break-word;
  position: relative;
}

.program .moduleName {
  display: inline;
  font-size: 110%;
  color: #484646;
  padding-left: 5%;
  vertical-align: middle;
}

.selectedModule.module .moduleName {
  font-weight: bold;
  color: #289efd;
}

.module:hover .moduleName {
  color: #289efd;
}

There are two problems I am facing here.

  1. I do not know how to draw a randomly positioned line using only html and css.
  2. I can not guess beforehand how much height will each module take and hence can not infer in code when I will have to draw a horizontal prong to the module name.

I refer the main name, which is in bold in screenshot as a program name and names which are indented from left as module names.

I hope someone will be able to help at least with something here.


Solution

  • I am not going to implement the details but you could use a well organised structure combined with background size to create the effect you are looking for. I am using a single-pixel SVG background image that you can stretch with background-size to generate the look you want. It also does not sacrifice the actual semantics:

    ul {
      padding: 0;
      margin: 0;
      list-style: none;
      padding-left: 5px;
      background: url( "data:image/svg+xml;charset=utf8,<svg width='100%' height='100%' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' preserveAspectRatio='none'><rect x='0' y='0' width='1' height='1' fill='gray' stroke='none' /></svg>" );
      background-size: 1px calc(100% - .5em);
      background-position: top 0 left 5px;
      background-repeat: no-repeat;
    }
    
    li {
      padding: 0;
      padding-left: 10px;
      background: url( "data:image/svg+xml;charset=utf8,<svg width='100%' height='100%' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' preserveAspectRatio='none'><rect x='0' y='0' width='1' height='1' fill='gray' stroke='none' /></svg>" );
      background-size: 8px 1px;
      background-position: top .5em left 0;
      background-repeat: no-repeat;
    }
    <h1>List</h1>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Lipsum Dolor</li>
      <li>
        Sit Amet:
        <ul>
          <li>Dolor</li>
          <li>Lorem</li>
          <li>Ipsum</li>
          <li>Datia</li>
        </ul>
      </li>
      <li>Other</li>
    </ul>

    Going a little further to make the last item not stretch like crazy we will have to use multiply background definitions, so this cannot be made compatible with some older browsers, but it works regardless:

    ul, h1 {
      padding: 0;
      margin: 0;
      list-style: none;
    }
    
    h1 {
      font-size: 1rem;
      color: gray;
      border-bottom: 1px solid gray;
    }
    
    
    li {
      padding: 0;
      padding-left: 13px;
      background: url( "data:image/svg+xml;charset=utf8,<svg width='100%' height='100%' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' preserveAspectRatio='none'><rect x='0' y='0' width='1' height='1' fill='gray' stroke='none' /></svg>" ), url( "data:image/svg+xml;charset=utf8,<svg width='100%' height='100%' viewBox='0 0 1 1' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' preserveAspectRatio='none'><rect x='0' y='0' width='1' height='1' fill='gray' stroke='none' /></svg>" );
      background-size: 8px 1px, 1px 100%;
      background-position: top .5em left 5px, top 0 left 5px;
      background-repeat: no-repeat, no-repeat;
    }
    
    li:last-of-type {
      background-size: 8px 1px, 1px .5em;
    }
    <h1>List</h1>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Lipsum Dolor</li>
      <li>
        Sit Amet:
        <ul>
          <li>Dolor</li>
          <li>Lorem</li>
          <li>Ipsum</li>
          <li>Datia</li>
        </ul>
      </li>
    </ul>
    
    <h1>'Nother List</h1>
    <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Lipsum Dolor</li>
      <li>
        Sit Amet:
        <ul>
          <li>Dolor</li>
          <li>Lorem</li>
          <li>Ipsum</li>
          <li>Datia</li>
        </ul>
      </li>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Lipsum Dolor<br />Sit Amet Nanaba</li>
    </ul>