CuriousG
CuriousG

Reputation: 97

DL element with DT / DD as equal column widths on one row

So for specific reasons I'm trying to use the dl (Description List) html element. I wanted the elements contents to display each dt and dd on their own row which I accomplished as such..

div {
  padding: 1rem;
  color: #fff;
  background-color: rgba(0,0,0,.8);
}
  
dl dt, dl dd {
  display: inline;
  line-height: 1.75rem;
}
<div>
  <h3>Cryptids of Cornwall:</h3>
  <dl>
      <dt>Beast of Bodmin</dt>
      <dd>A large feline inhabiting Bodmin Moor.<br></dd>

      <dt>Morgawr</dt>
      <dd>A sea serpent.<br></dd>

      <dt>Owlman</dt>
      <dd>A giant owl-like creature.<br></dd>
  </dl>
</div>

Which is really close to what I'm after, but I'm wondering if anyone knows a way with maybe Flex or Grid for a more uniformed layout like a table while still using the dl the element so the output is more like this...

table {
  border-collapse: collapse;
  color: #fff;
  background-color: rgba(0,0,0,.8);
}

table th {
  text-align: left;
  padding-left: 1rem;
}

table td {
  padding: 1rem;
}

table tr td:first-of-type {
  text-align: right;
  border-right: lightgray 1px solid;
}
<table>
  <tr>
    <th colspan="2">
      <h3>Cryptids of Cornwall:</h3>
    </th>
  </tr>
  <tr>
      <td>Beast of Bodmin</td>
      <td>A large feline inhabiting Bodmin Moor.</td>
  </tr>
  <tr>
      <td>Morgawr</td>
      <td>A sea serpent.</td>
  </tr>
  <tr>
      <td>Owlman</td>
      <td>A giant owl-like creature.</td>
  </tr>
</table>

Is there a way to accomplish this with css and explicitly using the dl element? I've tried things display: table on the parent dl with the dt and dd as display: table-cell but then I can't seem to break the into new rows after the dd along with failed attempts at using flex and css grid so wondering if someone knows a trick to teach? Thanks!

Upvotes: 2

Views: 1889

Answers (2)

zer00ne
zer00ne

Reputation: 43975

I've tried things display: table on the parent dl with the dt and dd as display: table-cell but then I can't seem to break the into new rows after the dd along with failed attempts at using flex and css grid so wondering if someone knows a trick to teach?

Table cells need table rows, and table rows need a table (technically a tbody, thead, or tfoot). Originally I thought that the <dl>, <dt>, and <dd> were not fit to configure into a table/grid layout since <dl> was the only parent element, not even <dt> was allowed to have <dt> and <dd> as children. Then I found out that <div> is valid if a direct descendant of a <dl> which is the perfect position to be a table row.

If you want table behavior, assign display table type values:

Element Property Value Hierarchy
<dl> display table
<dt> display table-caption dl > dt
<div> display table-row dl > div
<dt> diaplay table-cell dl > div > dt
<dd> display table-cell dl > div > dd

A <div> can be a direct descendant (ie child) of a <dl> and a parent of <dt> and <dd>

Using <table> and table component elements for layout has been discouraged for years, but not display: table and associated values.

html {
  font: 2ch/1.75 'Garamond'
}

main {
  padding: 1rem;
  color: #fff;
  background-color: rgba(0, 0, 0, .8);
}

dl {
  display: table;
  table-layout: fixed;
  border-collapse: collapse;
  width: 80%;
}

dl>dt {
  display: table-caption;
  width: 100%;
  margin-bottom: 5px;
  padding: 0;
  border: 0;
  font-size: 1.17rem;
  font-weight: 900;
}

dl>div {
  display: table-row;
}

dl>div:first-of-type>dt {
  width: 50%;
}

dl>div:first-of-type>dd {
  width: 50%;
}

div>dt,
div>dd {
  display: table-cell;
}

div>dt {
  padding-right: 10px;
  border-right: 2px solid #fff;
  text-align: right;
}

