CSS grid wrapping
Asked Answered
C

6

291

Is it possible to make a CSS grid wrap without using media queries?

In my case, I have a non-deterministic number of items that I want placed in a grid and I want that grid to wrap. Using Flexbox, I'm unable to reliably space things nicely. I'd like to avoid a bunch of media queries too.

Here's some sample code:

.grid {
  display: grid;
  grid-gap: 10px;
  grid-auto-flow: column;
  grid-template-columns: 186px 186px 186px 186px;
}

.grid > * {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

And here's a GIF image:

GIF image of what I'm seeing

As a side-note, if anyone can tell me how I could avoid specifying the width of all the items like I am with grid-template-columns that would be great. I'd prefer the children to specify their own width.

Chest answered 30/3, 2017 at 22:21 Comment(0)
P
510

Use either auto-fill or auto-fit as the first argument of the repeat() notation.

<auto-repeat> variant of the repeat() notation:

repeat( [ auto-fill | auto-fit ] , [ <line-names>? <fixed-size> ]+ <line-names>? )

auto-fill

When auto-fill is given as the repetition number, if the grid container has a definite size or max size in the relevant axis, then the number of repetitions is the largest possible positive integer that does not cause the grid to overflow its grid container.

https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fill

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fill, 186px);
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

The grid will repeat as many tracks as possible without overflowing its container.

Using auto-fill as the repetition number of the repeat() notation

In this case, given the example above (see image), only 5 tracks can fit the grid-container without overflowing. There are only 4 items in our grid, so a fifth one is created as an empty track within the remaining space.

The rest of the remaining space, track #6, ends the explicit grid. This means there was not enough space to place another track.


auto-fit

The auto-fit keyword behaves the same as auto-fill, except that after grid item placement any empty repeated tracks are collapsed.

https://www.w3.org/TR/css-grid-1/#valdef-repeat-auto-fit

.grid {
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(auto-fit, 186px);
}

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

The grid will still repeat as many tracks as possible without overflowing its container, but the empty tracks will be collapsed to 0.

A collapsed track is treated as having a fixed track sizing function of 0px.

Using auto-fit as the repetition number of the repeat() notation

Unlike the auto-fill image example, the empty fifth track is collapsed, ending the explicit grid right after the 4th item.


auto-fill vs auto-fit

The difference between the two is noticeable when the minmax() function is used.

Use minmax(186px, 1fr) to range the items from 186px to a fraction of the leftover space in the grid container.

When using auto-fill, the items will grow once there is no space to place empty tracks.

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

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

When using auto-fit, the items will grow to fill the remaining space because all the empty tracks will be collapsed to 0px.

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

.grid>* {
  background-color: green;
  height: 200px;
}
<div class="grid">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
</div>

Playground:

CodePen

Inspecting auto-fill tracks

auto-fill


Inspecting auto-fit tracks

auto-fit

Permeability answered 30/3, 2017 at 22:38 Comment(13)
Is there any way to make it center the ones that are on the next line?Chest
Just like you would with flex box, on the display: grid element use justify-content: centerColorific
Dear @Ricky How to make it so that the first property of minmax, eg. repeat(auto-fill, minmax(186px, 1fr)); is not pixels, but just as long as the div has text inside?Ehrsam
@Ehrsam It is not possible, a definite size is needed. You can take a look at this answer for more details.Permeability
Is there any way to make it so that when it has to go to the next line, two of the items go down instead of only one? So like from 4 to 2 to 1 and not have it 4 to 3 to 2 to 1?Sethrida
Is it possible to do the similar wrapping in height. I mean, as soon as 1 reaches viewport height, the data inside 1 wraps to 2 and so on..similar to sine curve?Venial
Re "range the items from 186px to 186px..." can be read as a range of zero (if the following is not parsed). Perhaps rephrase?Sirkin
@Spittal, I tried justify-content: center, but it doesn't work as expected. codepen.io/helloCaptMomo/pen/MWoJpqz do you have any advice?Microbicide
is there a way to use grid-column: span with auto-fill or auto-fit?Latham
I might be missing something here but the original question was about how to make the items wrap (to next line?). the accepted solution only changes the width of the columns I don't see any wrapping...Ambiguous
Is it possible to define the max number of columns that a row can have without setting the column width?Karykaryl
So many years after you wrote this, but still quite helpful. Thanks for the thoroughness and specially the to-the-point comparison between auto-fill and auto-fit with illustrations. Could not have hoped for better.Fendley
What if you don't want all columns to have the same width?Garlen
C
25

You want either auto-fit or auto-fill inside the repeat() function:

grid-template-columns: repeat(auto-fit, 186px);

The difference between the two becomes apparent if you also use a minmax() to allow for flexible column sizes:

grid-template-columns: repeat(auto-fill, minmax(186px, 1fr));

This allows your columns to flex in size, ranging from 186 pixels to equal-width columns stretching across the full width of the container. auto-fill will create as many columns as will fit in the width. If, say, five columns fit, even though you have only four grid items, there will be a fifth empty column:

Enter image description here

Using auto-fit instead will prevent empty columns, stretching yours further if necessary:

Enter image description here

Continuator answered 30/3, 2017 at 23:52 Comment(1)
How can I do the exact opposite of "ranging from 186 pixels to equal-width columns" - i.e. I want it to auto-fit equal-width columns ranging upto a max of 186px wide columns? -Slightly
G
18

You may be looking for auto-fill:

grid-template-columns: repeat(auto-fill, 186px);

Demo: http://codepen.io/alanbuchanan/pen/wJRMox

To use up the available space more efficiently, you could use minmax, and pass in auto as the second argument:

grid-template-columns: repeat(auto-fill, minmax(186px, auto));

Demo: http://codepen.io/alanbuchanan/pen/jBXWLR

