9

I'm trying to create a table using CSS grid, with equal columns based on the content. I want to avoid using <table>. This is a follow-up to this question: Auto-adjusting columns with CSS grid

What I'm trying to achieve:

enter image description here

This table works: https://codepen.io/anon/pen/baExYw

But I want to wrap the each row in a div, which unsurprisingly breaks the table.

This table is broken: https://codepen.io/anon/pen/qpbMgG

app.html

<div class="wrapper">
  <div class="box a">col 1</div>
  <div class="box b">col 2</div>
  <div class="box c">col 3</div>

  <!-- Table Row -->
  <div class="row">
    <div class="box d">short data</div>
    <div class="box e">a really long piece of data</div>
    <div class="box f">short data</div>
  </div>

  <!-- Table Row -->
  <div class="row">
    <div class="box d">short data</div>
    <div class="box e">a really long piece of data</div>
    <div class="box f">short data</div>
  </div>
</div>

app.css

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, auto);
  background-color: #fff;
  color: #444;
  max-width:  800px;
}

.box {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
}

I'm still very new to CSS Grid, so I'm still having trouble understanding how half of this stuff works behind the scenes.

Any help is appreciated. Thanks in advance.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
realph
  • 4,481
  • 13
  • 49
  • 104
  • 5
    You really want to avoid using a semantic `table` for tabular data, and instead using CSS grid? I think that whatever answer someone posts, you will have some caveat for why it's not acceptable. Save yourself the pain and use a `table`. – dom_ahdigital Dec 18 '17 at 17:46
  • 1
    @dom_ahdigital I'm trying to create a custom table because browsers only allow very specific elements inside tables (tt, td, thead etc). Hence the reason I'm avoiding `table` like the plague. – realph Dec 18 '17 at 17:48
  • @realph so you want a div table so you can make it _"pretty?"_ – hungerstar Dec 18 '17 at 17:50
  • @hungerstar Kind of. I'm trying to create a generic web component, and it won't play nicely with `table`. – realph Dec 18 '17 at 17:51
  • @dom_ahdigital Nope, because now the columns aren't the same width. – realph Dec 18 '17 at 17:52
  • @realph with the little info I've got, I'd say to use flexbox. If you provided an example of the exact styles/layout you'll be attempting, you might get better answers. – hungerstar Dec 18 '17 at 17:53

4 Answers4

17

display: contents is what you need.

contents

These elements don't produce a specific box by themselves. They are replaced by their pseudo-box and their child boxes.

Add this CSS (example):

.row {
    display: contents;
}

More links:

Spooky
  • 2,966
  • 8
  • 27
  • 41
Matveev Dmitriy
  • 451
  • 5
  • 9
  • Ideal explanation is here: https://rachelandrew.co.uk/archives/2016/01/29/vanishing-boxes-with-display-contents/ – Andrew Aug 19 '19 at 15:26
  • 1
    So you're saying to say this `display` value on the row elements? And that will allow the "cell" elements to work as children of the grid? It would help to be more explicit in your answer. – JohnK Jun 02 '20 at 14:38
  • .row just replaced by it's childrens. It's like you comment .row at base sample ... – Matveev Dmitriy Jun 03 '20 at 15:21
7

In your first example, your data cells are children of the container. Hence, grid properties – which only work between parent and child – work as you expect.

In your second example, you have some data cells that are children of .row containers. These cells are no longer children of .wrapper, the grid container. Therefore, these cells are outside the scope of grid layout, do not recognize grid properties and are rendered as standard block-level elements.

So, basically, grid containers with different child elements render different layouts.

One solution to get your examples to match would be to make the grid items into grid containers having the same properties as the parent. Here's the general idea:

Revised Codepen

.wrapper {
  display: grid;
  grid-template-columns: repeat(3, minmax(50px, 1fr));
  background-color: #fff;
  color: #444;
  max-width: 800px;
}

.row {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(50px, 1fr));
}

div:nth-child(4) { grid-row-start: 2; }
div:nth-child(5) { grid-row-start: 3; }

.box {
  background-color: #444;
  color: #fff;
  border-radius: 5px;
  padding: 20px;
  font-size: 150%;
}
<div class="wrapper">
  <div class="box a">col 1</div>
  <div class="box b">col 2</div>
  <div class="box c">col 3</div>

  <!-- Table Row -->
  <div class="row">
    <div class="box d">short data</div>
    <div class="box e">a really long piece of data</div>
    <div class="box f">short data</div>
  </div>

  <!-- Table Row -->
  <div class="row">
    <div class="box d">short data</div>
    <div class="box e">a really long piece of data</div>
    <div class="box f">short data</div>
  </div>
</div>
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Thanks for the explanation. But then is it possible for the width of col 2 to grow with its content? – realph Dec 18 '17 at 21:20
  • 1
    Yes, but then the columns in rows 2 and 3 are no longer forced to align with the columns in row 1. – Michael Benjamin Dec 18 '17 at 21:52
  • The columns align because they are *all* set to consume equal space in the container, and all containers are the same width. Once you remove that `1fr` association, they have no reason to align. Check it out: https://codepen.io/anon/pen/YYwgmR – Michael Benjamin Dec 18 '17 at 21:54
  • 1
    Oh no. :( I knew this might be harder than I initially thought. – realph Dec 19 '17 at 01:06
1

It didn't break, it works exactly as intended. Every child element is using one cell of the grid, if you wrap your header in another div you'll see they swap rows for columns, because each group will use one cell.

If you are going to display tabular data, then you should stick with tables as they are the semantically correct element for that purpose.

However if you are trying to build responsive designs or you really want to use grid I suggest you to read this incredible article about CSS grids.

Take a look in display: subgrid; maybe it is what you are looking for in this scenario.

0

Actually we should use auto-fit property of css-grid to create table-like layout with css grid

Note: here because of auto-fit we do not need to specify the number of columns

@mixin table-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    align-items: center;
}
.tr{
    @include table-row();
}
.thead{
    @include table-row();
}
<HTML>
<div>
<div class="thead"></div>
<div class="tr"></div>
</div>
</html>
Akshay Vijay Jain
  • 13,461
  • 8
  • 60
  • 73