Adler
Adler

Reputation: 2807

How can I specifically "exclude" an element from a css grid/subgrid or position it correctly in a complex entanglement of nested grids…

* {
  outline: 1px solid rgba(255, 0, 0, .2);
}

ol {
  *:not(li) {
    grid-area: none;
    /* hmmm... this is not right*/
  }
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: min-content 1fr;
  grid-column: subgrid;
  li {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    width: 100%;
  }
}

ol {
  counter-reset: Nr;
  *::before {
    font-variant-numeric: tabular-nums;
    overflow-wrap: normal;
    word-break: keep-all;
  }
  >li {
    counter-increment: Nr;
    &::before {
      content: counter(Nr) ".";
      text-align: end;
      margin-right: 0.85rem;
    }
    >ol {
      counter-reset: lit;
      >li {
        counter-increment: lit;
        &::before {
          content: counter(lit, lower-latin)')';
        }
        >ol {
          counter-reset: sublit;
          >li {
            counter-increment: sublit;
            &::before {
              content: counter(sublit, lower-roman) '.';
            }
          }
        }
      }
    }
  }
}
<ol>
  <li>
    This is <strong>txt</strong> hi.
    <ol>
      <li>This li is not affected.</li>
    </ol>
  </li>
</ol>

I would like to have all inline-elements such as the strong from the example behave normally and not get influenced by any grid/subgrid layouts… Also, everything in the same li after the strong element in the example is broken, too.

What I have tried so far is manipulating the display property and the grid property of any non-li item. My latest approach is in the code with a comment next to it.

It should look like this: [It should look like this1

But the snippet output is:

enter image description here

Why I am using grid? I want to have maximum control over the width of the numbers/bullets, their "padding" (e. g. exactly centering a variable/unknown-width number in the "column of numbers") and the extent of indentation of any sub-lists...

For example: indent from the left should be exactly 1 cm while perfectly centering what ever bullet is being used + aligning numbers with different digit lengths to another correctly and letting any sub-lists numbering begin with its left edge exactly where the previous li text started... and so on, all at the same time and with granular control and maximum flexibility.

Upvotes: 0

Views: 121

Answers (3)

Brett Donald
Brett Donald

Reputation: 14340

This is the grid solution you are looking for.

The key to the solution (and yes, it is slightly annoying) is to add some extra wrapper elements in your HTML. For any <li> which contains another explicit element such as <strong> or <a>, wrap its entire contents with another element ... I have used a <div>. (Of course, you can make it easy by just adding the additional wrapper inside every <li>.)

ol {
  margin-left: 1em;
  padding: 0;
  counter-reset: l1;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0 0.5em;
}

ol > li {
  list-style: none;
  display: contents;
}

ol > li::before { 
  content: counter(l1) '.';
  counter-increment: l1;
}

ol ol {
  counter-reset: l2;
}

ol ol > li::before { 
  content: counter(l2, lower-latin) ')';
  counter-increment: l2;
}

ol ol ol {
  counter-reset: l3;
}

ol ol ol > li::before { 
  content: counter(l3, lower-roman) '.';
  counter-increment: l3;
}
<ol>
  <li>
    <div>
      This is <strong>txt</strong> hi.
      <ol>
        <li>
          <div>a <a href="">link</a> here.
            <ol>
              <li>
                <div>
                  a <a href="">link</a> here.
                </div>
              </li>
              <li>This li is not affected.</li>     
            </ol>
          </div>
        </li>
        <li>
          <div>
            This <strong>li is not</strong> affected.
          </div>
        </li>
        <li>This li is not affected.</li>
      </ol>
    </div>
  </li>
  <li>This li is not affected.</li>
  <li>This li is not affected.</li>
</ol>

Upvotes: 0

Adler
Adler

Reputation: 2807

grid-area: none; was wrong

instead I used display: contents;

Nested lists did not display correctly then. But this is just because they were not accounted for in the :not() function. Added ol and ul to the function.

Now everything displays correctly.

* {
  outline: 1px solid rgba(255, 0, 0, .2);
}

li > *:not(ul, ol) {
    /* I have added ol, ul to the :not() function to make list nesting work again and improved the syntax*/
    
    display: contents; /* this fixes it */    
  }
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: min-content 1fr;
  grid-column: subgrid;
  li {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: subgrid;
    width: 100%;
  }
}

ol {
  counter-reset: Nr;
  *::before {
    font-variant-numeric: tabular-nums;
    overflow-wrap: normal;
    word-break: keep-all;
  }
  >li {
    counter-increment: Nr;
    &::before {
      content: counter(Nr) ".";
      text-align: end;
      margin-right: 0.85rem;
    }
    >ol {
      counter-reset: lit;
      >li {
        counter-increment: lit;
        &::before {
          content: counter(lit, lower-latin)')';
        }
        >ol {
          counter-reset: sublit;
          >li {
            counter-increment: sublit;
            &::before {
              content: counter(sublit, lower-roman) '.';
            }
          }
        }
      }
    }
  }
}
<ol>
  <li>
    This is <strong>txt</strong> hi.
    <ol>
      <li>This li is not affected.</li>
    </ol>
  </li>
</ol>

Upvotes: 0

Temani Afif
Temani Afif

Reputation: 273839

I would consider float to achieve the same layout. I don't think CSS grid is the right approach.

ol {
  padding: 0;
  list-style: none;
  overflow: hidden; /* this */
}

ol {
  counter-reset: Nr;
  *::before {
    font-variant-numeric: tabular-nums;
    overflow-wrap: normal;
    word-break: keep-all;
  }
  li {
    counter-increment: Nr;
    clear: both; /* and this */
    &::before {
      content: counter(Nr) ".";
      text-align: end;
      margin-right: 0.85rem;
      /* and this */
      margin-bottom: 2px;
      float: left;
      /**/
    }
    ol {
      counter-reset: lit;
      li {
        counter-increment: lit;
        &::before {
          content: counter(lit, lower-latin)')';
        }
        ol {
          counter-reset: sublit;
          li {
            counter-increment: sublit;
            &::before {
              content: counter(sublit, lower-roman) '.';
            }
          }
        }
      }
    }
  }
}
<ol>
  <li>
    This is <strong>txt</strong> hi.
    <ol>
      <li>a <a href="">link</a> here.
          <ol>
            <li>a <a href="">link</a> here.</li>
            <li>This li is not affected.</li>     
          </ol>
      </li>
      <li>This <strong>li is not</strong> affected.</li>
      <li>This li is not affected.</li>
    </ol>
  </li>
  <li>This li is not affected.</li>
  <li>This li is not affected.</li>
</ol>

Upvotes: 0

Related Questions