Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I sort grid items from top to bottom while still wrapping to the next column? [duplicate]

Tags:

css

css-grid

I have an unknown amount of items that need to be displayed in a grid. I'd like the number of columns to auto-fill as needed, with no limit on the number of rows. I can get this working just fine:

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  list-style: none;
}
<ul class="grid">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
  <li>e</li>
  <li>f</li>
  <li>g</li>
  <li>h</li>
</ul>

However, I'd also like the items to be sorted alphabetically by column:

a  d  g
b  e  h
c  f

I know I can use grid-auto-flow: column to place each item by column instead of by row, but if I do that, I just get one long row.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-auto-flow: column;
  list-style: none;
}
<ul class="grid">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
  <li>e</li>
  <li>f</li>
  <li>g</li>
  <li>h</li>
</ul>

How can I keep the behavior of the first snippet but with sorting from top to bottom instead of from left to right?

like image 267
Christian Jensen Avatar asked Aug 31 '25 04:08

Christian Jensen


2 Answers

I think the only way to do this is to consider JS and dynamically adjust the number of rows.

Here is a simplified example where you will need a more complete code if you will have gap, padding, etc

var minv = 200; 
var grid = document.querySelector('.grid');
var nb   = document.querySelectorAll('.grid li').length;

var nb_row = Math.ceil(nb/Math.floor(grid.offsetWidth/200));
/* grid.offsetWidth/200 = X will give the number of columns
   nb/X will give the number of rows
   
   We use floor with the first as we won't have overflow but a wrap (so 3.2 should be 3)
   We use ceil with the second one as we may have the last row with fewer elements (so 3.2 should be 4)

*/

grid.style.gridTemplateRows="repeat("+nb_row+",auto)";

window.addEventListener('resize', function(event){
   nb_row = Math.ceil(nb/Math.floor(grid.offsetWidth/200));
   grid.style.gridTemplateRows="repeat("+nb_row+",auto)";
});
.grid {
  display: grid;
  grid-auto-columns: minmax(200px, 1fr);
  grid-auto-flow: column;
  list-style: none;
  padding:0;
}
<ul class="grid">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
  <li>e</li>
  <li>f</li>
  <li>g</li>
  <li>h</li>
</ul>
like image 182
Temani Afif Avatar answered Sep 02 '25 18:09

Temani Afif


You can use grid-template-rows to limit the amount of rows, so the grid can calculate the items for each column.

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-template-rows: repeat(3, 100px);
  grid-auto-flow: column;
  list-style: none;
}
<ul class="grid">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
  <li>e</li>
  <li>f</li>
  <li>g</li>
  <li>h</li>
</ul>
like image 43
IvanS95 Avatar answered Sep 02 '25 17:09

IvanS95