Setting grid-gap on Css-grid to automatically fill up available horizontal space
Asked Answered
R

6

9

I'm trying to calculate the 'grid-gap' property of a Css Grid to fill all the available space using Sass.

Depiction

Here's my setup.

//Don't want to use javascript
//scss
$width: 250px;
.product-grid {
  $total: 100%;
  $count: 4; // <--- hardcoded value, I want this to be calculated automatically 
  display: grid;
  grid-template-rows: auto;
  grid-template-columns: repeat(auto-fill, minmax($width, 1fr));
  max-height: $count;
  grid-gap: calc(calc(#{$total} - calc(#{$count} * $width)) / (#{$count - 1}));
}

.product {
  width: $width;
  height: 406px;
  background:red;
}
<div class="container">
  <div class="product-grid">
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
  </div>
</div>

I'm currently able to calculate how big 'grid-gap' should be for the products to fit, only if I give it how many columns can fit in the container - '$count'. If I'm able to somehow calculate '$count', I would be done.

What I've tried

$count: floor(calc(#{$total} / #{$width})); //but this won't work because the result is not a 'Number'
Rapparee answered 15/12, 2020 at 9:57 Comment(3)
Frankly this is something for flexbox.Fluidics
Actually I have tried to do this flexbox: I set align-items to space-between and set the flexbox to wrap. It still wouldn't align the edge of the last element with the container.Rapparee
Then you will need javascript I'm afraid. You have an unknown and you can't use that in calc.Fluidics
K
7

It's not recommended to use Grid to create that behavior. Flexbox is the best solution here by using justify-content: space-between

.product-grid {
  display: flex;
  justify-content: space-between;
  width: 500px;
  border: 1px solid blue;
}

.product {
  width: 50px;
  height: 50px;
  background:red;
  border: 1px solid yellow;
}
  <div class="product-grid">
    <div class="product"></div>
    <div class="product"></div>
    <div class="product"></div>
  </div>
Kinematics answered 15/12, 2020 at 12:19 Comment(2)
Well I tried this with flex-wrapping set to wrap so it would automatically put the products that wouldn't fit on the next row, the problem is, when the number of products in the last row is less than the columns, the spacing get's messed up and you'll end up with something like this:pasteboard.co/JF2hDYdk.pngRapparee
Is there a solution to this using grid? I have this same setup but also need multiple rows.Cartierbresson
K
2

If you've gotten so far without a satisfying answer - here are some of the things I've tried that worked for me.

What I was trying to get to was a flex's "justify-content: space-between" behavior, but with grid - allow a grid structure but space the items evenly and don't leave that weird last gap OP has in his question.

Solution 1: If you have a fixed width for your items as well as for your container, just use a negative margin as suggested here.

Solution 2: Use a flexbox, but add phantom items. (what I ended up going with)

The reason I didn't go with flexbox in the first place was I wanted all of my items to be aligned to the left, but to have a gap corresponding to as if the entire container was filled with items. i.e. a justify-content: space-between dynamic gaps, but with justify-content: left behavior in case there were fewer items than will fill the container.

This behavior could be achieved if you know the amount of items that you need to fill out your container - just add the regular items, and add max - itemsCount phantom items afterwards.

Solution 3 - use grid with phantom items.

If you can't risk the negative margin, but still have to use grid - you can also use grid with phantom items. The result will look something like this (code was not run):

//scss
$width: 250px;
.product-grid {
  display: grid;
  grid-template-columns: $width 1fr $width 1fr $width 1fr $width;
  grid-gap: 0px;
}

.product {
  width: $width;
  height: 406px;
  background:red;
}
<div class="container">
  <div class="product-grid">
    <div class="product"></div>
    <div class="phantom"></div>
    <div class="product"></div>
    <div class="phantom"></div>
    <div class="product"></div>
    <div class="phantom"></div>
    <div class="product"></div>
  </div>
</div>

the phantom items + 1fr will give you the dynamic gap that you need, but because they only exist between the product items the gap at the end won't exist.

Kessiah answered 17/1, 2023 at 6:37 Comment(0)
S
1

I'm aware this is quite old but I wanted to highlight that display: grid in conjunction with auto-fill and grid-template-columns could be useful for people.

As you can see in the code example below, we use grid-template-columns: repeat(auto-fill, minmax(125px, 1fr)); to dynamically arrange the grid columns to fit to the container.

To explain this further:

  • repeat() - this allows the rule to be repeated as many times as necessary
  • auto-fill - this instructs the browser to dynamically calculate how many columns can fit based on the second parameter and the viewport width
  • minmax(125px, 1fr) - this defines that a single column cannot be smaller than 125px but can grow to make sure the container is filled until there is enough space to introduce a new column

.product-grid {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(125px, 1fr));
}

.product {
  height: 40px;
  background-color: green;
}
<div class="product-grid">
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
  <div class="product"></div>
</div>

I am aware this does not exactly answer the original question as the asker was looking for the gap between each item to grow but as @Sadra pointed out this is not possible with display: grid.

Serology answered 1/8, 2023 at 13:32 Comment(0)
J
0

The solution is pretty simple when you know it : justify-content-space between is usable with the display flex. You can see the detail of how it works here in the "In a grid layout" : css-tricks gap property

Jordain answered 10/8, 2022 at 12:17 Comment(1)
Can you simply type out what exactly your answer is?Beckon
J
0

I know I am late but this worked for me.

1. If you know how many elements you want in a row (in this case 5).

.product-grid {
  display: grid;
  grid-template-rows: auto;
  grid-template-columns: repeat(5, auto);
}

.product {
    margin: 0 auto;
}

2. If you want to fit as many elements as possible in a row.

.product-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
}

.product {
    /* Nothing Extra Needed */
}
Jaco answered 28/7, 2024 at 20:24 Comment(0)
L
0

You can use 1fr for grid elements size with a fixed size for each element as so:

.grid{
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  width: 100%;
  gap: 16px;
}
    
.element{
  width: 120px;
  height: 120px;
  background-color: red;
  margin: 0 auto;
}
<div class="grid">
  <div class="element"></div>
  <div class="element"></div>
  <div class="element"></div>
</div>

The example above places the child divs in the center of their containers, to achieve your exact requirements you can do something like this:

.grid{
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  width: 100%;
  gap: 16px;
}
    
.element{
  width: 120px;
  height: 120px;
  background-color: red;
  margin: 0 auto;
}
            
.grid>.element:nth-child(3n){
  margin:0;
  margin-left: auto;
}
            
.grid>.element:nth-child(3n+1){
  margin:0;
  margin-right: auto;
}
<div class="grid">
  <div class="element"></div>
  <div class="element"></div>
  <div class="element"></div>
</div>
Lavern answered 16/8, 2024 at 7:11 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.