Сделать столбцы контейнера сетки не строками

Я хочу, чтобы моя сетка была заполнена вертикально:

1 4 7 
2 5 8
3 6 9
... arbitrary number of additional rows.

Вместо этого он заполняется горизонтально следующим образом:

1 2 3
4 5 6
7 8 9

Я хочу указать количество столбцов в моей сетке, а не количество строк.

Это то, что мой div выглядит со встроенным стилем CSS:

<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>

Ответ 1

Для вертикальной сетки, которая создает новые столбцы по мере необходимости, а строки не определены, рассмотрите возможность использования многостолбцовой компоновки CSS (пример). CSS Grid Layout (по крайней мере, текущая реализация - Уровень 1) не может выполнить эту задачу. Здесь проблема:

В CSS Grid Layout существует обратная рабочая взаимосвязь между свойствами grid-auto-flow и grid-template-rows/grid-template-columns.

Точнее говоря, с помощью grid-auto-flow: row (настройка по умолчанию) и grid-template-columns оба определены, элементы сетки перемещаются красиво в горизонтальном направлении, автоматически создавая новые строки по мере необходимости. Эта концепция проиллюстрирована в коде в вопросе.

#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>

Ответ 2

Другой вариант - сбросить CSS-сетку и использовать столбцы CSS, что делает именно то, что вы просите, а также иметь гораздо лучшую поддержку браузера.

.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>

Ответ 3

Больше, чем техническое упражнение, чем как практическое решение, вы можете получить какой-то результат с помощью определенных стилей в зависимости от количества элементов

Посмотрите, как это работает:

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6) ~ .item:nth-child(n+3)

первый селектор

.item:first-child:nth-last-child(n+4):nth-last-child(-n + 6)

активен, наш список имеет от 4 до 6 элементов. В этом случае какой-то элемент будет как в первом, так и во втором.

В этом случае мы хотим, чтобы в первом столбце находилось 2 элемента. задайте оставшиеся предметы (начиная с третьего) с помощью

~ .item:nth-child(n+3)

и поместите их во второй столбец. Аналогичное правило, теперь для 5-го и далее

~ .item:nth-child(n+5)

помещает другие элементы в третий столбец. Эти 2 правила имеют одинаковый приоритет и нацелены на оба последних элемента, поэтому критически важно, чтобы они отображались в этом порядке.

Нам нужно повторить аналогичные правила до максимального количества элементов, которые могут присутствовать (возможно, задания для препроцессора)

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>

Ответ 4

Простейший метод, который я видел, выглядит следующим образом:

.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>

Ответ 5

Вот один подход, основанный на CSS Grid, с использованием javascript и CSSOM для вставки пары:

transform: translate(x, y)

правил в созданную таблицу стилей.

Два правила преобразования (всего два, на основе сетки, состоящей из 3 столбцов, смещают нижние элементы исходной сетки одного столбца, перемещая элементы вверх и вправо.

Следовательно, вы можете добавить любое количество элементов в сетку с одним столбцом, и скрипт всегда будет настраивать сетку так, чтобы она имела три столбца более или менее равного размера.

Если столбцы не могут быть одинакового размера, то более высокий столбец всегда будет первым и/или вторым столбцом (никогда не справа, третьим столбцом).

Рабочий пример (9 блоков сетки):

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>