55

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>
Steve Wortham
  • 21,740
  • 5
  • 68
  • 90
  • 4
    Sometimes the best element to display the data would be a table. – happymacarts Feb 01 '18 at 19:18
  • 1
    If it's tabular data then use it, if you can't change the markup and need a table, there is also an option of using [css table](https://jsfiddle.net/vqd7tqoz/). – Stickers Feb 01 '18 at 23:47

4 Answers4

51

header, .row {
  display: flex;  /* aligns all child elements (flex items) in a row */
}

.col {
  flex: 1;        /* distributes space on the line equally among items */
}
<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>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 17
    This does not work, because the text in the first row is longer than the second row. The text will not left align in each row like the requester has demonstrated above. – user2847376 Jun 13 '19 at 20:41
  • 4
    It looks fine in my Chrome browser. – hrabinowitz Sep 05 '19 at 20:37
  • 4
    What the comment above is referring to is that when the contents of a cell in a row is larger than it's equal share of space then it pushes the next column along and out of alignment with other rows. That's when a table would work better. – user2219808 May 19 '20 at 12:49
  • 1
    [Here's an example](https://jsfiddle.net/q025soap/) of columns getting pushed right. You could add `overflow-wrap: anywhere;` on `.col` to fix this specific example – bendytree Oct 13 '22 at 16:15
  • I like this answer, unfortunately, when rows have less items than others, they're not aligned anymore – jokoon Apr 08 '23 at 18:32
  • In that case, use CSS Grid. @jokoon – Michael Benjamin Apr 08 '23 at 19:05
45

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>
Asons
  • 84,923
  • 12
  • 110
  • 165
  • 1
    Css Table is only proper if your data is fixed in size, and the table has definite width and height. If the table is auto width and auto height and data also vary in length. the table will look ugly and broken. – angry kiwi Sep 28 '21 at 05:24
  • @angrykiwi -- The choice of element type has more to do with what the data represent rather than its size. Using CSS Table or `` will give pretty much the same output, hence my suggestion relates to the type of data the user expect to show. Yes, a table can look ugly, though the question and answers here doesn't try to answer that, as that is not what is asked for.
    – Asons Sep 28 '21 at 09:18
  • @angrykiwi -- May I suggest that you post an answer that both solves what's asked for, and at the same time show how one could make such _table_ look good. That would be a good contribution. – Asons Sep 28 '21 at 09:22
  • that's my answer. Table is not always for tabular data. Table is for controlled tabular data. If this helps the OP understands and considerate your answer and other answers and conclude what to do to solve his problem. – angry kiwi Sep 28 '21 at 15:01
  • @angrykiwi -- So if you think that, and to provide help for future users, why not post that as an answer, instead of telling me. Do note, I don't disagree and never said "`table` is __always__ for tabular data". Also, a comment can be deleted at any time, so a proper answer is the best if you want it to persist. ... Or do you mean my answer is wrong, and if, how does it __not__ answer what OP asked? – Asons Sep 28 '21 at 19:38
  • you said `If the content you are going to present is of type tabular data, then CSS Table is the proper way`. it's obviously to me means, if tabular data, use table. – angry kiwi Sep 28 '21 at 21:25
  • again, if the tabular data vary in size and length, table will look real ugly, an no matter what css you try, you can't never fix that table. – angry kiwi Sep 28 '21 at 21:30
  • @angrykiwi -- You might want to read [HTML 5.1 W3C Recommendation, 4.9 Tabular data](https://www.w3.org/TR/2016/REC-html51-20161101/tabular-data.html). There you will see that it is not me who says `table` is for tabular data, it is a W3C Recommendation. It has to do with much more than "it can look ugly". Screen readers etc. are dependent on the element type used, to proper present data for e.g. a blind person, so as you can read there, it has little to do with how it looks. And if tabular data looks ugly because of its size, it looks ugly, and no other element type, or CSS, will fix that. – Asons Sep 29 '21 at 09:57
  • that recommendation is pointing out that we should use html table for tabular data. Here we have this topic question about making tabular data look nice by applying CSS. And using HTML table can not assure your tabular data look nice. This confusion happens to many. You can use grid css to make the html table to look nice, but that will me the html table no longer an html table. – angry kiwi Sep 30 '21 at 06:28
  • @angrykiwi -- First off, the topic is __not__ _making tabular data look nice by applying CSS_, OP is asking _"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?"_ -- Second, as I wrote before, and as you now finally reveal that you think CSS Grid will solve the problem, post such answer instead of keep commenting why my answer is not good enough, as that is not constructive. – Asons Sep 30 '21 at 13:03
  • It's obvious the OP know there is HTML table. He opted for flex instead because there is something with table he didn't like in the first place . Then he found out flex also not look right. He then is searching for solution that make his tabular data look nice and right. And you pointing him back at the HTML table, and the html table has the drawback, I see your answer missing to address that. that's why there is need to comment to clarify the answer a bit more. And I did not mean you is wrong. What I meant is your lacking information. And that information is important to the question – angry kiwi Sep 30 '21 at 14:45
7

This code works for me:

        * {
            box-sizing: border-box;
        }


        body, html {
            height: 100%;
            margin: 0;
        }


        #container {
            width: 400px;
            display: flex;
            flex-direction: column;
            justify-content: flex-start;
            align-items: flex-start;
            background-color: lightgrey;
            padding: 10px;

        }


        .shelf {

            flex: 1 1 auto;
            width: 100%;
            margin-bottom: 10px;
            border: 1px solid black;
            background-color: lightgreen;

            display: flex;
            flex-direction: row;

        }
        .shelf:last-child {
            margin-bottom: 0;
        }


        .labelbox {
            flex: 0 0 35%;
        }


        .valuebox {
            flex: 0 0 65%;
        }
<div id="container">

    <div class="shelf">
        <div class="labelbox">Name: </div> <div class="valuebox">Barry Carter</div>
    </div>

    <div class="shelf">
        <div class="labelbox">DOB:</div><div class="valuebox">10/12/1980</div>
    </div>

    <div class="shelf">

        <div class="labelbox">
            Description:
        </div>

        <div class="valuebox">

            This content goes on and on and will force the height to expand. And the label box to the left will
            "move" with it. There need not be much of a relation other than that their parent div/flex-container is
            getting taller as well.

        </div>

    </div>

    <div class="shelf">
        <div class="labelbox">Group:</div><div class="valuebox">Advanced</div>
    </div>

    <div class="shelf">
        <div class="labelbox">End Date:</div><div class="valuebox">2020-09-20</div>
    </div>

</div>
WebDev-SysAdmin
  • 269
  • 4
  • 12
1

Use CSS Grid. You can style any table the way you like.

Keep in mind If your table is more than 700 rows, the fram rate will start to drop, no matter what js framework you use. react, angular, vue or vanila JS. the scrolling will get real laggy.

And the maximum you row can use is 1000. More than that the extra row will create bad graphic. But you wont reach 1000 anyway, because at 700th row, the scrolling speed, starts to get bad.

If somehow you need to display more than 1000 rows, you will visualized lib. Every js framework has a lib to do so. Basically, it will render the rows in the view port. The rows that not in the view port will not be rendered. They will only be rendered when user scrolls.

This is year 2021, chances you read this answer in the future, the browsers vendor might probably fix the performance of 1000 rows, they might even extend that limit. So try it out.

angry kiwi
  • 10,730
  • 26
  • 115
  • 161