Reverse order of columns in CSS Grid Layout

HtmlCssCss Grid

Html Problem Overview


I was hoping to use CSS Grid to reverse the apparent order of two side-by-side divs, where one of the divs grows arbitrarily (I don't want to use floats).

I've created a plunkr here: 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>

The crux of it is that when I have the .reverse class applied (so that you should see B | A), B is offset to a new line so it looks more like:

          | A
B

If I invert the document ordering of .a with .b, this goes back to normal (but of course, if I drop the .reverse class, I get the same problem).

Why is this, and how can I address?

Html Solutions


Solution 1 - Html

As the Grid auto-placement algorithm lays out items in the container, it uses next available empty cells (source).

In your source code the A element comes before the B element:

<div id="container" class="reverse" style="width: 800px;">
   <div class="a">A</div>
   <div class="b">B</div>
</div>

Therefore, the grid container first places A, then uses the next available space to place B.

>By default, the auto-placement algorithm looks linearly through the grid without backtracking; if it has to skip some empty spaces to place a larger item, it will not return to fill those spaces. To change this behavior, specify the dense keyword in grid-auto-flow. > >http://www.w3.org/TR/css3-grid-layout/#common-uses-auto-placement</sup>;


grid-auto-flow: dense

One solution to this problem (as you have noted) is to override the default grid-auto-flow: row with grid-auto-flow: dense.

With grid-auto-flow: dense, the Grid auto-placement algorithm will look to back-fill unoccupied cells with items that fit.

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

> 7.7. Automatic Placement: the grid-auto-flow > property > > Grid items that aren’t explicitly placed are automatically placed into > an unoccupied space in the grid container by the auto-placement > algorithm. > > grid-auto-flow controls how the auto-placement algorithm works, > specifying exactly how auto-placed items get flowed into the grid. > > dense > > If specified, the auto-placement algorithm uses a “dense” packing > algorithm, which attempts to fill in holes earlier in the grid if > smaller items come up later. This may cause items to appear > out-of-order, when doing so would fill in holes left by larger items.

#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

Another solution would be to simply define the row for the second item.

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

Solution 2 - Html

The simplest way is to add order: 1 to element B or order: -1 to element A in .reverse

It's also correct CSS rather than hack-y

Solution 3 - Html

I'm not sure how to reverse more grid items. But if you have 2 grid items in your grid, you can simply position 2nd grid item using below code.

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

Solution 4 - Html

I had this same issue just now. I tried auto-row-dense and then set the direction of the container parent to rtl. It worked.

Just this, on the plunker link, seemed to do the trick.

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

Solution 5 - Html

You can use direction property to reverse a grid x-axis order. Nested elements will be reversed too so you have to make sure to add additional styles to fix this behavior.

<div class="grid">
  <div class="grid-item"><div>
</div>

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

Solution 6 - Html

I found out: I need to apply grid-auto-flow: dense; on the container:

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

According to MDN, this algorithm attempts to fill in holes earlier in the grid.

Solution 7 - Html

Round peg in square hole

Remember even if you're using fancy 'new' grid features the older flex layout will still work. You can combine them, nest them and sometime you have to admit that certain problems like this may just be better solved with good old flex-direction: row-reverse

But I know some people will want to downvote me for that so here's another way with grid.

Use named template regions

You can use named template regions and reverse them in the definition.

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

Here's an more complex example that uses that technique with media queries

Solution 8 - Html

I want to mention a solution which is also relevant to this question in some cases. When having a multi-row layout, and you want a reversed look of how you grid fills up.

You can play with grid-start combined with some :nth-child & :last-child selectors to achieve a reverse auto flow.

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

Reversed: horizontal & vertical

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>

Solution 9 - Html

I found out: I need to apply grid-auto-flow: dense; on the container:

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRobView Question on Stackoverflow
Solution 1 - HtmlMichael BenjaminView Answer on Stackoverflow
Solution 2 - HtmlChris PinkView Answer on Stackoverflow
Solution 3 - HtmlAngrej KumarView Answer on Stackoverflow
Solution 4 - HtmlkarenefereyanView Answer on Stackoverflow
Solution 5 - HtmlLeo SeyersView Answer on Stackoverflow
Solution 6 - HtmlRobView Answer on Stackoverflow
Solution 7 - HtmlSimon_WeaverView Answer on Stackoverflow
Solution 8 - HtmlLuhnView Answer on Stackoverflow
Solution 9 - HtmlShlomo FarberView Answer on Stackoverflow