div>dd {
  padding-left: 10px;
  border-left: 2px solid #fff;
}
<main>
  <dl>
    <dt>Cryptids of Cornwall:</dt>
    <div>
      <dt>Beast of Bodmin</dt>
      <dd>A large feline inhabiting Bodmin Moor.</dd>
    </div>
    <div>
      <dt>Morgawr</dt>
      <dd>A sea serpent.</dd>
    </div>
    <div>
      <dt>Owlman</dt>
      <dd>A giant owl-like creature.</dd>
    </div>
  </dl>
</main>

Upvotes: 1

Dai
Dai

Reputation: 155390

Here's a quick-and-dirty display: grid; implementation:

  • The vertical tracks ("columns") are 1fr 1fr, so they're both 50% wide. I'm unsure of the best approach to make the tracks sized-to-content.
    • I ultimately got this working by simply doing grid-template-columns: auto auto;, phew!
  • There's no white border between the vertical tracks.
    • I did try to hack it by using dl::before (making it 1px wide with a border: 1px solid white but it seems like it's currently impossible to make a grid item span all horizontal tracks when there are implicit tracks.
    • UPDATE: After being inspired by this post, I was able to hack a vertical line by using an absolutely-positioned ::after element (in the <dt> so it has the correct horizontal position without an explicit left or right value).
  • To my surprise, it does actually work very well when a <dt> element has multiple <dd> siblings (I've added one for the Mermaid of Zennor as an example). I was originally apprehensive that multiple <dd> elements would break the layout.
  • BTW, you don't need the <br /> breaks in your HTML. I've removed them in my example below.

div {
  padding: 1rem;
  color: #fff;
  background-color: #333;
}
  
dl, dt, dd {
  margin: 0;
  padding: 0;
}
  
dl {
  color: #eee;
  background-color: #666;
  border-radius: 5px;
  padding: 1rem;
  
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-columns: auto auto;
  grid-template-columns: auto 5px auto;
  grid-template-rows: auto [last-line];
  grid-auto-rows: min-content;
  
  grid-gap: 1rem;
  
  /* This is to allow the `dl > dt:first-child::after` to fill the height */
  position: relative;
}

/* Using this to make a vertical line won't work, see https://stackoverflow.com/questions/44052336/make-a-grid-item-span-to-the-last-row-column-in-implicit-grid
dl::before {
  content: '';
  display: block;
  grid-column-start: 2;
  grid-column-end: 3;
  grid-row-start: 1;
  grid-row-end: -1;
  grid-row-end: last-line;
  
  background-color: red;
  border-left: 1px solid white;
  width: 1px;
}
*/

dl > dt:first-child::after {
  content: '';
  display: inline;
  border-left: 1px solid white;
  width: 1px;
  
  position: absolute;
  top: 0;
  bottom: 0;
  /* Offset it to the right a bit using margin: */
  margin-left: 1rem;
}

dl > dt {
  grid-column-start: 1;
  grid-column-end: 2;

  /*
  `align-self` is for vertical alignment in a grid cell.
  `justify-self` is for horizontal alignment in a grid cell.
  */

  align-self: center; 
  justify-self: end; /* i.e. right-align */
  text-align: right; /* This is needed so narrow-viewports don't break. */
}
dl > dd {
  grid-column-start: 2;
  grid-column-end: 3;
  
  grid-column-start: 3;
  grid-column-end: 4;

  align-self: center; 
  justify-self: start; /* i.e. left-align */
}
<div>
  <h3>Cryptids of Cornwall:</h3>
  <dl>
      
      <dt>Beast of Bodmin</dt>
      <dd>A large feline inhabiting Bodmin Moor.</dd>

      <dt>Morgawr</dt>
      <dd>A sea serpent.</dd>

      <dt>Mermaid of Zennor</dt>
      <dd>A popular Cornish folk tale</dd>
      <dd>The parishioners at St. Senara's commemorated the story by having one end of a bench carved in the shape of a mermaid</dd>

      <dt>Owlman</dt>
      <dd>A giant owl-like creature.</dd>

      
  </dl>
</div>


Screenshot proof:

It looks good at a variety of viewport sizes:

Very narrow:

enter image description here

Normal

enter image description here

Very wide

enter image description here

Upvotes: 2

Related Questions