【问题标题】:Make grid container fill columns not rows使网格容器填充列而不是行
【发布时间】:2024-05-21 12:45:02
【问题描述】:

我希望我的网格像这样垂直填充:

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 的属性吗?

【问题讨论】:

  • 这是一个非常有趣的问题,我也有同样的问题,我想知道您是否找到了比这里的答案更好的解决方案,这不适合任意数量的项目/行(或不要使用 CSS 网格)。
  • 有效的答案在内心深处:*.com/a/44099977/984471

标签: html css flexbox css-grid


【解决方案1】:

对于根据需要创建新列且未定义行的垂直流动网格,请考虑使用CSS Multi-Column Layout (example)。 CSS 网格布局(至少是当前实现 - Level 1)无法执行此任务。问题来了:

在 CSS 网格布局中,grid-auto-flowgrid-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: rowgrid-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: columngrid-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>

因此,请考虑multi-column layout solution,如上所述。

规格参考:7.7. Automatic Placement: the grid-auto-flow property

【讨论】:

  • 希望它能够正常工作,但它现在只能在一行中结束:codepen.io/glenpierce/pen/XRyevJ
  • 我明白你在说什么,我不够清楚。重要的是我有 3 列。
  • 更多背景:我正在构建一个将在多个地方使用的小部件。容器可以是任意高度,并且应该能够包含任意数量的行。我试图对网格施加的唯一限制是它是 3 列宽,并且先按列然后按行对项目进行排序。
【解决方案2】:

另一个选择是放弃 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>

【讨论】:

  • 作为一个小提示:Chrome (50+) 和 Firefox (52+) 的最新版本已经具有不带前缀的列相关属性 (developer.mozilla.org/en-US/docs/Web/CSS/…)
  • @IlyaStreltsyn 我知道,但是由于仍然使用旧版本的amount of users 相当多,所以将前缀保持更长一点是个好主意:)¨
  • 绝对正确....大多数时候,问题不应该是如何强制此工具按我的意愿行事,而是如果我选择了正确的工具。
  • @vals,同意,当然,除非子元素接受 grid / flex 属性同样重要。
  • 是的,CSS 列似乎最适合纯文本内容而不是块,因为参差不齐的包装行为可能会无意中将块分开,并且跨浏览器的处理方式不同。
【解决方案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>

【讨论】:

  • :nth-child() 的惊人使用。
【解决方案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>

工作示例(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>

【讨论】:

    最近更新 更多