Sadra M.
Sadra M.

Reputation: 1532

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

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'

Upvotes: 10

Views: 20523

Answers (6)

EmanuelLamba
EmanuelLamba

Reputation: 97

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>

Upvotes: 0

Kodd
Kodd

Reputation: 163

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 */
}

Upvotes: 0

lukehillonline
lukehillonline

Reputation: 2647

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.

Upvotes: 1

jonyB
jonyB

Reputation: 12025

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.

Upvotes: 2

Benoit Bonavia
Benoit Bonavia

Reputation: 63

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

Upvotes: 0

deerawan
deerawan

Reputation: 8443

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>

Upvotes: 7

Related Questions