Search code examples
htmlcssflexboxcss-grid

Ordering items in vertical columns with CSS grid or Flexbox?


Is there a CSS-only way of ordering items in columns for grid layout without using pixel values? Flexbox would work as well. I need the same HTML to enable the following two scenarios (with numbers of columns between 1 and 5 in the dynamically-generated HTML):

Case A:

| item 1          | item 2          | item 3          |
| item 4          | item 5          | item 6          |
| item 7          | item 8          | item 9          |

Case B:

| item 1          | item 4          | item 7          |
| item 2          | item 5          | item 8          |
| item 3          | item 6          | item 9          |

Case A is easy, just need to do something like:

.case-a[data-column-count='3'] {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}

<div data-column-count="3" class="case-b">
     <label>item 1</label>
     <label>item 2</label>
     <label>item 3</label>
</div>

The closest I came to it is this Codepen, though vertical alignment is messy on each individual column: https://codepen.io/anon/pen/zbGWRa

body {
  font-family: sans-serif;
}

.columns {
  column-width: 18vw;
}
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: 2em;
  grid-gap: .5em;
  align-items: center;
  background: #eee;
  padding: .5em;
  box-decoration-break: clone;
  counter-reset: nb;
  border: 2px solid red;
}
input {
  align-self: stretch;
  border-radius: 2px;
  border: 1px solid #ccc;
}
label::before {
  counter-increment: nb;
  content: counter(nb) ". ";
}
<div class="columns">
  <div class="grid">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
    <label>label</label>
    <input type="text">
  </div>
</div>

Another Codepen - I can also indirectly control the number of columns by specifying the number of items per column, but I want to just specify a number of columns: https://codepen.io/anon/pen/BbNqGE

.container {
  display: grid;
  grid-template-columns: 1fr;
}

.container {
  grid-template-rows: 1fr 1fr 1fr 1fr 1fr;
  grid-auto-columns: 1fr;
  grid-auto-flow: column;
}

* {
  box-sizing: border-box;
}

body {
  font-size: 1.35em;
  font-family: 'Varela Round', sans-serif;
  color: #fff;
  background: #e8e9e9;
  padding-left: 5%;
  padding-right: 5%;
}

.container {
  padding: 10px;
  background: #fff;
  border-radius: 5px;
  margin: 45px auto;
}

.item {
  color: #fff;
  padding: 15px;
  margin: 5px;
  background: #3db5da;
}
<div class="container">
  <div class="item-1 item">Item 1</div>
  <div class="item-2 item">Item 2</div>
  <div class="item-3 item">Item 3</div>
  <div class="item-4 item">Item 4</div>
  <div class="item-5 item">Item 5</div>
  <div class="item-5 item">Item 6</div>
  <div class="item-5 item">Item 7</div>
</div>


Solution

  • You can do this with CSS' grid-template-area.

    The code will look like this. Where grid-template-areas represents the placement. And in each id of the element will define the named area. grid-area: a;. The id selector of each element does not need to match the grid-are name as in my example.

    *{
      box-sizing: border-box;
    }
    .wrapper {
      color:white;
      font-size: 2em;
      
      display:grid;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: 100px 100px 100px;
        
      grid-template-areas: 
                           "a d g"
                           "b e h"
                           "c f i";
    
    }
    #a{
      background-color:rgb(180,247,182);
      grid-area: a;
    }
    #b{
      background-color:rgb(250,235,122);
      grid-area:b;
    }
    #c{
      background-color:rgb(167,255,250);
      grid-area:c;
    
    }
    #d{
      background-color:rgb(227,176,252);
        grid-area:d;
    
    }
    #e{
      background-color:rgb(157,255,205);
      grid-area:e;
    
    }
    #f{
      background-color:rgb(243,152,98);
        grid-area:f;
    
    }
    #g{
      background-color:rgb(55,32,199);
        grid-area:g;
    
    }
    #h{
      background-color:rgb(120,152,98);
        grid-area:h;
    
    }
    #i{
      background-color:rgb(243,100,98);
        grid-area:i;
    
    }
    
    .wrapper > div {
      display: flex;
      align-items: center;
      justify-content: center;
    }
    <div class="wrapper">
      <div id="a">1</div>
      <div id="b">2</div>
      <div id="c">3</div>
      <div id="d">4</div>
      <div id="e">5</div>
      <div id="f">6</div>
      <div id="g">7</div>
      <div id="h">8</div>
      <div id="i">9</div>
    
    </div>