htmlcsstext-styling

Auto indenting lines in html using css


The desired result from this code is for the lines to auto indent, based on the previous sibling element. Right now the best I can do is hardcoded CSS classes, which I've included in the below example.

If possible, I'd like to have the text indent out for the open class, and indent down for the close class. Though really, anything would be better than what I currently have. I'm hoping I can replicate how many websites currently structure the visible code, like typed in this above HTML.

.cd_tag {
  text-align: left;
  color: black;
  height: auto;
  width: 80%;
  outline-color: black;
  outline-width: 2px;
  outline-style: dotted;
  background-color: rgb(238, 238, 238);
}


/* html text(default text) */
.ht_txt {
  color: black;
}


/* html tag styling */
.ht_tag {
  color: red;
}


/* add < & >, encapsulting html tags */
.open::before {
  font-weight: lighter;
  content: "<"
}

.open::after {
  font-weight: lighter;
  content: ">";
}

.close::before {
  font-weight: lighter;
  content: "</"
}

.close::after {
  font-weight: lighter;
  content: ">"
}


/* a couple tab classes to make the structure easier to read */
.tab1 {
  margin-left: 2rem;
}

.tab2 {
  margin-left: 4rem;
}

.tab3 {
  margin-left: 6rem;
}

.tab4 {
  margin-left: 8rem;
}

.tab5 {
  margin-left: 10rem;
}

.tab6 {
  margin-left: 12rem;
}
<div class="cd_tag">
  <div class="ht_tag">
    <div class="open">!DOCTYPE html</div>
    <div class="open tab1">html</div>
    <div class="open tab2">head</div>
    <div class="open tab3">style</div>
    <div class="close tab3">style</div>
    <div class="close tab2">head</div>
    <div class="open tab2">body</div>
    <div class="close tab2">body</div>
    <div class="close tab1">html</div>
  </div>
</div>


Solution

  • Edit:

    Actually it is possible to automatically indent elements based on the net sum of preceding "open" (+1) and "close" (-1) elements if you use a CSS counter() function.

    You can increment and decrement a counter for each .open and .close element, respectively. Then you can use the @counter-style CSS at-rule to create a custom counter style. Setting the system to symbolic will let you output N number of a specified symbol, where N is equal to the counter's value. Setting symbols to a couple non-breaking spaces lets the counter act as an indenter, indenting the contents of the element to the correct level:

    @counter-style custom {
      system: symbolic;
      symbols: '\2003\2003';
    }
    .parent {
      border: 1px solid black;
      margin: 1rem;
      padding: 1rem 1rem 1rem 0;
      font-family: monospace;
      counter-set: level 0;
    }
    .open,
    .close {
      color: #b75301;
    }
    .open:first-child,
    :not(.close) + .open,
    .content {
      counter-increment: level 1;
    }
    :not(.open) + .close {
      counter-increment: level -1;
    }
    .open:before,
    .open:after,
    .close:before,
    .close:after {
      color: black;
    }
    .open:after,
    .close:after {
      content: '>';
    }
    .open:before {
      content: counter(level, custom) '<';
    }
    .close:before {
      content: counter(level, custom) '</';
    }
    .content:before {
      content: counter(level, custom);
    }
    <div class="parent">
      <div class="open">html</div>
      <div class="open">head</div>
      <div class="open">style</div>
      <div class="close">style</div>
      <div class="close">head</div>
      <div class="open">body</div>
      <div class="open">p</div>
      <div class="content">Lorem Ipsum</div>
      <div class="close">p</div>
      <div class="close">body</div>
      <div class="close">html</div>
    </div>


    Previous answer:

    This is technically possible using the adjacent sibling selector, but you'd have to add styles for every potential combination of preceding classes (see below). It's not possible (without javascript) to just total up the net "opens" and "closes" preceding an element using CSS.

    You're better off using the .tab-* classes as you currently are. You could automate adding them with javascript though, to make things easier.

    /* probably don't do this */
    .open + .open {
      margin-left: 2rem;
    }
    .open + .open + .open {
      margin-left: 4rem;
    }
    .open + .open + .open + .open {
      margin-left: 6rem;
    }
    .open + .open + .open + .open + .close {
      margin-left: 6rem;
    }
    .open + .open + .open + .open + .close + .close {
      margin-left: 4rem;
    }
    .open + .open + .open + .open + .close + .close + .open {
      margin-left: 4rem;
    }
    .open + .open + .open + .open + .close + .close + .open + .close {
      margin-left: 4rem;
    }
    .open + .open + .open + .open + .close + .close + .open + .close + .close {
      margin-left: 2rem;
    }
    
    .cd_tag {
      text-align: left;
      color: black;
      height: auto;
      width: 80%;
      outline-color: black;
      outline-width: 2px;
      outline-style: dotted;
      background-color: rgb(238, 238, 238);
    }
    
    
    /* html text(default text) */
    .ht_txt {
      color: black;
    }
    
    
    /* html tag styling */
    .ht_tag {
      color: red;
    }
    
    
    /* add < & >, encapsulting html tags */
    .open::before {
      font-weight: lighter;
      content: "<"
    }
    
    .open::after {
      font-weight: lighter;
      content: ">";
    }
    
    .close::before {
      font-weight: lighter;
      content: "</"
    }
    
    .close::after {
      font-weight: lighter;
      content: ">"
    }
    <div class="cd_tag">
      <div class="ht_tag">
        <div class="open">!DOCTYPE html</div>
        <div class="open">html</div>
        <div class="open">head</div>
        <div class="open">style</div>
        <div class="close">style</div>
        <div class="close">head</div>
        <div class="open">body</div>
        <div class="close">body</div>
        <div class="close">html</div>
      </div>
    </div>