9

I am trying to create an ordered multi-column list, but am struggling with CSS Grid layout rules.

The desired outcome should be responsive. On small screens 2 grid columns, on larger screens up to 4, all while maintaining a column order.

Instead of being ordered like this:

1  2  3  4
5  6  7  8
9  10 11 12
13 14 15

They should be ordered like this:

1 5 9  13
2 6 10 14
3 7 11 15
4 8 12

I feel I am close with this fiddle.

ol {
  margin: 0;
  padding: 0;
  list-style: none;
  background-color: grey;
  
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(33.333%, 50%));
  grid-auto-flow: column;
  grid-template-rows: repeat(5, 1em);
}

li {
  outline: 1px solid orange;
}
<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>Item 12</li>
  <li>Item 13</li>
  <li>Item 14</li>
  <li>Item 15</li>
</ol>

Especially, I am struggling with these points:

a) grid-auto-flow: column is required to make the column wrapping work, but also forces me to add grid-template-rows: repeat(5, 1em) to specify a row count, which breaks the responsiveness. Is there a way to calculate the row count automatically based on content and column count?

b) Why are the columns widths not evenly distributed and why don't they adapt to the screen size? Isn't this what minmax is for?

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Sven
  • 12,997
  • 27
  • 90
  • 148
  • For some reason using `grid-auto-flow: column` seems to break the auto-fill mechanism for the rows. The only way I managed to pull this off is with media queries. https://codepen.io/danield770/pen/JJLpgR/?editors=1100 - but I suppose that's cheating :) – Danield Jul 02 '17 at 10:32

2 Answers2

0

Tweak with column count to change number of columns :)

ol {
  margin: 0;
  padding: 0;
  list-style: none;
  /*---*/
  column-count: 4;
  column-gap: 0;
  width: 100%;
}

li {
  background-color: grey;
  outline: 1px solid orange;
}
<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>Item 12</li>
  <li>Item 13</li>
  <li>Item 14</li>
  <li>Item 15</li>
</ol>
0

Let's go through your two sticking points.

  1. grid-auto-flow: column is required to make the column wrapping work, but also forces me to add grid-template-rows: repeat(5, 1em) to specify a row count, which breaks the responsiveness. Is there a way to calculate the row count automatically based on content and column count?

grid-auto-flow: column does not make column wrapping work. In fact, it does the exact opposite. The rule creates new columns to accommodate additional grid items.

Here's how it works (from the spec):

7.7. Automatic Placement: the grid-auto-flow property

Grid items that aren’t explicitly placed are automatically placed into an unoccupied space in the grid container by the auto-placement algorithm.

grid-auto-flow controls how the auto-placement algorithm works, specifying exactly how auto-placed items get flowed into the grid.

column

The auto-placement algorithm places items by filling each column in turn, adding new columns as necessary.

row

The auto-placement algorithm places items by filling each row in turn, adding new rows as necessary. If neither row nor column is provided, row is assumed.

With regard to your question:

Is there a way to calculate the row count automatically based on content and column count?

With CSS Grid alone, I don't believe so. As it says in the spec, grid-auto-flow is designed to add new tracks in the specified direction (column / row).

If it can be done with Grid, then it wouldn't be fully automatic. You would need at least some defined placement and, I would guess, media queries.

Lastly, with regard to column wrapping, that comes from the auto-fit or auto-fill values in the grid-template-columns and grid-template-rows properties.


  1. Why are the column widths not evenly distributed and why don't they adapt to the screen size? Isn't this what minmax is for?

This goes back to the spec section highlighted above.

This is your column-sizing code:

grid-template-columns: repeat(auto-fill, minmax(33.333%, 50%));

This translates to: The width of each explicit column must be a minimum of 33.333% and a maximum of 50%.

The problem is that the third column is not explicit. It is implicit, as it is being added to the grid by the auto-placement algorithm, under the guidance of grid-auto-flow: column. So this column is not subject to grid-template-columns, which deals solely with explicit track sizing.

The properties for implicit track sizing are grid-auto-columns and grid-auto-rows. Their default value is auto, which is what you're seeing in your layout: The third column is the width of its content.

ol {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(33.333%, 50%));
  grid-auto-flow: column;
  grid-template-rows: repeat(5, 1em);

  margin: 0;
  padding: 0;
  list-style: none;
  background-color: grey;
}

li {
  outline: 1px solid orange;
}
<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>Item 12</li>
  <li>Item 13</li>
  <li>Item 14</li>
  <li>Item 15</li>
</ol>

Once you set the value of grid-auto-columns, the third column can be properly sized.

ol {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(33.333%, 50%));
  grid-auto-flow: column;
  grid-template-rows: repeat(5, 1em);
  grid-auto-columns: 33.333%; /* NEW */

  margin: 0;
  padding: 0;
  list-style: none;
  background-color: grey;
}

li {
  outline: 1px solid orange;
}
<ol>
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
  <li>Item 4</li>
  <li>Item 5</li>
  <li>Item 6</li>
  <li>Item 7</li>
  <li>Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>Item 12</li>
  <li>Item 13</li>
  <li>Item 14</li>
  <li>Item 15</li>
</ol>

Of course, the information above is intended to be an explanation, not a solution to the main problem, as I don't believe CSS Grid provides one.

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 1
    In particular, note `auto-fill` will use the *max* size to calculate how many tracks to create, if possible. In this case, 50% is compatible with that, so it'll make two columns. (There's never a reason to use auto-fill with percentages, since you trivially know how many columns will fit just from simple division.) – Xanthir Sep 18 '18 at 17:43
  • Thanks for the clarification. Yes, I've noticed that `minmax()` uses *max* in track-sizing calculations. The issue is explored here: [`minmax()` defaulting to max](https://stackoverflow.com/q/50654400/3597276). Thanks for [posting an explanation](https://stackoverflow.com/a/52377092/3597276). @Xanthir – Michael Benjamin Sep 23 '18 at 00:14
  • Also, with regard to the question in this post, it's explored in more detail here: [Make grid container fill columns not rows](https://stackoverflow.com/q/44092529/3597276). If there is, in fact, a way for Grid to automatically add columns after filling all vertical space (like CSS Columns), you may want to mention it there. @Xanthir – Michael Benjamin Sep 23 '18 at 00:18