在CSS Grid布局中反转列顺序

91
我希望利用CSS网格来反转两个并排div的显示顺序,其中一个div会任意增长(我不想使用浮动)。我已在这里创建了一个plunkr:http://plnkr.co/edit/6WZBnHbwhD7Sjx2ovCO7?p=preview

#container {
  grid-template-columns: 240px 1fr;
  display: grid;
}

.a {
  background: yellow;
}

.b {
  background: blue;
  color: white;
}

#container>.a {
  grid-column: 1;
}

#container>.b {
  grid-column: 2;
}

#container.reverse>.a {
  grid-column: 2;
}

#container.reverse>.b {
  grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
  <div class="a">A</div>
  <div class="b">B</div>
</div>

问题的关键是,当我应用了.reverse类(这样你应该可以看到B | A),B会偏移到新的一行,所以它看起来更像:

          | A
B

如果我对.a.b的文档顺序进行反转,这将恢复正常(但是,当然,如果删除.reverse类,我会遇到同样的问题)。

为什么会这样,并且我该如何解决?

10个回答

87
最简单的方法是在 .reverse 中元素B中添加 order: 1 或者在元素A中添加 order:-1,这是正确的CSS方式,而不是hack-y。

6
这应该放在更高的位置。这是一个简单的修复。 - sayandcode
1
不仅易于修复,而且正确无误。这应该是被接受的答案。 - Paulo Coghi
这就是 order 的作用 https://developer.mozilla.org/zh-CN/docs/Web/CSS/order 。"order CSS 属性设置了 flex 或 grid 容器中的项目布局顺序。容器中的项目按升序值排序,然后按它们在源代码中的顺序排序。" - katiedev

74
作为网格自动布局算法在容器中布置项目,它使用下一个可用的空单元格(source)。
在您的源代码中,A元素出现在B元素之前:
<div id="container" class="reverse" style="width: 800px;">
   <div class="a">A</div>
   <div class="b">B</div>
</div>

因此,网格容器首先放置A,然后使用下一个可用空间来放置B。
默认情况下,自动布局算法在线性方式下遍历网格而不回溯;如果必须跳过一些空白空间来放置较大的项目,则不会返回以填充这些空间。要更改此行为,请在grid-auto-flow中指定dense关键字。

grid-auto-flow: dense

这个问题的一个解决方案(正如您所注意到的)是使用grid-auto-flow: dense来覆盖默认的grid-auto-flow: row

使用grid-auto-flow: dense,Grid自动布局算法将会尝试用适合的项目填充未被占据的单元格。

#container {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-auto-flow: dense; /* NEW */
}
7.7. 自动布局:grid-auto-flow 属性 未明确定位的网格项目会通过自动布局算法自动放置到网格容器中未被占用的空间中。 grid-auto-flow 控制自动布局算法的工作方式,确切地指定了自动放置项目如何流入网格中。 dense 如果指定了此属性,则自动布局算法使用“密集”排列算法,尝试在后续出现较小项目时更早地填充网格中的空洞。这可能导致项目出现错位,但这样做可以填补大型项目留下的空洞。

#container {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-auto-flow: dense; /* NEW */
}

.a {
  background: yellow;
}

.b {
  background: blue;
  color: white;
}

#container>.a {
  grid-column: 1;
}

#container>.b {
  grid-column: 2;
}

#container.reverse>.a {
  grid-column: 2;
}

#container.reverse>.b {
  grid-row: 1;
  grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
  <div class="a">A</div>
  <div class="b">B</div>
</div>


grid-row: 1

另一种解决方案是简单地为第二个项目定义行。

#container>.b {
  grid-column: 2;
  grid-row: 1; /* NEW */
}

#container {
  display: grid;
  grid-template-columns: 240px 1fr;
}

.a {
  background: yellow;
}

.b {
  background: blue;
  color: white;
}

#container>.a {
  grid-column: 1;
}

#container>.b {
  grid-column: 2;
  grid-row: 1; /* NEW */
}

#container.reverse>.a {
  grid-column: 2;
}

#container.reverse>.b {
  grid-row: 1;
  grid-column: 1;
}
<div id="container" class="reverse" style="width: 800px;">
  <div class="a">A</div>
  <div class="b">B</div>
</div>


1
只想指出 dense 会从网格的开头填充空白空间到结尾。因此,如果您在放置的网格项之前有两个空白空间,则会从左到右填充这些空间。 - Seth Feldkamp

23

我不确定如何反转更多的网格项。但是如果您的网格中有2个网格项,您可以使用以下代码来定位第2个网格项。

#container > .b {
    grid-column-start: 1;
    grid-row-start: 1;
}

13

我刚遇到了同样的问题。我尝试使用auto-row-dense,然后将容器父级的方向设置为rtl。这起作用了。