If you don't want the empty columns, you could use auto-fit instead of auto-fill.

Garvin answered 30/3, 2017 at 22:37 Comment(1)
Is there any way to make it center the ones that are on the next line?Chest
M
2

I had a similar situation. On top of what you did, I wanted to center my columns in the container while not allowing empty columns to for them left or right:

.grid { 
    display: grid;
    grid-gap: 10px;
    justify-content: center;
    grid-template-columns: repeat(auto-fit, minmax(200px, auto));
}
Montalvo answered 28/3, 2019 at 15:54 Comment(1)
Re "while not allowing empty columns to for them": Do you mean "while not allowing empty columns either for them" (totooeither)? Or "while not allowing empty columns for them" (without to)? Or something else (it doesn't seem to compute)?Sirkin
D
1

Here is a calendar example which is a common layout with lots of elements. I show the 7 days in a week in all-days with grid-template-columns: repeat(7, 1.5em); for the CSS and then only have to put the correct number of blanks at the start of each all-days I left it at 4 "fake months" as more would just be excess HTML.

.parent-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, 1fr);
}

.actions {
  display: flex;
  gap: 1em;
}

.calendar-container {
  display: grid;
  grid-gap: 0.5em;
  grid-template-columns: repeat(auto-fill, 13em);
  justify-content: center;
}

.calendar-month {
  display: grid;
  grid-gap: 0.25em;
  grid-template-columns: repeat(auto-fill, 1fr);
  grid-template-rows: 1.5em;
  border: solid 1px green;
  place-items: center;
}

.calendar-month .all-days {
  display: grid;
  grid-template-columns: repeat(7, 1.5em);
  grid-gap: 0.25em;
  place-items: center;
}

.no {
  text-align: center;
  display: block;
  width: 1.5em;
  background: lightgreen;
}
<div class="parent-container">
  <div class="calendar-container">
    <div class="calendar-month">
      <div class="actions">
        <button>Next</button>
        <span>January</span> <button>Last</button>
      </div>
      <div class="all-days">
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">5</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
        <span class="no">31</span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>February</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">5</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">16</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">28</span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>Bearanary</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
        <span class="no">31</span>
      </div>
    </div>
    <div class="calendar-month">
      <div class="actions">
        <span>Fishly</span>
      </div>
      <div class="all-days">
        <span class="no"></span>
        <span class="no"></span>
        <span class="no"></span>
        <span class="no">1</span>
        <span class="no">2</span>
        <span class="no">3</span>
        <span class="no">4</span>
        <span class="no">6</span>
        <span class="no">7</span>
        <span class="no">8</span>
        <span class="no">9</span>
        <span class="no">10</span>
        <span class="no">11</span>
        <span class="no">12</span>
        <span class="no">13</span>
        <span class="no">14</span>
        <span class="no">15</span>
        <span class="no">16</span>
        <span class="no">17</span>
        <span class="no">18</span>
        <span class="no">19</span>
        <span class="no">20</span>
        <span class="no">21</span>
        <span class="no">22</span>
        <span class="no">23</span>
        <span class="no">24</span>
        <span class="no">25</span>
        <span class="no">26</span>
        <span class="no">27</span>
        <span class="no">29</span>
        <span class="no">30</span>
      </div>
    </div>
  </div>
</div>
Danilodanio answered 3/10, 2023 at 0:42 Comment(0)
I
-4

Here's my attempt. Excuse the fluff, I was feeling extra creative.

My method is a parent div with fixed dimensions. The rest is just fitting the content inside that div accordingly.

This will rescale the images regardless of the aspect ratio. There will be no hard cropping either.

body {
    background: #131418;
    text-align: center;
    margin: 0 auto;
}

.my-image-parent {
    display: inline-block;
    width: 300px;
    height: 300px;
    line-height: 300px; /* Should match your div height */
    text-align: center;
    font-size: 0;
}

/* Start demonstration background fluff */
    .bg1 {background: url(https://unsplash.it/801/799);}
    .bg2 {background: url(https://unsplash.it/799/800);}
    .bg3 {background: url(https://unsplash.it/800/799);}
    .bg4 {background: url(https://unsplash.it/801/801);}
    .bg5 {background: url(https://unsplash.it/802/800);}
    .bg6 {background: url(https://unsplash.it/800/802);}
    .bg7 {background: url(https://unsplash.it/802/802);}
    .bg8 {background: url(https://unsplash.it/803/800);}
    .bg9 {background: url(https://unsplash.it/800/803);}
    .bg10 {background: url(https://unsplash.it/803/803);}
    .bg11 {background: url(https://unsplash.it/803/799);}
    .bg12 {background: url(https://unsplash.it/799/803);}
    .bg13 {background: url(https://unsplash.it/806/799);}
    .bg14 {background: url(https://unsplash.it/805/799);}
    .bg15 {background: url(https://unsplash.it/798/804);}
    .bg16 {background: url(https://unsplash.it/804/799);}
    .bg17 {background: url(https://unsplash.it/804/804);}
    .bg18 {background: url(https://unsplash.it/799/804);}
    .bg19 {background: url(https://unsplash.it/798/803);}
    .bg20 {background: url(https://unsplash.it/803/797);}
/* end demonstration background fluff */

.my-image {
    width: auto;
    height: 100%;
    vertical-align: middle;
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
}
<div class="my-image-parent">
    <div class="my-image bg1"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg2"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg3"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg4"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg5"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg6"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg7"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg8"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg9"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg10"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg11"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg12"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg13"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg14"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg15"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg16"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg17"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg18"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg19"></div>
</div>

<div class="my-image-parent">
    <div class="my-image bg20"></div>
</div>
Interatomic answered 23/6, 2017 at 5:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.