CSS grid: different alignment for every second row

Viewed 552

Is it possible to align every second row right and every other left with CSS Grid? The number of .item is unknown.

Here is the HTML/CSS:

.container {
  grid-template-columns: repeat(4, 1fr);
}
<ul class="container">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <!-- ... -->
</ul>

Expected solution: enter image description here

I am open to other solutions than CSS Grid also.

3 Answers

You can use nth-child() to create a repeating pattern.

ul {
  display: grid;
  grid-template-columns: repeat(6, 1fr);/* 6 = 4 + 2 empty cells */
  grid-auto-rows: 50px;/*demo purpose */
}

li {
  display: block;
  border: solid 1px;
}

li:nth-child(8n-3) {
  grid-column: 3;
}

li:nth-child(8n + 1) {
  grid-column: 1
}

/*demo purpose */
ul{counter-reset:lis;}
li:before {counter-increment:lis;content:counter(lis);}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

A flexbox idea:

.container {
  display:flex;
  padding:0;
  margin:0;
  flex-wrap:wrap;
  border:1px solid red;
  --w:300px; /* the width of 4 items */
}

.container > * {
  flex-grow:1;
  flex-basis:calc(var(--w)/4);
  border:1px solid;
  box-sizing:border-box;
  list-style:none;
}

.container > *:nth-child(8n + 4) {
  margin-right:calc(100% - var(--w)); 
}
.container > *:nth-child(8n + 5) {
  margin-left:calc(100% - var(--w));
}

/* Irrelevant style to maintain the square ratio */
.container > *::before {
  content:"";
  display:inline-block;
  padding-top:100%;
}
<ul class="container">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

<ul class="container" style="--w:200px">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

<ul class="container" style="--w:60%">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

You can also use the old float method:

.container {
  padding:0;
  margin:0;
  border:1px solid red;
  overflow:auto;
  --w:300px; /* the width of 4 items */
}

.container > * {
  float:left;
  width:calc(var(--w)/4);
  border:1px solid;
  box-sizing:border-box;
  list-style:none;
}

.container > *:nth-child(8n + 5),
.container > *:nth-child(8n + 6),
.container > *:nth-child(8n + 7),
.container > *:nth-child(8n + 8){
  float:right;
}

.container > *:nth-child(8n + 5) {
  clear:left;
}
.container > *:nth-child(8n + 1) {
  clear:right;
}

/**/
.container > *::before {
  content:"";
  display:inline-block;
  padding-top:100%;
}
/**/
<ul class="container">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

<ul class="container" style="--w:200px">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

<ul class="container" style="--w:60%">
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
  <li class="item"></li>
</ul>

Possible with grid-column-start and grid-column-end property.

.container {
  display: inline-grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: auto;
  margin: 0;
  padding: 0;
}

.item {
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100px;
  height: 100px;
  border: 1px solid red;
}

.item:nth-child(4) {
  grid-column-end: span 3;
}

.item:nth-child(8n + 5) {
  grid-column-start: 3;
}
<ul class="container">
  <li class="item">1</li>
  <li class="item">2</li>
  <li class="item">3</li>
  <li class="item">4</li>
  <li class="item">5</li>
  <li class="item">6</li>
  <li class="item">7</li>
  <li class="item">8</li>
  <li class="item">9</li>
  <li class="item">10</li>
  <li class="item">11</li>
  <li class="item">12</li>
  <li class="item">13</li>
  <li class="item">14</li>
  <li class="item">15</li>
  <li class="item">16</li>
</ul>

Related