Make grid container fill columns not rows

Viewed 64834

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?

6 Answers

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>

Here is one CSS Grid based approach using javascript and the CSSOM to insert a pair of:

transform: translate(x, y)

rules into a generated stylesheet.

The two transform rules (there are only two, based on the grid being 3 columns wide displace the lower elements of the original single column grid, moving the elements upwards and to the right.

Consequently, you can add any number of elements to the single-column grid, and the script will always adjust the grid so that it has three columns of more or less equal size.

If the columns cannot be of exactly equal size, then the taller column(s) will always be the first and / or second column (never the rightmost, third column).

Working Example (9 grid units):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));
var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.push(shortColumn);
    }

    else {

        columns.push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-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>


Working Example (10 grid units):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.push(shortColumn);
    }

    else {

        columns.push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-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>


Working Example (11 grid units):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.push(shortColumn);
    }

    else {

        columns.push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-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>

Working Example (14 grid units):

var numberOfColumns = 3;

document.head.appendChild(document.createElement('style'));

var newStyles = document.styleSheets[(document.styleSheets.length - 1)];

var myGrid = document.getElementsByClassName('my-grid')[0];
var myGridUnits = myGrid.getElementsByTagName('div');

var tallColumn = Math.ceil(myGridUnits.length /  numberOfColumns);
var shortColumn = Math.floor(myGridUnits.length / numberOfColumns);

var nextUnit = 1;
var unitsRemaining = myGridUnits.length;
var xTranslate, yTranslate;
var columns = [];

for (var i = 0; i < (numberOfColumns - 1); i++) {


    if (unitsRemaining % shortColumn === 0) {
    
        columns.push(shortColumn);
    }

    else {

        columns.push(tallColumn);
    }
    
    nextUnit += columns[(columns.length - 1)];
    unitsRemaining -= columns[(columns.length - 1)];
    
    xTranslate = ((i + 1) * 48);
    yTranslate = 0;
    columns.forEach(function(columnHeight){yTranslate += (columnHeight * 48);});
                         
    newStyles.insertRule('.my-grid div:nth-of-type(n+' + nextUnit + ') {transform: translate(' + xTranslate + 'px, ' + (0 - (yTranslate)) + 'px);}', newStyles.cssRules.length);

}
.my-grid {
display: inline-grid;
grid-row-gap: 6px;
}

.my-grid div {
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
border: 1px solid rgb(127, 127, 127);
}
<div class="my-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>14</div>
</div>

One way to fill the grid vertically is using column-count = 3; CSS property and removing the display: grid;. But in my case it caused an issue (big white space) on Iphone 13. Here is how I switched the order from horizontal to vertical in grid layout:

function horizontalToVerticalGridSorting(gridSelector) {
    const grid = document.querySelector(gridSelector);
    const gridItems = grid.children;
    const gridComputedStyle = window.getComputedStyle(grid);
    // Grid columns count
    const colCount = gridComputedStyle.gridTemplateColumns.split(' ').length;
    // Grid rows count
    const rowsCount = gridComputedStyle.gridTemplateRows.split(' ').length;
    // Total items count
    const itemsCount = gridItems.length;
    // Full columns amount
    const fullColCount = itemsCount % colCount || colCount;
    // Amount of items in full columns
    const fullColItems = fullColCount*rowsCount;
    // Current column
    let curX = 1;
    // Current row
    let curY = 1;
    for (let i = 0; i < itemsCount; i++) {
        gridItems[i].style.order = (curY - 1) * colCount + curX;
        // Number of items in column
        let perColItems = rowsCount;
        // Not full column
        if (i >= fullColItems) {
            perColItems--;
        }
        curY++;
        // Switching to the next column
        if (curY > perColItems) {
            curY = 1;
            curX++;
        }
    }
}
horizontalToVerticalGridSorting('.cols');
.cols {
  text-align: center;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.col {
  padding: 10px;
}
<div class="cols">
  <div class="col">1</div>
  <div class="col">2</div>
  <div class="col">3</div>
  <div class="col">4</div>
  <div class="col">5</div>
  <div class="col">6</div>
  <div class="col">7</div>
  <div class="col">8</div>
  <div class="col">9</div>
  <div class="col">10</div>
</div>

The function goes through all grid items and calculates the new coordinates [X, Y] for vertical sorting. Then the order is calculates based on that new coordinates. It works with any grid size

Related