8

I have the following html code:

<dl>
  <dt>term1</dt><dd>defn1</dd>
  <dt>term2</dt><dd>defn2</dd>
  <dt>term3</dt><dd>defn3</dd>
</dl>

I'm trying to have them floated in pairs (same width), with all the dts going on the first line and all the dds on the second one.

Like this:

term1 term2 term3
defn1 defn2 defn3

I have tried all sorts of combinations of display: block (+floats/clears), inline-block, table-*, flex, but none came any close.

Any idea how it could be done?

Salman A
  • 262,204
  • 82
  • 430
  • 521
lucian
  • 623
  • 10
  • 21

4 Answers4

5

Here's one using flex box with no changes to your list, just CSS. Basically just defining the order of the children of dl using the nth-child pseudo selector. The calc() method used here is unfortunately dependent upon knowing the number of children in your list (in my example: 4).

With just CSS you can't really determine the number of children, but you can count siblings and prepare your CSS for different situations if you know the maximum number of items in your list:

Can CSS detect the number of children an element has?

dl {
  display: flex;
  flex-flow: row wrap;
}

dt,dd {
  margin: 0;
  flex-grow: 1;
  }

dt {
  order: 0;
  flex-basis: calc(100%/4);
}

dd {
  order: 1;
  flex-basis: calc(100%/4);
}
<dl>
  <dt>term1</dt><dd>defn1</dd>
  <dt>term2</dt><dd>defn2</dd>
  <dt>term3</dt><dd>defn3</dd>
  <dt>term4</dt><dd>defn4</dd>
</dl>
Community
  • 1
  • 1
Robert Wade
  • 4,918
  • 1
  • 16
  • 35
  • Great, thanks - I had gotten one step away from this but missed because of a detail and would have never thought about going back. – lucian Sep 07 '16 at 11:55
3

I achieved what you want with flex, but only by adding the wrapper that controls the overall width.

Only change to your html markup is the div wrapper.

div {
  width: 50%;
}
dl {

 -ms-flex-direction: row;
    -moz-flex-direction: row;
    -webkit-flex-direction: row;
    flex-direction: row;
 
    -ms-flex-wrap: wrap;
    -moz-flex-wrap: wrap;
    -webkit-flex-wrap: wrap;
    flex-wrap: wrap;
 
  display: -webkit-box;      /* OLD - iOS 6-, Safari 3.1-6 */
  display: -moz-box;         /* OLD - Firefox 19- (buggy but mostly works) */
  display: -ms-flexbox;      /* TWEENER - IE 10 */
  display: -webkit-flex;     /* NEW - Chrome */
  display: flex;             /* NEW, Spec - Opera 12.1, Firefox 20+ */
}

dt {
min-width: 30%;

  -webkit-box-flex: 0 0 30%;      /* OLD - iOS 6-, Safari 3.1-6 */
  -moz-box-flex: 0 0 30%;         /* OLD - Firefox 19- */
  -moz-flex: 0 0 30%;  
               /* For old syntax, otherwise collapses. */
  -webkit-flex: 0 0 30%;          /* Chrome */
  -ms-flex: 0 0 30%;              /* IE 10 */
  flex: 0 0 30%;                  /* NEW, Spec - Opera 12.1, Firefox 20+ */
  
  -webkit-box-ordinal-group: 1;  
  -moz-box-ordinal-group: 1;     
  -ms-flex-order: 1;     
  -webkit-order: 1;  
  order: 1;

}

dd {
min-width: 30%;

  -webkit-box-flex: 0 0 30%;      /* OLD - iOS 6-, Safari 3.1-6 */
  -moz-box-flex: 0 0 30%;         /* OLD - Firefox 19- */
    -moz-flex: 0 0 30%;
                 /* For old syntax, otherwise collapses. */
  -webkit-flex: 0 0 30%;          /* Chrome */
  -ms-flex: 0 0 30%;              /* IE 10 */
  flex: 0 0 30%;                  /* NEW, Spec - Opera 12.1, Firefox 20+ */
   
  -webkit-box-ordinal-group: 2;  
  -moz-box-ordinal-group: 2;     
  -ms-flex-order: 2;     
  -webkit-order: 2;  
  order: 2;
   
  margin-left: 0;
}
<div>
  <dl>
    <dt>term1</dt>
    <dd>defn1</dd>
    <dt>term2</dt>
    <dd>defn2</dd>
    <dt>term3</dt>
    <dd>defn3</dd>
  </dl>
