8

I have grid-template-areas that builds on known elements, but not all elements can be fetched from the database. If I don’t get something from the database, then I don’t render the html element and I get an empty "dashed" rows with gaps. See the attached picture, empty rows are located under the blue boxes. Is it possible to hide unused areas or remove gaps from them?

Empty row with gaps

*{
 margin: 0;
 padding: 0;
}

.name {
  grid-area: name;
}

.lastname{
  grid-area: lastname;
}

.phone {
  grid-area: phone;
}

.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-areas: 
    'name name name lastname lastname lastname'
    'somethingelse somethingelse somethingelse . . .'
    'phone phone phone phone phone phone'
    'email email email email email email';
}
<div class="wrapper">
  <div class="field name">
    <div class="titile">Name</div>
    <div class="description">Antony</div>
  </div>
  <div class="field lastname">
    <div class="titile">Last name</div>
    <div class="description">Lastnamed</div>
  </div>
  <div class="field phone">
    <div class="titile">Phone number</div>
    <div class="description">123 456 789</div>
  </div>
</div>

NOT RELATED TO MY QUESTION

This question is not related to mine, because I don't have empty item. I have empty row without html items with gaps

Marty
  • 534
  • 8
  • 24
  • I don't know anything about css grid but looks like you can use different values for row and column. `gap: 5px 10px;`. or `row-gap: 5px;` and `column-gap: 10px;` – hyperdrive Jul 22 '20 at 19:31
  • @hyperdrive noo) I need only 20px gap :) And i need to remove empty rows without changing grid-template-areas) or I need to remove gaps from empty rows :) – Marty Jul 22 '20 at 19:33
  • something like row auto-shift up – Marty Jul 22 '20 at 19:36
  • What rows are 'empty' in your example? The all look like they have content in them to me. – hyperdrive Jul 22 '20 at 19:38
  • empty it's a "dashed" rows under blue boxed rows :) – Marty Jul 22 '20 at 19:40
  • Does this answer your question? [How do you collapse unused row in a CSS grid?](https://stackoverflow.com/questions/50708974/how-do-you-collapse-unused-row-in-a-css-grid) – disinfor Jul 22 '20 at 19:58
  • @disinfor no. This case for existing for example `div`, but without content. In my case I don't have item for row, but row is present – Marty Jul 22 '20 at 20:00
  • Oh I see, you have template area for "something else" so it's adding that to the grid. But you don't want "something else" there. – hyperdrive Jul 22 '20 at 20:13
  • this question is already clear and understandable. vote to reopen. – doğukan Jul 22 '20 at 20:15
  • please, vote to reopen – Marty Jul 22 '20 at 20:17
  • 3
    Voted to reopen - as it is clear. And is different from the perceived duplicate. – disinfor Jul 22 '20 at 20:17
  • 1
    I had the exact same problem a month ago. I didn't have empty borders, because I did not render the blocks I didn't get from the database (I use Angular's *ngIf to not render the blocks which would be empty), so only the excess gaps caused problem. I ended up not using grid-gap, I simply added right and bottom margins to the blocks, so I only got single "gaps", that is margins between blocks. It's OK for now, but it would be nice to have "collapsible grid-gap" :) – kol Jul 22 '20 at 20:23
  • @kol that's a great solution, since OP can add the margin to the bottom of each of the HTML elements. If one is not present, no margin. Good thinking! And column-gap can still be used. – disinfor Jul 22 '20 at 20:25
  • 1
    But I’ll wait few days for solution (if solution can be) – Marty Jul 22 '20 at 20:29
  • @Marty there really isn't a solution using `grid-gap` since there is no fallback or spec if the template area is empty - e.g. unlike margin, the gap doesn't collapse. kol's solution is about the best you're going to get. – disinfor Jul 22 '20 at 20:31
  • 2
    That's very interesting, I dag a bit in the documentation and in the Editor's draft and I didn't see anything related to rendering untracked area-names. I guess it is implemented in a way that giving area-name in the template, even if there no class referenced to it, will tokenize it and render it anyways. – SomoKRoceS Jul 22 '20 at 20:33
  • Should I create issue to w3.org? – Marty Jul 22 '20 at 20:46
  • I would say it is something you can bring up. Not sure if it intended though. – SomoKRoceS Jul 22 '20 at 21:03
  • I have found sort of a solution for you, not exactly with the parameters you wanted, but it might help you. writing an answer. – SomoKRoceS Jul 22 '20 at 21:04

3 Answers3

3

I had the exact same problem a month ago. I didn't have empty borders, because I did not render the blocks I didn't get from the database (I use Angular's *ngIf to not render the blocks which would be empty), so only the excess gaps caused problem. I ended up not using grid-gap, I simply added right and bottom margins to the blocks, so I only got single "gaps", that is margins between blocks. It's OK for now, but it would be nice to have "collapsible grid-gap" :)

Here is my code, after extreme simplification, of course... and note that I use Angular.

HTML:

<div id="container">
  <div id="block-0-0" class="block" *ngIf="data[0][0]">
    <app-block [block-data]="data[0][0]"></app-block>
  </div>
  <div id="block-0-1" class="block" *ngIf="data[0][1]">
    <app-block [block-data]="data[0][1]"></app-block>
  </div>
  <div id="block-1-0" class="block" *ngIf="data[1][0]">
    <app-block [block-data]="data[1][0]"></app-block>
  </div>
  <div id="block-1-1" class="block" *ngIf="data[1][1]">
    <app-block [block-data]="data[1][1]"></app-block>
  </div>
  <!-- etc. -->
</div>

CSS:

div#container {
  display: grid;
  grid-template:
    "block-0-0 block-0-1" auto
    "block-1-0 block-1-1" auto
    /* etc. */
    / 300px 300px;
}

