3

I have a grid with eight (or less) cards. I would like the cards to be automatically placed in the grid and not aware of their width and height. That is, widths and heights should be specified in grid styles. It works great when I have all 8 cards displayed. Example:

grid-template-areas:
    'card-1 card-1 card-2'
    'card-3 card-4 card-5'
    'card-3 card-6 card-5'
    'card-7 card-8 card-8';
grid-template-rows: 20px 20px 20px 20px;
grid-template-columns: 20px 20px 20px;

body {
  background: white;  
}

.grid {
  display: grid;
  grid-template-areas:
     'card-1 card-1 card-2'
     'card-3 card-4 card-5'
     'card-3 card-6 card-5'
     'card-7 card-8 card-8';
  grid-template-rows: 20px 20px 20px 20px;
  grid-template-columns: 20px 20px 20px;
  grid-gap: 5px;
  background: black;
}

.card-1 {
  grid-area: card-1;
  background: red;
}

.card-2 {
  grid-area: card-2;
  background: orange;
}

.card-3 {
  grid-area: card-3;
  background: yellow;
}

.card-4 {
  grid-area: card-4;
  background: green;
}

.card-5 {
  grid-area: card-5;
  background: cyan;
}

.card-6 {
  grid-area: card-6;
  background: blue;
}

.card-7 {
  grid-area: card-7;
  background: indigo;
}

.card-8 {
  grid-area: card-8;
  background: gray;
}
<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
  <div class="card-5"></div>
  <div class="card-6"></div>
  <div class="card-7"></div>
  <div class="card-8"></div>
</div>

However, the problem arises when the cards are less than 8. The last row of the grid is not occupied by the cards, but it still has the height:

body {
  background: white;  
}

.grid {
  display: grid;
  grid-template-areas:
     'card-1 card-1 card-2'
     'card-3 card-4 card-5'
     'card-3 card-6 card-5'
     'card-7 card-8 card-8';
  grid-template-rows: 20px 20px 20px 20px;
  grid-template-columns: 20px 20px 20px;
  grid-gap: 5px;
  background: black;
}

.card-1 {
  grid-area: card-1;
  background: red;
}

.card-2 {
  grid-area: card-2;
  background: orange;
}

.card-3 {
  grid-area: card-3;
  background: yellow;
}

.card-4 {
  grid-area: card-4;
  background: green;
}

.card-5 {
  grid-area: card-5;
  background: cyan;
}

.card-6 {
  grid-area: card-6;
  background: blue;
}

.card-7 {
  grid-area: card-7;
  background: indigo;
}

.card-8 {
  grid-area: card-8;
  background: gray;
}
<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
</div>

I can solve this problem by removing grid-template-areas, replacing grid-template-rows with grid-auto-rows, and replacing grid-area with grid-row + grid-column:

body {
  background: white;  
}

.grid {
  display: grid;
  grid-auto-rows: 20px;
  grid-template-columns: 20px 20px 20px;
  grid-gap: 5px;
  background: black;
}

.card-1 {
  grid-row: 1;
  grid-column: 1 / 3;
  background: red;
}

.card-2 {
  grid-row: 1;
  grid-column: 3;
  background: orange;
}

.card-3 {
  grid-row: 2 / 4;
  grid-column: 1;
  background: yellow;
}

.card-4 {
  grid-row: 2;
  grid-column: 2;
  background: green;
}

.card-5 {
  grid-row: 2 / 4;
  grid-column: 3;
  background: cyan;
}

.card-6 {
  grid-row: 3;
  grid-column: 2;
  background: blue;
}

.card-7 {
  grid-row: 4;
  grid-column: 1;
  background: indigo;
}

.card-8 {
  grid-row: 4;
  grid-column: 2 / 4;
  background: gray;
}
<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
</div>

But this method is not very convenient. Help, please, is it possible to do what I want using grid-template-areas and specifying the widths and heights in grid styles? (It is also unacceptable to specify the widths and heights for children of the grid using cascade)

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
psixdev
  • 131
  • 1
  • 8
  • why the last one is not very convenient? – Temani Afif Mar 30 '19 at 19:11
  • @TemaniAfif I would like to have several different grids with 8 cards. It is inconvenient and tedious to calculate grid-row and grid-column properties for each card of each grid. – psixdev Mar 30 '19 at 19:15
  • Can you show an example of what you mean by "different grids with 8 cards"? it's too generic and maybe they are different but with a lot of similarities. What do the layout of each different grid depend on? are all crafted by hand? Can the empty row be one on the middle? or do empty rows are always the bottom ones? – arieljuod Mar 30 '19 at 22:31
  • @arieljuod Here is an example with different grids: https://codepen.io/anon/pen/yrLJMB. As you can see, adding new grids is very simple; I only change one property of grid-template-areas. Adding new grids by changing the properties of all child cards is not so convenient. An empty row cannot be in the middle, since the cards will always be located from left to right and from top to bottom. – psixdev Mar 31 '19 at 08:10
  • The set of grid patterns is pre-selected manually, but the current grid will be selected programmatically. – psixdev Mar 31 '19 at 08:16
  • Hmmm sounds like you are calculating the "dense" placement algorithm by hand. I understand you don't want to set the cards columns/rows but its the only solution for your problem I don't see it that inconvenient (you are calculating the positions by hand, personally I think that's more inconvenient). If you define template areas you are making them explicit and you can't have implicit behaviour. I think @TemaniAfif's solution is the best, I don't think you can achieve what you want with only CSS. – arieljuod Mar 31 '19 at 13:57
  • Yes, I deliberately do not use "dense", because I do not want the cards to know about their size, and also I want to specify a limited set of grid patterns. It seems that the improvement proposed by @TemaniAfif is the only one. In principle, for me this is not a very big problem, since I use styled-components and with the help of js I can laconic generate all styles directly in the class .grid (using inheritance). I just hoped to find a solution with using pure css, without js mixins. – psixdev Mar 31 '19 at 14:05

1 Answers1

3

You can keep the use of grid-colum/grid-row but simplify your code like below in case you will always have the good order in the HTML code:

.grid {
  display: grid;
  grid-auto-rows: 20px;
  grid-auto-flow: dense; /*to make sure we fill all the space (not mandatory)*/
  grid-template-columns: 20px 20px 20px;
  grid-gap: 5px;
  background: black;
  margin:5px;
}
/*only need this*/
.card-1,.card-8 {
  grid-column:span 2;
}
.card-3,.card-5 {
  grid-row:span 2;
}
/**/

.card-1 {background: red;}
.card-2 {background: orange;}
.card-3 {background: yellow;}
.card-4 {background: green;}
.card-5 {background: cyan;}
.card-6 {background: blue;}
.card-7 {background: indigo;}
.card-8 {background: gray;}
<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
</div>

<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
</div>

<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
  <div class="card-5"></div>
  <div class="card-6"></div>
</div>

<div class="grid">
  <div class="card-1"></div>
  <div class="card-2"></div>
  <div class="card-3"></div>
  <div class="card-4"></div>
  <div class="card-5"></div>
  <div class="card-6"></div>
  <div class="card-7"></div>
  <div class="card-8"></div>
</div>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Obviously, this is a more beautiful solution than mine, thanks. Unfortunately, it does not completely solve the problem. It would be cool to customize the grid by changing only one class (.grid). And in this case, I have to change several classes (.card-{n}), depending on the grid. – psixdev Mar 30 '19 at 19:30
  • @PsiX_dev true, at leat I reduced the code as I doubt we can do everything on the gird but let's wait for more answers ;) probably there is some magic I still don't know. – Temani Afif Mar 30 '19 at 19:33