Make grid container fill columns not rows
Solution 1
For a vertically-flowing grid that creates new columns as necessary, and rows are not defined, consider using CSS Multi-Column Layout (example). CSS Grid Layout (at least the current implementation - Level 1) cannot perform this task. Here's the problem:
In CSS Grid Layout, there is an inverse relationship between the grid-auto-flow
and grid-template-rows
/ grid-template-columns
properties.
More specifically, with grid-auto-flow: row
(the default setting) and grid-template-columns
both defined, grid items flow nicely in a horizontal direction, automatically creating new rows as necessary. This concept is illustrated in the code in the question.
#container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-flow: row;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
However, with a switch to grid-template-rows
, grid items stack in a single column.
#container {
display: grid;
grid-template-rows: 1fr 1fr 1fr;
grid-auto-flow: row;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
There is no automatic creation of columns with grid-auto-flow: row
and grid-template-rows
. grid-template-columns
must be defined (hence, the inverse relationship with grid-auto-flow
).
#container {
display: grid;
grid-template-rows: 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-flow: row;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
The same behavior is true in the reverse scenario.
With grid-auto-flow: column
and grid-template-rows
both defined, grid items flow nicely in a vertical direction, automatically creating new columns as necessary.
#container {
display: grid;
grid-template-rows: 1fr 1fr 1fr;
grid-auto-flow: column;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
However, with a switch to grid-template-columns
, grid items stack in a single row. (This is the problem most people ask about, including in this question.)
#container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-auto-flow: column;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
There is no automatic creation of rows. That requires grid-template-rows
to be defined. (This is the solution most often provided, but it is usually rejected because the layouts have a variable number of rows.)
#container {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: 1fr 1fr 1fr;
grid-auto-flow: column;
}
<div id="container">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
Hence, consider a multi-column layout solution, as suggested above.
Spec reference: 7.7. Automatic Placement: the grid-auto-flow
property
Solution 2
Another option is to drop CSS Grid and use CSS Columns, which does exactly what you ask and also have much better browser support.
.csscolumn {
-webkit-column-count: 3; /* Chrome, Safari, Opera */
-moz-column-count: 3; /* Firefox */
column-count: 3;
}
/* styling for this demo */
.csscolumn {
width: 50%;
}
.csscolumn + .csscolumn {
margin-top: 10px;
padding-top: 10px;
border-top: 1px solid;
}
<div class="csscolumn">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
</div>
<div class="csscolumn">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
<div class="csscolumn">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
</div>
Solution 3
More as a technical exercise than as a practical solution, you can get somehow your result using specific styles depending on the number of items
Let's see how it works:
.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+3)
the first selector
.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6)
is active is our list has between 4 and 6 elements. In this case, some item will be both in the first condition and in the second.
In this case, we want 2 items to be in the first column. target the remaining items (from the third onwards) with
~ .item:nth-child(n+3)
and put them on the second column. A similar rule, now for the 5th and onwards
~ .item:nth-child(n+5)
puts the other items in the third column. These 2 rules have the same precedence, and target both the last items, so it's critical that they appear in this order.
We need to repeat similar rules up to the maximum amount of items that can be present (probably a job for a preprocessor)
var elements = 5;
function add () {
var ctn = document.getElementById("container");
var ele = document.createElement("div");
elements ++;
ele.innerHTML = elements;
ele.className = "item";
ctn.appendChild (ele);
}
#container {
width: 90%;
border: solid 1px red;
display: grid;
grid-template-rows: 33% 33% 33%;
grid-auto-flow: column dense;
}
.item {
width: 90%;
height: 80px;
background-color: lightgreen;
margin: 10px;
grid-column: 1;
}
.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+3) {
background-color: yellow;
grid-column: 2;
}
.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+5) {
background-color: tomato;
grid-column: 3;
}
.item:first-child:nth-last-child(n+7):nth-last-child(-n + 9) ~ .item:nth-child(n+4) {
background-color: burlywood;
grid-column: 2;
}
.item:first-child:nth-last-child(n+7):nth-last-child(-n + 9) ~ .item:nth-child(n+7) {
background-color: blueviolet;
grid-column: 3;
}
.item:first-child:nth-last-child(n+10):nth-last-child(-n + 12) ~ .item:nth-child(n+5) {
background-color: darkcyan;
grid-column: 2;
}
.item:first-child:nth-last-child(n+10):nth-last-child(-n + 12) ~ .item:nth-child(n+9) {
background-color: chartreuse;
grid-column: 3;
}
.item:first-child:nth-last-child(n+13):nth-last-child(-n + 15) ~ .item:nth-child(n+6) {
background-color: yellow;
grid-column: 2;
}
.item:first-child:nth-last-child(n+13):nth-last-child(-n + 15) ~ .item:nth-child(n+11) {
background-color: tomato;
grid-column: 3;
}
<button onclick="add()">Add</button>
<div id="container">
<div class="item">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
</div>
Solution 4
The simplest method I've seen follows:
.grid {
display: grid;
grid-auto-flow: column;
grid-gap: 1px;
grid-template-columns: repeat(3, 1fr);
grid-template-rows: repeat(5, auto);
}
<div class="grid">
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>6</div>
<div>7</div>
<div>8</div>
<div>9</div>
<div>10</div>
<div>11</div>
<div>12</div>
<div>13</div>
</div>
Related videos on Youtube
![Glen Pierce](https://i.stack.imgur.com/QHIcL.png?s=256&g=1)
Glen Pierce
Software engineer using Java, JavaScript, HTML, CSS, SQL, Python, and a little C#. I love git. I've got some personal projects using Node.js and some Unity. I'd love to do more with D3.js. I'm also interested in doing some more work with Blender.
Updated on July 08, 2022Comments
-
Glen Pierce almost 2 years
I want my grid to fill in vertically like this:
1 4 7 2 5 8 3 6 9 ... arbitrary number of additional rows.
Instead, it fills in horizontally like this:
1 2 3 4 5 6 7 8 9
I want to specify the number of columns in my grid, not the number of rows.
This is what my div looks like with inline CSS styling:
<div style="display:grid; grid-template-columns:1fr 1fr 1fr;"> <div>1</div> <div>2</div> <div>3</div> <div>4</div> <div>5</div> <div>6</div> <div>7</div> <div>8</div> <div>9</div> </div>
It's important that my grid be 3 columns wide, but I want the items to be populated by column, not by row. Is this possible in CSS Grid? I've read through this https://css-tricks.com/snippets/css/complete-guide-grid/ but didn't see anything about order.
CSS Flexbox has
flex-direction
, isn't there an attribute like that for CSS Grid?-
benface almost 7 yearsThis is a very interesting problem, I have the same question and I'm wondering if you found a better solution than the answers here, which are not suitable for an arbitrary number of items/rows (or don't use CSS Grid).
-
Manohar Reddy Poreddy over 5 yearsAnswer that works is deep down: stackoverflow.com/a/44099977/984471
-
-
Glen Pierce about 7 yearsWould love for that to work, but it just ends up on one line now: codepen.io/glenpierce/pen/XRyevJ
-
Glen Pierce about 7 yearsI see what you're saying, I wasn't sufficiently clear. It's important that I have 3 columns.
-
Glen Pierce about 7 yearsMore background: I'm building a widget that's going to be used in several places. The containers can be any height and should be able to contain any number of rows. The only limit I'm trying to impose on the grid is that it be 3 columns wide and order the items by column first then row.
-
Glen Pierce about 7 yearsLet us continue this discussion in chat.
-
Ilya Streltsyn about 7 yearsJust as a small note: recent versions of Chrome (50+) and Firefox (52+) have already unprefixed column-related properties (developer.mozilla.org/en-US/docs/Web/CSS/…)
-
Asons about 7 years@IlyaStreltsyn I know, but as the amount of users that still use older versions is quite many, it is a good idea to keep the prefix a little bit longer :)¨
-
Michael Benjamin about 7 yearsAmazing use of :nth-child().
-
vals about 7 yearsAbsolutely right .... Most of the time the question shouldn't be how can i force this tool to behave like I want, but instead if I have choosen the right tool.
-
Michael Benjamin about 7 years@vals, agreed, unless of course, it's equally important for child elements to accept grid / flex properties.
-
MattTreichel over 5 yearsYeah, CSS Columns seem best suited for purely textual content rather than blocks, because of spotty wrapping behaviour that can break blocks apart unintentionally, with handling that differs cross-browser.
-
mix3d over 4 yearsSimple, yes, but does not work if you need a variable number of rows, depending on the length of the incoming data