div.block {
  margin: 0 10px 10px 0;
  border: solid 1px gray;
}

div#block-0-0 {
  grid-area: block-0-0;
}

div#block-0-1 {
  grid-area: block-0-1;
}

div#block-1-0 {
  grid-area: block-1-0;
}

div#block-1-1 {
  grid-area: block-1-1;
}

/* etc. */

I'd like to emphasize that this is only a workaround. I'd be happy to see The Solution :)

kol
  • 27,881
  • 12
  • 83
  • 120
  • I know this was a quick answer, but can you add a code example to make this more complete? I did a quick test and it works great. – disinfor Jul 22 '20 at 20:29
  • 1
    Wait a sec, I have to open github :) It's a private project, but this part can be shared. – kol Jul 22 '20 at 20:30
  • Good solution. And simple, but I’ll wait few days. Probably we can find better solution :) – Marty Jul 22 '20 at 20:31
  • @Kol I would just use the OPs code and add margin values to the elements :) – disinfor Jul 22 '20 at 20:32
  • @Marty to avoid posting another answer, you can probably do this: https://jsfiddle.net/mut7yLdh/ – disinfor Jul 22 '20 at 20:36
  • Doesn't this kinda almost defeat purpose of using css grid in the first place over flex? What is gained? – hyperdrive Jul 22 '20 at 20:39
  • 1
    I added some code. I will create a working jsfiddle tomorrow (sorry it's almost 11:00PM here, and my wife is about to kill me... if I don't let go of my laptop *immediately*). – kol Jul 22 '20 at 21:00
1

Do you need named template areas?

Could you just define how many columns certain grid items should span?

.name { 
  grid-column: span 3;
}

.lastname {
  grid-column: span 3;
}

.phone { 
  grid-column: span 6;
}

.wrapper {
  gap: 10px;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
}
hyperdrive
  • 1,786
  • 5
  • 19
  • 33
1

