110

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?

12 Answers 12

129

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

Sign up to request clarification or add additional context in comments.

3 Comments

This should be higher up. Its an easy fix
Not only an easy fix, but a correct one. This should be the accepted answer.
This is what order is for developer.mozilla.org/en-US/docs/Web/CSS/order "The order CSS property sets the order to lay out an item in a flex or grid container. Items in a container are sorted by ascending order value and then by their source code order."
78

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


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>

1 Comment

Just wanted to note that dense fills empty spaces from the start of the grid to the end. So if you have two empty spaces preceding your placed grid item, you will fill those left to right.
26

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

Comments

16

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

4 Comments

rtl will also flip text and text-align as well, so it's not a really good solution for content.
@RockyKev Upvoting this answer cause it's exactly what I was looking for. Use direction:rtl for the main grid container to reverse the X axis and add direction: ltr in sub elements to revert to initial and desired alignement
unfortunately, using direction will have unintended side effects and most likely break for any users viewing the page in a rtl language
While not correct semantics, this solution is the only one that works with an undefined number of items in the grid. One addition you need to do, is add .reverse > * {direction: ltr} to revert the correct direction for your content. To accound for rtl languages, you can add the newly available :dir() pseudo-class: .reverse:dir(rtl) {direction: ltr}.
7

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

2 Comments

vote for the "Round peg in square hole" - what's the English parallel to EWS? (egg giving wool milk pig?)
I think it is “square peg in a round hole”. The other way around works just fine…
5

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>

Edit: this may work but could cause accessibilty issues.

Comments

2

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>

Comments

1

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.

Comments

-1

If you are using something like SCSS, you can use:

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

Note that in rtl locales, you will probably want to add:

[dir='rtl'] #container {
  direction: ltr;
  & > * {
    direction: rtl;
  }
}

2 Comments

This is a hacky "solution" and an inappropriate hijacking of the language direction property. It's semantically incorrect and may lead to unexpected consequences since it's not the intended use.
That's the only method that worked for me when combining it with grid-template-columns: repeat(auto-fit, ...) for responsiveness. I wanted the items to flip horizontally, not vertically.
-1

I ended up using a transform to mirror the columns and then applying the same transform to the grid content to mirror the content back...

transform: scale(-1, 1);

Codepen here: https://codepen.io/RobLessard/pen/XWLzQgx

Comments

-2

Similar to the direction: rtl;-method, another awful way to achieve reverse grid flow is to use transform: rotate(180deg). This also places tiles from the bottom up.

.reverse,
.reverse > * {
  transform: rotate(180deg);
}

.container {
  display: grid;
  width: 10em;
  height: 10em;
  gap: 0.5em;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
}

.container > div {
  background: red;
  border: 1px solid black
}

.reverse,
.reverse > * {
  transform: rotate(180deg);
}
<div class="container reverse">
  <div>1</div>
  <div>2</div>
  <div>3</div>
  <div>4</div>
  <div>5</div>
  <div>6</div>
  <div>7</div>
</div>

Comments

-5

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

1 Comment

Isn't that what this accepted Answer by Michael Benjamin and this Answer by Rob is also saying?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.