</div>
Vcasso
  • 1,328
  • 1
  • 8
  • 14
  • It works in Chrome, Firefox and IE. I will play around a little more to get it to work in Safari. – Vcasso Sep 07 '16 at 13:57
  • This is working in Safari too now. (Still requires knowing the column count, but watchagonnado) – henry Sep 07 '16 at 20:29
1

There is a proper and scalable solution which, unfortunately, does not work in most browsers yet. it requires proper support for CSS3 break properties.

I am still posting this as an answer; currently works in FF.

dl {
  display: flex;
  flex-direction: column;
  flex-wrap: wrap;
}
dd + dt {
  page-break-before: always;
}
dd {
  margin: 0;
}
<dl>
  <dt>Term 1</dt>
  <dd>Defn 1</dd>
  <dt>Term 2</dt>
  <dd>Defn 2</dd>
  <dt>Term 3</dt>
  <dd>Defn 3</dd>
</dl>

<dl>
  <dt>Term 1</dt>
  <dd>Defn 1</dd>
  <dt>Term 2</dt>
  <dd>Defn 2</dd>
  <dt>Term 3</dt>
  <dd>Defn 3</dd>
  <dt>Term 4</dt>
  <dd>Defn 4</dd>
</dl>

<dl>
  <dt>Term 1</dt>
  <dd>Defn 1-1</dd>
  <dd>Defn 1-2</dd>
  <dd>Defn 1-3</dd>
  <dt>Term 2</dt>
  <dd>Defn 2</dd>
  <dt>Term 3-1</dt>
  <dt>Term 3-2</dt>
  <dt>Term 3-3</dt>
  <dd>Defn 3</dd>
  <dt>Term 4</dt>
  <dd>Defn 4</dd>
  <dt>Term 5</dt>
  <dd>Defn 5</dd>
</dl>

Assuming the browser does the right thing, the result will look like this:

enter image description here

Salman A
  • 262,204
  • 82
  • 430
  • 521
0

In the future, you may be able to use the proposed css property break-after to start a new column after every dd. That isn't supported by any browser yet, so you'll have to do something like this

dl div {
  display: inline-block
}
div dd {
  margin: 0
}
<dl>
  <div>
    <dt>term1</dt>
    <dd>defn1</dd>
  </div>
  <div>
    <dt>term2</dt>
    <dd>defn2</dd>
  </div>
  <div>
    <dt>term3</dt>
    <dd>defn3</dd>
  </div>
</dl>

Using the selectors div and dd would work here too, but I'm using dl div and div dd to make sure we don't mess up any dls that don't have the column layout.

Note: though this will render fine (in all browsers, I believe), it is strictly speaking invalid HTML. If you can get away from using a dl, I personally would do something like

<div class="terms">
    <div class="term">
        <p>term1</p>
        <dfn>def1</dfn>
    </div>
    <div class="term">
        <p>term2</p>
        <dfn>def2</dfn>
    </div>
</div>
henry
  • 4,244
  • 2
  • 26
  • 37
  • 2
    Except that this is invalid HTML – j08691 Sep 06 '16 at 20:50
  • Yep. It'll render okay though. I'm assuming the OP has a reason for using a `dl`. Will update my answer to reflect this – henry Sep 06 '16 at 21:05
  • 1
    @DrewKennedy that is both inappropriate and absurd – henry Sep 06 '16 at 21:15
  • @DrewKennedy 1) that analogy really does not work at all: no warning is being disabled. 2) I didn't say anything about standards being a bad idea. 3) Attacking someone's employability is not the way to bring this up. 4) I can tell you that this particular type of rule is broken all the time (e.g. google.com has four instances of unallowed child-parent pairs). 5) Saying it works doesn't mean I'm advocating for it. If you don't like that it works, take it up with the browser dev teams. 6) I added a note about the validity issue before you first commented. ¶ This isn't constructive, I'm out – henry Sep 06 '16 at 22:43
  • This is now valid HTML. See https://html.spec.whatwg.org/multipage/semantics.html#the-dl-element – zcorpan Nov 13 '16 at 22:59