Skip to content Skip to sidebar Skip to footer

3 Columns Grid (top To Bottom) Using Grid CSS

Ok, here's the situation, let's say I have a list with unknown number of items, it could be 10 or a 100, and I want to lay them out in 3 columns going top to bottom not left to rig

Solution 1:

I don't think this is possible without previously know the number of items that you want to display, for your case you could do this:

ul {
   display: grid;
   grid-auto-flow: column;
   grid-template-rows: repeat(8, 1fr);
}
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>21</li>
  <li>22</li>
</ul>

But the number of rows have to be defined previously.


Solution 2:

In theory, you can kind of achieve this with CSS Grid by using "Quantity queries" based on :nth-* selectors, like this:

ul {
  list-style: none;
  display: grid;
  grid-auto-flow: row dense;
  grid-template-columns: repeat(3, 1fr);
  grid-column-gap: 10px;
}

/* by default, items go in first column */
li { grid-column: 1; }

/* if there are 1 to 3 items, the 2nd one goes to 2nd column and the 3rd one goes to 3rd column */
li:first-child:nth-last-child(n + 1):nth-last-child(-n + 3) ~ li:nth-child(n + 2):nth-child(-n + 2) { grid-column: 2; }
li:first-child:nth-last-child(n + 1):nth-last-child(-n + 3) ~ li:nth-child(n + 3) { grid-column: 3; }

/* ... */

/* if there are 19 to 21 items, items 8-14 to 2nd column and items 15+ to 3rd one */
li:first-child:nth-last-child(n + 19):nth-last-child(-n + 21) ~ li:nth-child(n + 8):nth-child(-n + 14) { grid-column: 2; }
li:first-child:nth-last-child(n + 19):nth-last-child(-n + 21) ~ li:nth-child(n + 15) { grid-column: 3; }

/* if there are 22 to 24 items, items 9-16 to 2nd column and items 17+ to 3rd one */
li:first-child:nth-last-child(n + 22):nth-last-child(-n + 24) ~ li:nth-child(n + 9):nth-child(-n + 16) { grid-column: 2; }
li:first-child:nth-last-child(n + 22):nth-last-child(-n + 24) ~ li:nth-child(n + 17) { grid-column: 3; }

/* if there are 25 to 27 items, items 10-18 to 2nd column and items 19+ to 3rd one */
li:first-child:nth-last-child(n + 25):nth-last-child(-n + 27) ~ li:nth-child(n + 10):nth-child(-n + 18) { grid-column: 2; }
li:first-child:nth-last-child(n + 25):nth-last-child(-n + 27) ~ li:nth-child(n + 19) { grid-column: 3; }

/* and so on */
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
  <li>6</li>
  <li>7</li>
  <li>8</li>
  <li>9</li>
  <li>10</li>
  <li>11</li>
  <li>12</li>
  <li>13</li>
  <li>14</li>
  <li>15</li>
  <li>16</li>
  <li>17</li>
  <li>18</li>
  <li>19</li>
  <li>20</li>
  <li>21</li>
  <li>22</li>
</ul>

However, this approach isn't practical. In my opinion, the CSS Multi-column layout is the better solution here than CSS Grid.


Solution 3:

I have a list with unknown number of items, it could be 10 or a 100

As you already observed, CSS Multi-Column Layout produces the desired layout with pure CSS - without having to know in advance the number of items in the container.

This is not the case with CSS grids - you would have to know in advance the number of items in the grid in order to calculate the necessary number of rows - which is quite a limitation.

So I would suggest you stick with Multi-Column Layout for your layout.


Assuming the above limitation is ok - then you can create the layout with css as follows:

(Note: @Ander already answered this but for what it's worth here's a small explanation)

1) On the grid container change the grid-auto-flow property to column - This lays out the grid items vertically instead of horizontally (the default).

2) Once you know the number of items, you can calculate the number of rows necessary to create a balanced grid as follows:

#rows =  ceil( #items / #columns )

So for 22 items - the # rows = ceil(22/3) = 8

ul {
   display: grid;
   grid-auto-flow: column; /* 1 */
   grid-template-rows: repeat(8, 1fr);  /* 2 */
}

We can slightly improve this solution with SASS - to produce a more generic solution which calculates the number of rows. (SASS has a ceil function)

ul {
  list-style: none;
  padding: 0;
  display:grid;
  $num-items: 22;
  $num-cols: 3;
  $num-rows: ceil($num-items / $num-cols);
  grid-template-columns: repeat($num-cols, 1fr);
  grid-template-rows: repeat($num-rows, 1fr);
  grid-auto-flow: column;
  border: 5px solid gold;
}

Codepen Demo


FWIW: Here's an alternative solution which uses nth-child selectors without needing to change the grid-auto-flow property. Unfortunately it has the same limitation that the #items must be known in advance.

li:nth-child(-n + 24) {
  grid-column: 3;
}

li:nth-child(-n + 16) {
  grid-column: 2;
}

li:nth-child(-n + 8) {
  grid-column: 1;
}

SASS Codepen


Solution 4:

I've used a little JavaScript here.Where 'lst' is id of the UL. I've used the CSS variables to pass the value of elements in the UL and ultimately calculating the required columns as per the requirement. Only downside being we will need to check if the total element number os odd or even.

<script>
 var list = document.getElementById("lst").childElementCount;
document.getElementById("lst").style.setProperty('--x',list/2);
</script>

<style>
    ul {
          list-style:none;
          display: grid;
          grid-auto-flow:column;
          grid-template-rows:repeat(var(--x),1fr);
         }
</style>

Post a Comment for "3 Columns Grid (top To Bottom) Using Grid CSS"