0

I have some HTML structure like this:

<ul>
<li>
  <h2>Item 1</h2>
  <dl>
    <div><dt>attr1</dt><dd>value a</dd></div>
    <div><dt>attr2</dt><dd>value b</dd></div>
    <div><dt>attr3</dt><dd>value c</dd></div>
  </dl>
</li>
<li>
  <h2>Item Another One Here</h2>
  <dl>
    <div><dt>attr1</dt><dd>value x</dd></div>
    <div><dt>attr2</dt><dd>value some bit long</dd></div>
    <div><dt>attr3</dt><dd>value z</dd></div>
  </dl>
</li>
</ul>

I want it be rendered as:

---------------------------------------------------------------------
  Item 1
  attr 1: value a  attr 2: value b              attr 3: value c
---------------------------------------------------------------------
  Item Another One Here
  attr 1: value x  attr 2: value some bit long  attr 3: value z
---------------------------------------------------------------------

Attributes are aligned to each other based on the length of theirs contents.

How can I do that?

I would avoid change my markup to <table>, since they are not really tables. I had tried layout them using display: table-*, but that won't work for the title (which should take place of whole row instead of one cell).

tsh
  • 4,263
  • 5
  • 28
  • 47
  • I honestly don't understand the reluctance to use for this particular use case. What you are trying to achieve is a structure.
    is a structural element and built for this purpose. Everything about
    lends itself perfectly for the structure you're trying to achieve (particularly column alignment). Tables have a bad reputation because they were abused and used as a style element, but they still have a purpose.
    – Robert Wade Nov 09 '17 at 13:51
  • @RobertWade the OP explained that he didn't want to use `` markup because it's not tabular data, and CSS tables don't have `colspan` like real tables have (for the full width title). CSS grids do offer [a viable way](https://stackoverflow.com/a/47203811/703717) to create this layout, but to date it's still not perfect. (subgrids are still in the draft spec) In the meantime, we need to additionally use `display: contents` to pull this off
    – Danield Nov 09 '17 at 14:10
  • @Danield I don't like using tables either, but the example provided is a perfect fit for it. The notion that "only tabular data" can be used in tables stems from the abandonment of tables as a primary layout tool (which is a very good thing), however the W3C specification for tables says no such thing. https://www.w3.org/TR/html401/struct/tables.html It recommends using stylesheets for primary layout purposes obviously. This is a long, old argument and my comment was based on the example provided. Had OP shown what he actually intended to use in the layout my opinion might differ. – Robert Wade Nov 09 '17 at 14:44

3 Answers3

1

Just add display inline block to all your values...

dl *{
display:inline-block;
}
<ul>
<li>
  <h2>Item 1</h2>
  <dl>
    <div><dt>attr1</dt><dd>value a</dd></div>
    <div><dt>attr2</dt><dd>value b</dd></div>
    <div><dt>attr3</dt><dd>value c</dd></div>
  </dl>
</li>
<li>
  <h2>Item Another One Here</h2>
  <dl>
    <div><dt>attr1</dt><dd>value x</dd></div>
    <div><dt>attr2</dt><dd>value some bit long</dd></div>
    <div><dt>attr3</dt><dd>value z</dd></div>
  </dl>
</li>
</ul>
Renzo Calla
  • 7,486
  • 2
  • 22
  • 37
1

This layout is possible with the CSS Grid Layout Module

.container {
  display: inline-grid;
  grid-column-gap: 1em;
  grid-template-columns: repeat(3,auto);
  padding: 0;
  background-color: white;
  padding-bottom: 0.5em;
  border-bottom: 2px dashed;
}

.container li, .container dl {
  display: contents;
}

h2 {
  grid-column: 1 / -1;
  font-size: inherit;
  padding: 0.5em 0 0 0;
  border-top: 2px dashed;
}