So as I wrote in the comments, it seems like when using grid-gap with grid-template-areas, the template-row is being rendered even if there is no content in it, which makes grid-gap apply on it anyways. After digging a bit in the documentation and in the Editor's draft and I didn't see anything we can manipulate how grid-gap works and make it responsive to unused row tracks.

I guess grid-gap need some work, so you can open an issue to w3.org or at least bring it up.

My suggestions for now are:

Option 1

Best solution I can suggest (while still using areas names and grid-template-areas):

There are great alternatives for grid-gap, you can use padding or margin for each cell content, that will result exactly what you want:

*{
 margin: 0;
 padding: 0px;
}

.name {
  grid-area: name;
  margin: 0px 20px 20px 0px
}

.lastname{
  grid-area: lastname;
  margin: 0px 20px 20px 0px
}

.phone {
  grid-area: phone;
  margin: 0px 20px 20px 0px
}

.email {
  grid-area: email;
  margin: 0px 20px 20px 0px
}

.somethingelse {
  grid-area: somethingelse;
  margin: 0px 20px 20px 0px
}

.wrapper {
  display: grid;
  grid-template-areas: 
    'name name name lastname lastname lastname'
    'somethingelse somethingelse somethingelse . . .'
    'phone phone phone phone phone phone'
    'email email email email email email';
}
<div class="wrapper">
  <div class="field name">
    <div class="titile">Name</div>
    <div class="description">Antony</div>
  </div>
  <div class="field lastname">
    <div class="titile">Last name</div>
    <div class="description">Lastnamed</div>
  </div>
  
  
  <div class="field phone">
    <div class="titile">Phone number</div>
    <div class="description">123 456 789</div>
  </div>
  
  
  
</div>

Option 2

Using grid-gap as you want, but without using template-areas, instead render rows and cols depends on the elements that should be rendered.

Notice that in this solution, the position of the divs are important.

*{
 margin: 0;
 padding: 0px;
}

.name {
grid-row: 1fr;
  grid-column: 1 / 2;
}

.lastname{
grid-row: 1fr;
  grid-column: 2 / 3;
}

.phone {
grid-row: 1fr;
  grid-column: 1 / 2;
}

.email {
grid-row: 1fr;
  grid-column: 1 / 2;
}

.somethingelse {
grid-row: 1fr;
  grid-column: 1 / 2;
}

.wrapper {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-gap: 20px;
}
<div class="wrapper">
  <div class="field name">
    <div class="titile">Name</div>
    <div class="description">Antony</div>
  </div>
  <div class="field lastname">
    <div class="titile">Last name</div>
    <div class="description">Lastnamed</div>
  </div>
  
  
  <div class="field phone">
    <div class="titile">Phone number</div>
    <div class="description">123 456 789</div>
  </div>
  
  
  
  
  
</div>

Option 3

This will not behave exactly as you want, but it is something you can check:

I thought about using the grid gap with units relative to the size of the grid (if more rows were generated, the gap between them will be bigger, and if no row will be generated, then the gap will "shrink" relatively).

So you could use percentage as a unit for grid-gap, instead of a fixed gap size.

*{
 margin: 0;
 padding: 0;
}

.name {
  grid-area: name;
}

.lastname{
  grid-area: lastname;
}

.phone {
  grid-area: phone;
}

.email {
  grid-area: email;
}

.somethingelse {
  grid-area: somethingelse;
}

.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-areas: 
    'name name name lastname lastname lastname'
    'somethingelse somethingelse somethingelse . . .'
    'phone phone phone phone phone phone'
    'email email email email email email';
}
<div class="wrapper">
  <div class="field name">
    <div class="titile">Name</div>
    <div class="description">Antony</div>
  </div>
  <div class="field lastname">
    <div class="titile">Last name</div>
    <div class="description">Lastnamed</div>
  </div>
  <div class="field phone">
    <div class="titile">Phone number</div>
    <div class="description">123 456 789</div>
  </div>
  
</div>

Hope it helped you out somehow.

SomoKRoceS
  • 2,934
  • 2
  • 19
  • 30