Search code examples
htmlcssmultiple-columnscss-grid

Can I stack a right-hand set of columns with CSS Grid instead of Flex?


I have a pretty simple "label + value" layout with left and right sections of label + value pairs:

Left Label 1 | Left Value 1 | Right Label 1 | Right Value 1
Left Label 2 | Left Value 2 | Right Label 2 | Right Value 2
Left Label 3 | Left Value 3

When stacked the right-hand side should be the last set of rows:

Left Label 1   | Left Value 1
Left Label 2   | Left Value 2
Left Label 3   | Left Value 3
Right Label 1  | Right Value 1
Right Label 2  | Right Value 2                          

I can do this "good enough" in flex, with the right hand side of columns grouped in a flex item that is stacked in smaller views.

CSS Grid seems to handle label + value pairs a little better than flex, though, so I was hoping to use it instead.

With CSS Grid I can get the single column presentation easily, as the order is just natural / what is in the DOM. When I switch to the 4 column view (left and right-hand pairs of label + value), though, the order is wrong (as expected) as it flows left to right, top to bottom:

Left Label 1  | Left Value 1  | Left Label 2  | Left Value 2
Left Label 3  | Left Value 3  | Right Label 1 | Right Value 1
Right Label 2 | Right Value 2

Example

.responsiveGrid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px;
}


/* two pairs in rows for larger view */

@media (min-width: 500px) {
  .responsiveGrid {
    grid-template-columns: [left] auto 1fr [right] auto 1fr;
  }
}

.label {
  background-color: yellow;
}

.value {
  background-color: orange;
}
<div class="responsiveGrid">
  <span class="label left">Left Label 1</span>
  <span class="value left">Left Value 1</span>

  <span class="label left">Left Label 2</span>
  <span class="value left">
    Left Value 2
    A really long value to see some wrapping.
    A really long value to see some wrapping.
    A really long value to see some wrapping.
    A really long value to see some wrapping.
  </span>

  <span class="label left">Left Label 3 Which is Longer</span>
  <span class="value left">Left Value 3</span>

  <!-- TODO: These items should be on a right-hand side in the two-pairs view -->
  <span class="label right">Right Label 1</span>
  <span class="value right">Right Value 1</span>

  <span class="label right">Right Label 2</span>
  <span class="value right">Right Value 2</span>
</div>

What I've tried:

  1. Putting the left and right parts of the grid inside of flex items, but that doesn't seem to work well because then the rows don't stay aligned, as they are two separate grids at that point.
  2. "Left" and "Right" grid areas to assign grid items. This doesn't work because rows just overlap each other in those single grid areas, and since the number of rows is unknown, I can't necessarily define a number of "hard coded" rows in a grid template.

Is there any straightforward way I can get these "sections"/"groups" of columns to stick together on the right-hand side when I switch to 4 columns?


Solution

  • All you need is to play with the column position of each element. Also note the use of grid-auto-columns and not grid-template-columns.

    .responsiveGrid {
      display: grid;
      grid-auto-columns: auto 1fr;
      grid-auto-flow: dense;
      gap: 4px;
    }
    
    .label {
      background-color: yellow;
      grid-column: 1;
    }
    
    .value {
      background-color: orange;
      grid-column: 2;
    }
    
    @media (min-width: 500px) {
      .label.right {
        grid-column: 3;
      }
      .value.right {
        grid-column: 4;
      }
    }
    <div class="responsiveGrid">
      <span class="label left">Left Label 1</span>
      <span class="value left">Left Value 1</span>
    
      <span class="label left">Left Label 2</span>
      <span class="value left">
        Left Value 2
        A really long value to see some wrapping.
        A really long value to see some wrapping.
        A really long value to see some wrapping.
        A really long value to see some wrapping.
      </span>
    
      <span class="label left">Left Label 3 Which is Longer</span>
      <span class="value left">Left Value 3</span>
    
      <!-- TODO: These items should be on a right-hand side in the two-pairs view -->
      <span class="label right">Right Label 1</span>
      <span class="value right">Right Value 1</span>
    
      <span class="label right">Right Label 2</span>
      <span class="value right">Right Value 2</span>
    </div>