Home > Software engineering >  CSS Grid, specifying layout order
CSS Grid, specifying layout order

Time:06-16

So I have a grid for a section of a page as you can see below. Basically, the way its laid out is as follows:

[1] [ Item 1 ] [2] [ Item 2 ]  
[3] [ Item 3 ] [4] [ Item 4 ]

And once the screen narrows to mobile via media queries it changes to this:

[1] [ Item 1 ]  
[2] [ Item 2 ]  
[3] [ Item 3 ]  
[4] [ Item 4 ]

Which is perfect, that's what I need. My issue is that in the first example, I need it to go like this:

[1] [ Item 1 ] [3] [ Item 3 ]  
[2] [ Item 2 ] [4] [ Item 4 ]

Now in my actual code, there are a lot more grid-items so basically I would like it to lay out the first column and then the second instead of filling row by row. I could physically change the order of the grid items in the HTML but then on mobile screens the order is messed up. I took a look at grid-auto-flow and I could not figure out if that's what I needed. The solution is probably so simple but I think I am so close to this project it's hard to take a step back and figure it out. Any help is greatly appreciated!

.grid {
  display: grid;
  grid-template-columns: 48px 1fr 48px 1fr;
  column-gap: 12px;
  align-items: center;
  justify-content: center;
  background-color: orange;
  border: 1px solid black;
}

.grid-item {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
}
<section >
  <div >1</div>
  <div >Item 1</div>
  <div >2</div>
  <div >Item 2</div>
  <div >3</div>
  <div >Item 3</div>
  <div >4</div>
  <div >Item 4</div>
</section>

CodePudding user response:

I have changed your layout to achieve what you want. Like you say, there is a lot of solutions and here you have mine! Hope it helps.

In summary, I have used display flex instead of grid dividing the layout in two columns (mobile first strategy) that will be printed one below the other in mobile screens and then change to one beside the other via media query.

Here is my code:

.flex {
  background-color: orange;
  border: 1px solid black;
}
.grid-item {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
}
.row {
  display: flex;
  justify-content: start;
  align-items: center;
}
.row div {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
  text-align: center;
}
.row .counter {
  max-width: 48px;
}
.row .item {
  flex: 1;
}

@media(min-width: 768px) {
  .flex {
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .column {
    flex: 1;
  }
}
<section >
  <div >
    <div >
      <div >1</div>
      <div >Item 1</div>
    </div>
    <div >
      <div >2</div>
      <div >Item 2</div>
    </div>
  </div>
  <div >
    <div >
      <div >3</div>
      <div >Item 3</div>
    </div>
    <div >
      <div >4</div>
      <div >Item 4</div>
    </div>
  </div>
</section>

CodePudding user response:

to change the order, you may use order ;)

using the nth-child(n) selector and from your HTML , it could be :

.grid {
  display: grid;
  grid-template-columns: 48px 1fr 48px 1fr;
  column-gap: 12px;
  align-items: center;
  justify-content: center;
  background-color: orange;
  border: 1px solid black;
}

.grid-item {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
}

.grid-item:nth-child(4n) ,/* catch 4, 8, ..*/
.grid-item:nth-child(4n - 1)/*, catch 3,7,...)*/
 {
  order: 1;
  color:green;
  font-weight:bold;
}
<section >
  <div >1</div>
  <div >Item 1</div>
  <div >2</div>
  <div >Item 2</div>
  <div >3</div>
  <div >Item 3</div>
  <div >4</div>
  <div >Item 4</div>
</section>

ressources

For an unknown number of item (& if you have a maximum possible known ) , you could prepare a few rules using the :nth-last-child():first-child selector to test numbers of item to place x item into different column.

Example with 8 items (16)

.grid {
  display: grid;
  grid-template-columns: 48px 1fr 48px 1fr;
  column-gap: 12px;
  align-items: center;
  justify-content: center;
  background-color: orange;
  border: 1px solid black;
  grid-auto-flow:row dense;
}

.grid-item {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
}

/* start filling 2 columns of the grid */
.grid-item:nth-child(odd)  {
  grid-column:1;
}
.grid-item:nth-child(even)  {
  grid-column:2;
}

/* if 8 items (16) , send odds and evens them to their next respective columns */
.grid-item:nth-last-child(16):first-child~:nth-child(8) ~ .grid-item:nth-child(odd)  {
  grid-column:3;
}
.grid-item:nth-last-child(16):first-child~:nth-child(8) ~ .grid-item:nth-child(even)  {
  grid-column:4;
}
<section >
  <div >1</div>
  <div >Item 1</div>
  <div >2</div>
  <div >Item 2</div>
  <div >3</div>
  <div >Item 3</div>
  <div >4</div>
  <div >Item 4</div>  
  <div >5</div>
  <div >Item 5</div>
  <div >6</div>
  <div >Item 6</div>
  <div >7</div>
  <div >Item 7</div>
  <div >8</div>
  <div >Item 8</div>
</section>

From that last snippet, you can repeat the rules updating .grid-item:nth-last-child(XX):first-child~:nth-child(X) with the testing amount of child item it has


Javascript can also easily help to set elements into a specific column.

let item = document.querySelectorAll(".grid-item");

i = 0;

for (let e of document.querySelectorAll(".grid-item")) {
  i  ;
  if (i > item.length / 2   1) {
    let pos = i;

    let odd = pos % 2;
    if (odd == 1) {
      e.classList.toggle("col3");
    } else {
      e.classList.toggle("col4");
    }
  }
}
.grid {
  display: grid;
  grid-template-columns: 48px 1fr 48px 1fr;
  column-gap: 12px;
  align-items: center;
  justify-content: center;
  background-color: orange;
  border: 1px solid black;
  grid-auto-flow: row dense;
}

.grid-item {
  padding: 16px;
  border: 1px solid black;
  font-size: 12px;
  background-color: aliceblue;
}

.grid-item:nth-child(odd) {
  grid-column: 1;
}

.grid-item:nth-child(even) {
  grid-column: 2;
}


/* class will beassigned via javascript */

.grid-item.col3 {
  grid-column: 3;
}

.grid-item.col4 {
  grid-column: 4;
}
<section >
  <div >1</div>
  <div >Item 1</div>
  <div >2</div>
  <div >Item 2</div>
  <div >3</div>
  <div >Item 3</div>
  <div >4</div>
  <div >Item 4</div>
  <div >5</div>
  <div >Item 5</div>
  <div >6</div>
  <div >Item 6</div>
  <div >7</div>
  <div >Item 7</div>
  <div >8</div>
  <div >Item 8</div>
  <div >9</div>
  <div >Item 9</div>
</section>

CodePudding user response:

I think you shoud change the display value to block

  • Related