就像在plunker链接上所做的那样,似乎就解决了问题。

.reverse{
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  grid-auto-flow: dense;
  direction: rtl;
}

4
RTL 也会翻转文本和文本对齐,因此它并不是内容的好解决方案。 - Rocky Kev
@RockyKev 点赞这个答案,因为它正是我在寻找的。使用 direction:rtl 来反转主网格容器的 X 轴,并在子元素中添加 direction:ltr 来恢复初始和期望的对齐方式。 - Leo Seyers
2
不幸的是,使用 direction 将会产生意想不到的副作用,并且很可能会破坏任何以 rtl 语言查看页面的用户。 - xec

4
你可以使用direction属性来反转网格的x轴顺序。 嵌套元素也会被反转,因此您需要确保添加其他样式来修复此行为。
<div class="grid">
  <div class="grid-item"><div>
</div>

<style>
.grid { direction : rtl; }
.grid-item { direction : ltr; }
</style>

编辑:这个方法可能有效,但可能会引起无障碍性问题。


3

圆形钉子放在方形洞里

记住,即使您使用了新的高级网格功能,旧的弹性布局仍然有效。您可以将它们组合,嵌套它们,并且有时您必须承认某些问题可能只能通过良好的flex-direction: row-reverse来解决。

但是这里有另一种使用网格的方法。

使用命名模板区域

您可以使用命名模板区域并在定义中反转它们。

#container
{
  grid-template-areas: a b;
  grid-template-rows: 240px 1fr;

  display: grid;
}

#container.reverse
{
  // note the order is flipped for both these properties
  grid-template-areas: b a;
  grid-template-rows: 1fr 240px;
}

.a {
  grid-area: a;
  background: yellow;
}

.b {
  grid-area: b;
  background: blue;
  color: white;
}

这里有一个更复杂的例子,使用媒体查询技术


1
投票支持“圆钉在方孔中”-英语中与EWS相对应的类比是什么?(鸡生毛、羊出奶、猪能飞?) - halfbit
1
我认为这就是“方块插入圆孔”。反过来就没问题了... - AlexJeffcott

1
我发现:我需要在容器上应用 grid-auto-flow: dense;
#container {
  grid-template-columns: 240px 1fr;
  display: grid;
  grid-auto-flow: dense;
}

根据MDN的说明, 该算法试图更早地填补网格中的空洞。

1

我想提到一个解决方案,它在某些情况下也与这个问题相关。当有多行布局时,您希望网格填充的外观是reversed

您可以使用grid-start结合一些:nth-child:last-child选择器来实现反向自动流。

反向grid-auto-flow: column

enter image description here

.container{
  display: grid;
  width: 10rem;
  gap: 0.5rem;
  grid-template-rows: repeat(2, 1fr);
  grid-auto-flow: column; /* => vertical grid*/
}

/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed auto-flow: column */
  grid-row-start: 2;
}

.pixel{
  width: 2rem;
  height: 2rem;
  background: red;
  border: 1px solid black
}
<div class="container">
  <!-- ADD/REMOVE SOME PIXELS to see the result  -->
  <div class="pixel"></div>
  <div class="pixel"></div>
  <div class="pixel"></div>
  <div class="pixel"></div>
  <div class="pixel"></div>
  <div class="pixel"></div>
  <div class="pixel"></div>
</div>

翻转:水平和垂直

enter image description here

.container{
  display: grid;
  width: 10rem;
  gap: 0.5rem;
  grid-template-rows: repeat(2, 1fr);
  grid-auto-flow: column; 
  direction: rtl;  /* reversed horizontal */
}

/* REMOVE THIS TO SEE THE DIFFERENCE */
.pixel:nth-child(odd):last-child { /* reversed vertical */
  grid-row-start: 2;
}

.pixel{
  width: 2rem;
  height: 2rem;
  background: red;
  border: 1px solid black
}
<div class="container">
  <!-- ADD/REMOVE SOME PIXELS to see the result  -->
  <div class="pixel">1</div>
  <div class="pixel">2</div>
  <div class="pixel">3</div>
  <div class="pixel">4</div>
  <div class="pixel">5</div>
  <div class="pixel">6</div>
  <div class="pixel">7</div>
</div>


0

如果您正在使用类似 SCSS 的东西,您可以使用:

#container {
  direction: rtl;
  & > * {
    direction: ltr;
  }
}

请注意,在从右到左的语言环境中,您可能需要添加以下内容:
[dir='rtl'] #container {
  direction: ltr;
  & > * {
    direction: rtl;
  }
}

-4
我发现:我需要在容器上应用grid-auto-flow: dense;

1
这不就是 Michael Benjamin这个被接受的回答Rob这个回答所说的吗? - Scratte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接