Search code examples
htmlcssflexbox

Layout a flex box similar to a table?


I'm working with a framework developed in-house which depends on a certain structure to our HTML. And one of the tricky things is that each row needs its own container with its own classes and data attributes.

So here's the problem. Without drastically changing the DOM, how can I make the flex box below render essentially like an HTML table would? Or is a table the only way? The solution will have to work in both IE11 and Chrome.

I'm trying to make it look like this...

Column A      |      Column B      |      Column C
1             |      2             |      3

section {
  display: flex;
  flex-wrap: wrap;
}

section .col {
  flex: 1 1 auto;
}

section .line-break {
  flex-basis: 100%;
  width: 0px; 
  height: 0px; 
  overflow: hidden;
}
<html>
  <head>
  </head>
  <body>
    <section>
      <header>
        <div class="col">Column A</div>
        <div class="col">Column B</div>
        <div class="col">Column C</div>
      </header>
      <div class="line-break"></div>
      <div class="row">
        <div class="col">1</div>
        <div class="col">2</div>
        <div class="col">3</div>
      </div>
    </section>
  </body>
</html>


Solution

  • If the content you are going to present is of type tabular data, then a table is the proper way.

    HTML 5.1 W3C Recommendation, 1 November 2016, 4.9 Tabular data

    Given that you can't, or don't want to, alter the markup, this can be done using CSS Table, and with that easily swap between any display type such as flex, block, etc., or even float, using media query etc.

    I also removed the <div class="line-break"></div> element, since you don't need, though if it is rendered by a component or similar, leaving it as is won't cause any problem.

    Using CSS Table

    section {
      display: table;
      width: 100%;
    }
    
    section > * {
      display: table-row;
    }
    
    section .col {
      display: table-cell;
    }
    <html>
      <head>
      </head>
      <body>
        <section>
          <header>
            <div class="col">Column A</div>
            <div class="col">Column B</div>
            <div class="col">Column C</div>
          </header>
          <div class="row">
            <div class="col">1</div>
            <div class="col">2</div>
            <div class="col">3</div>
          </div>
        </section>
      </body>
    </html>


    If you still need, or have to, use Flexbox, this answer of mine mention the difference between CSS Table and Flexbox on two important features:


    Updated, a sample showing some useful Flexbox stuff, with varying width's and span columns.

    Using Flexbox

    .tbl {
      display: flex;
      flex-direction: column;
    }
    .row {
      display: flex;
      min-height: 50px;
    }
    .cell {
      flex: 4;
      border: 1px solid red;
    }
    .cell:nth-child(1) {
      flex: 1;
    }
    .cell:nth-child(2) {
      flex: 2;
    }
    .cell.span4-5 {
      flex: 8 24px;                    /*  col 4,5 flex-grow/border/padding  */
    }
    .cell.span3-4 {
      flex: 8 24px;                    /*  col 3,4 flex-grow/border/padding  */
    }
    .cell.span3-5 {
      flex: 12 36px;                   /*  col 3,4,5 flex-grow/border/padding  */
    }
    .row:first-child .cell {
      display: flex;
      justify-content: center;         /*  center horiz. */
      align-items: center;             /*  center vert. */
    }
    .row .cell {
      padding: 5px;
      box-sizing: border-box;
    }
    <div class="tbl">
      <div class="row">
        <div class="cell">ID </div>
        <div class="cell">Nr </div>
        <div class="cell">Header 1 </div>
        <div class="cell span4-5"> Header 2 </div>
      </div>
      <div class="row">
        <div class="cell">1</div>
        <div class="cell">2</div>
        <div class="cell">Content</div>
        <div class="cell">Content</div>
        <div class="cell">Content</div>
      </div>
      <div class="row">
        <div class="cell">2</div>
        <div class="cell">3</div>
        <div class="cell span3-5">Content</div>
      </div>
      <div class="row">
        <div class="cell">1</div>
        <div class="cell">2</div>
        <div class="cell span3-4">Content</div>
        <div class="cell">Content</div>
      </div>
    </div>