it-swarm.com.ru

Сделать контейнер сетки заполнять столбцы, а не строки

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

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>

Важно, чтобы размер моей сетки составлял 3 столбца, но я хочу, чтобы элементы заполнялись по столбцам, а не по строкам. Возможно ли это в CSS Grid? Я прочитал это https://css-tricks.com/snippets/css/complete-guide-grid/ , но ничего не видел в заказе.

CSS Flexbox имеет flex-direction, нет ли такого атрибута для CSS Grid?

16
Glen Pierce

Для вертикальной сетки, которая создает новые столбцы по мере необходимости, а строки не определены, рассмотрите возможность использования CSS Multi-Column Layout ( example ). CSS Grid Layout (по крайней мере, текущая реализация - Level 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>

Однако при переключении на grid-template-rows элементы сетки складываются в один столбец.

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

Нет автоматического создания столбцов с grid-auto-flow: row и grid-template-rows. grid-template-columns должен быть определен (следовательно, обратная связь с 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>

Такое же поведение верно в обратном сценарии.

Когда оба grid-auto-flow: column и grid-template-rows определены, элементы сетки перемещаются в вертикальном направлении, автоматически создавая новые столбцы по мере необходимости.

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

Однако при переключении на grid-template-columns элементы сетки складываются в одну строку. (Это проблема, о которой спрашивают большинство людей, в том числе и в этом вопросе.)

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

Там нет автоматического создания строк. Это требует grid-template-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>

Следовательно, рассмотрим решение с несколькими столбцами , как предложено выше.

Ссылка на спецификацию: 7.7. Автоматическое размещение: свойство grid-auto-flow

14
Michael_B

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

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

7
LGSon

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

Давайте посмотрим, как это работает:

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

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

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

2
RayYates

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

transform: translate(x, y)

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

Два правила преобразования (есть only два, основанные на том, что сетка 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>


Рабочий пример (10 единиц сетки):

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 единиц сетки):

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>

Рабочий пример (14 единиц сетки):

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>

0
Rounin