dl > div, dd, dt {
  display: inline-block;
  padding: 0;
  margin: 0;
}
dt:after {
  content: ':'
}
dd {
 margin-left: 0.5em;
}
dl > div:nth-child(1) {
  background-color: lightblue;
}
dl > div:nth-child(2) {
  background-color: lightgreen;
}
dl > div:nth-child(3) {
  background-color: pink;
}
<ul class="container">
  <li>
    <h2>Item 1</h2>
    <dl>
      <div><dt>attr1</dt>
        <dd>value a</dd>
      </div>
      <div><dt>attr2</dt>
        <dd>value b</dd>
      </div>
      <div><dt>attr3</dt>
        <dd>value c</dd>
      </div>
    </dl>
  </li>
  <li>
    <h2>Item 2 - Another One Here</h2>
    <dl>
      <div><dt>attr1</dt>
        <dd>value y -bla bla </dd>
      </div>
      <div><dt>attr2</dt>
        <dd>value some bit long</dd>
      </div>
      <div><dt>attr3</dt>
        <dd>value z</dd>
      </div>
    </dl>
  </li>
  <li>
    <h2>Item 3 - Another One Here</h2>
    <dl>
      <div><dt>attr1</dt>
        <dd>value x</dd>
      </div>
      <div><dt>attr2</dt>
        <dd>value some much longer</dd>
      </div>
      <div><dt>attr3</dt>
        <dd>value z - blabl bla</dd>
      </div>
    </dl>
  </li>
</ul>

(Codepen demo)

The difficulty here is since the li and dl elements aren't direct children of the grid container - you can't apply grid properties to it.

Grid Layout Module Level 2 - Subgrids (currently a draft spec) are supposed to solve this problem, but in the meantime we can use display:contents to overcome this.

See this post for more details.


If your markup was flat to begin with, then you wouldn't need display: contents and CSS grid module could do this fine:

Cross-browser demo (With 'flat' markup')

.container {
  display: inline-grid;
  grid-column-gap: 1em;
  grid-template-columns: repeat(3,auto);
  padding: 0;
  background-color: white;
  padding-bottom: 0.5em;
  border-bottom: 2px dashed;
}

h2 {
  grid-column: 1 / -1;
  font-size: inherit;
  padding: 0.5em 0 0 0;
  border-top: 2px dashed;
}

dl, dt, dd {
  display: inline-block;
  padding: 0;
  margin: 0;
}
dt:after {
  content: ':'
}
dd {
 margin-left: 0.5em;
}
dl:nth-of-type(3n + 1) {
  background-color: lightblue;
}
dl:nth-of-type(3n + 2) {
  background-color: lightgreen;
}
dl:nth-of-type(3n) {
  background-color: pink;
}
<div class="container">
  <h2>Item 1</h2>
    <dl><dt>attr1</dt><dd>value a</dd></dl>
    <dl><dt>attr2</dt><dd>value b</dd></dl>
    <dl><dt>attr3</dt><dd>value c</dd></dl>
  <h2>Item 2 - Another One Here</h2>
    <dl><dt>attr1</dt><dd>value x</dd></dl>
    <dl><dt>attr2</dt><dd>value some bit long</dd></dl>
    <dl><dt>attr3</dt><dd>value z</dd></dl>
  <h2>Item 3 - Another One Here</h2>
    <dl><dt>attr1</dt><dd>value x</dd></dl>
    <dl><dt>attr2</dt><dd>value some much much much longer</dd></dl>
    <dl><dt>attr3</dt><dd>value z</dd></dl>
</div>

NB:

In order to 'shrink-wrap' the grid I applied display: inline-grid to the grid container.

Danield
  • 121,619
  • 37
  • 226
  • 255
  • Maybe i will flatten my markup use `
    Item 1
    attrvalue
    Item 2
    ...
    ` to avoid `display: content`. Anyway, it seems a great idea. thanks.
    – tsh Nov 10 '17 at 02:05
  • @tsh I added a cross-browser demo with flat markup and also found a better way to shrink-wrap :) – Danield Nov 13 '17 at 09:32
0

i used float to align the items

.f{
 float:left;
 margin:10px;
}

.c{
 clear:both;
}
<ul>
 <hr>
<li>
 
  <h2>Item 1</h2>
  <dl>
    <div class="f">attr1 value a</div>
<!--   <div class="c"></div> -->
    <div class="f">attr2 value b</div>
    <div class="f">attr3 value c</div>
  </dl>
 <div class="c"></div>
</li>
 <hr>
<li>
  <h2>Item Another One Here</h2>
   <dl>
    <div class="f">attr1 value a</div>
<!--   <div class="c"></div> -->
    <div class="f">attr2 value b</div>
    <div class="f">attr3 value c</div>
    <div class="c"></div>
  </dl>
</li>
 <hr>
</ul>
Albin Paul
  • 3,330
  • 2
  • 14
  • 30