Search code examples
htmlcsscss-grid

Switch columns on a row with dynamic data table using css grid?


I'm looking at building a data table using css grids. The idea would be that it is ready to be fully responsive. Take the following example: https://jsfiddle.net/9L46zfp7/

body {
  margin: 0;
}

.container {
  width: 100%;
}

.cssgrid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-auto-flow: dense;
}

.column {
  padding: 10px;
  border-bottom: 1px solid black;
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

.column1 {
  grid-column: 1;
  background-color: wheat;
}

.column2 {
  grid-column: 2;
  background-color: palegreen;
}

.column3 {
  grid-column: 3;
  background-color: lemonchiffon;
}

.column4 {
  grid-column: 4;
  background-color: lightcyan;
}

.column5 {
  grid-column: 5;
  background-color: thistle;
}

@media screen and (max-width: 800px) {
  .cssgrid {
    grid-template-columns: repeat(4, 1fr);
  }
  .column1 {
    grid-column: 1;
    grid-row: span 2;
  }
  .column2 {
    grid-column: 2;
    border: 0;
  }
  .column3 {
    grid-column: 3;
    border: 0;
  }
  .column4 {
    grid-column: 2;
    grid-column: span 2;
  }
  .column5 {
    grid-column: 4;
    grid-row: span 2;
  }
}
<div class="container">
  <div class="cssgrid">
    <!-- row -->
    <div class="column column1">0</div>
    <div class="column column2">1</div>
    <div class="column column3">2</div>
    <div class="column column4">3</div>
    <div class="column column5">4</div>
    <!-- row -->
    <div class="column column1">5</div>
    <div class="column column2">6</div>
    <div class="column column3">7</div>
    <div class="column column4">8</div>
    <div class="column column5">9</div>
  </div>
</div>

Here, you'll see that when the screen is less than 800px wide, the table rows will "split up" into two rows. Now, I'd really like to switch the green with the blue columns.

Is this possible using css only, knowing that the data is dynamically generated (so I cannot reference any specific column number, the html should remain unchanged)?

Thanks in advance!


Solution

  • You can drop the grid-column: n definitions from your code and see that it works without it (grid-auto-flow: dense helps you in achieving the layout without holes in it):

    body {
      margin: 0;
    }
    
    .container {
      width: 100%;
    }
    
    .cssgrid {
      display: grid;
      grid-template-columns: 40px repeat(3, 1fr) 40px;
      grid-auto-flow: dense;
    }
    
    .column {
      padding: 10px;
      border-bottom: 1px solid black;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
    
    .column1 {
      background-color: wheat;
    }
    
    .column2 {
      background-color: palegreen;
    }
    
    .column3 {
      background-color: lemonchiffon;
    }
    
    .column4 {
      background-color: lightcyan;
    }
    
    .column5 {
      background-color: thistle;
    }
    
    @media screen and (max-width: 800px) {
      .cssgrid {
        grid-template-columns: 25px repeat(2, 1fr) 25px;
      }
      .column1 {
        grid-row: span 2;
      }
      .column2 {
        border: 0;
      }
      .column3 {
        border: 0;
      }
      .column4 {
        grid-column: span 2;
      }
      .column5 {
        grid-row: span 2;
      }
    }
    <div class="container">
      <div class="cssgrid">
        <!-- row -->
        <div class="column column1">0</div>
        <div class="column column2">1</div>
        <div class="column column3">2</div>
        <div class="column column4">3</div>
        <div class="column column5">4</div>
        <!-- row -->
        <div class="column column1">5</div>
        <div class="column column2">6</div>
        <div class="column column3">7</div>
        <div class="column column4">8</div>
        <div class="column column5">9</div>
      </div>
    </div>

    Now for generalizing you can use some nth-child logic for this to work for any number of columns - see demo below:

    body {
      margin: 0;
    }
    
    .container {
      width: 100%;
    }
    
    .cssgrid {
      display: grid;
      grid-template-columns: 40px repeat(3, 1fr) 40px;
      grid-auto-flow: dense;
    }
    
    .column {
      padding: 10px;
      border-bottom: 1px solid black;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
    
    @media screen and (max-width: 800px) {
      .cssgrid {
        grid-template-columns: 25px repeat(2, 1fr) 25px;
      }
      .column:nth-child(5n - 4),
      .column:nth-child(5n) {
        grid-row: span 2;
      }
      .column:nth-child(5n - 1) {
        grid-column: span 2;
      }
    }
    
    
    /* presentation styles below */
    
    .column:nth-child(5n - 4) {
      background-color: wheat;
    }
    
    .column:nth-child(5n - 3) {
      background-color: palegreen;
    }
    
    .column:nth-child(5n - 2) {
      background-color: lemonchiffon;
    }
    
    .column:nth-child(5n - 1) {
      background-color: lightcyan;
    }
    
    .column:nth-child(5n) {
      background-color: thistle;
    }
    
    @media screen and (max-width: 800px) {
      .column:nth-child(5n - 3),
      .column:nth-child(5n - 2) {
        border: 0;
      }
    }
    <div class="container">
      <div class="cssgrid">
        <!-- row -->
        <div class="column">0</div>
        <div class="column">1</div>
        <div class="column">2</div>
        <div class="column">3</div>
        <div class="column">4</div>
        <!-- row -->
        <div class="column">5</div>
        <div class="column">6</div>
        <div class="column">7</div>
        <div class="column">8</div>
        <div class="column">9</div>
      </div>
    </div>


    I'd really like to switch the green with the blue columns.

    With the current markup you can't really exchange the rows but you can get the colspans right:

    body {
      margin: 0;
    }
    
    .container {
      width: 100%;
    }
    
    .cssgrid {
      display: grid;
      grid-template-columns: 40px repeat(3, 1fr) 40px;
      grid-auto-flow: dense;
    }
    
    .column {
      padding: 10px;
      border-bottom: 1px solid black;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
    
    @media screen and (max-width: 800px) {
      .cssgrid {
        grid-template-columns: 25px repeat(2, 1fr) 25px;
      }
      .column:nth-child(5n - 4),
      .column:nth-child(5n) {
        grid-row: span 2;
      }
      .column:nth-child(5n - 3) {
        grid-column: span 2;
      }
      .column:nth-child(5n - 2) {
        grid-column: 3;
      }
     
      .column:nth-child(5n - 1) {
        grid-column: 2;
      }
    }
    
    
    /* presentation styles below */
    
    .column:nth-child(5n - 4) {
      background-color: wheat;
    }
    
    .column:nth-child(5n - 3) {
      background-color: palegreen;
    }
    
    .column:nth-child(5n - 2) {
      background-color: lemonchiffon;
    }
    
    .column:nth-child(5n - 1) {
      background-color: lightcyan;
    }
    
    .column:nth-child(5n) {
      background-color: thistle;
    }
    
    @media screen and (max-width: 800px) {
      .column:nth-child(5n - 3){
        border: 0;
      }
    }
    <div class="container">
      <div class="cssgrid">
        <!-- row -->
        <div class="column">0</div>
        <div class="column">1</div>
        <div class="column">2</div>
        <div class="column">3</div>
        <div class="column">4</div>
        <!-- row -->
        <div class="column">5</div>
        <div class="column">6</div>
        <div class="column">7</div>
        <div class="column">8</div>
        <div class="column">9</div>
      </div>
    </div>

    You can't switch the row positions unless you explicitly place into rows (which essentially defeats the purpose I guess but you'll have to do with this) - see demo below:

    body {
      margin: 0;
    }
    
    .container {
      width: 100%;
    }
    
    .cssgrid {
      display: grid;
      grid-template-columns: 40px repeat(3, 1fr) 40px;
      grid-auto-flow: dense;
    }
    
    .column {
      padding: 10px;
      border-bottom: 1px solid black;
      white-space: nowrap;
      text-overflow: ellipsis;
      overflow: hidden;
    }
    
    @media screen and (max-width: 800px) {
      .cssgrid {
        grid-template-columns: 25px repeat(2, 1fr) 25px;
      }
      .column:nth-child(5n - 4),
      .column:nth-child(5n) {
        grid-row: span 2;
      }
      .column:nth-child(5n - 3) {
        grid-column: span 2;
      }
      .column:nth-child(5n - 2) {
        grid-column: 3;
      }
     
      .column:nth-child(5n - 1) {
        grid-column: 2;
      }
      /* explicitly placing in rows for first group */
      .column:nth-child(2) {
        grid-row: 2;
        grid-column: 2 / span 2;
      }
      /* explicitly placing in rows for second group */
      .column:nth-child(7) {
        grid-row: 4;
        grid-column: 2 / span 2;
      }
      /* and so on */
    }
    
    /* presentation styles below */
    
    .column:nth-child(5n - 4) {
      background-color: wheat;
    }
    
    .column:nth-child(5n - 3) {
      background-color: palegreen;
    }
    
    .column:nth-child(5n - 2) {
      background-color: lemonchiffon;
    }
    
    .column:nth-child(5n - 1) {
      background-color: lightcyan;
    }
    
    .column:nth-child(5n) {
      background-color: thistle;
    }
    
    @media screen and (max-width: 800px) {
      .column:nth-child(5n - 2),
      .column:nth-child(5n - 1) {
        border: 0;
      }
    }
    <div class="container">
      <div class="cssgrid">
        <!-- row -->
        <div class="column">0</div>
        <div class="column">1</div>
        <div class="column">2</div>
        <div class="column">3</div>
        <div class="column">4</div>
        <!-- row -->
        <div class="column">5</div>
        <div class="column">6</div>
        <div class="column">7</div>
        <div class="column">8</div>
        <div class="column">9</div>
      </div>
    </div>