skip to Main Content

I’m attempting to create a simple grid and have trouble figuring one thing out.

Namely having a few items next to each other how can I merge multiple items into one so they all look "even"?

Here’s how my columns look like right now:

enter image description here

And that’s what I want to achieve:

enter image description here

I want it to be quite universal and work on different resolutions etc. so I’m not sure if flex-grow will be the best bet here, but seems like in the first row flex-grow: 160 helps and in the last one – flex-grow: 2 also works. But is it the way to go? What if I want ab + bcd + e? I’ll have to calculate flex-grows for every single scenario? Can’t I somehow tell flex to use "basis of X items"?

JSFiddle & SO snippet below.

* {
  box-sizing: border-box;
}

.row {
  display: flex;
  flex-wrap: wrap;
  max-width: 460px;
  outline: solid 1px #000;
}

.cell {
  display: flex;
  margin: 10px;
  padding: 10px;
  background: #eee;
  flex: 1 0 70px;
  max-width: 100%;
}
<div class="row">
  <div class="cell">auto with adjust</div>
  <div class="cell">auto with adjust</div>
</div>
<div class="row">
  <div class="cell">a</div>
  <div class="cell">b</div>
  <div class="cell">c</div>
  <div class="cell">d</div>
  <div class="cell">e</div>
  <div class="cell">auto new line + auto full width</div>
</div>
<div class="row">
  <div class="cell" style="outline: solid 1px red;">a+b+c+d</div>
  <div class="cell">e</div>
</div>
<div class="row">
  <div class="cell">a+b</div>
  <div class="cell" style="outline: solid 1px red;">c+d+e</div>
</div>

3

Answers


  1. It would be much easier to use Grid instead.

    * {
      box-sizing: border-box;
    }
    
    .cell {
      background-color: pink;
      border: 1px solid #000;
      text-align: center;
    }
    
    .row {
      background-color: #ccc;
      padding: 10px;
      margin-bottom: 5px;
      display: grid; 
      gap: 1rem; 
      grid-template-columns: repeat(5, 1fr); 
    }
    
    .row-1 .cell:nth-child(1) {
      grid-area: cell-11;
    }
    .row-1 .cell:nth-child(2) {
      grid-area: cell-12;
    }
    
    .row-2 .cell:nth-child(1) {
      grid-area: cell-21;
    }
    .row-2 .cell:nth-child(2) {
      grid-area: cell-22;
    }
    
    .row-3 .cell:nth-child(1) {
      grid-area: cell-31;
    }
    .row-3 .cell:nth-child(2) {
      grid-area: cell-32;
    }
    .row-3 .cell:nth-child(3) {
      grid-area: cell-33;
    }
    
    .row-1 {
      grid-template-areas:
      "cell-11 cell-11 cell-11 cell-11 cell-12";  
    }
    .row-2 {
      grid-template-areas:
      "cell-21 cell-21 cell-22 cell-22 cell-22";  
    }
    .row-3 {
      grid-template-areas:
      "cell-31 cell-32 cell-32 cell-32 cell-33";  
    }
      <div class="row row-1">
        <div class="cell" style="outline: solid 1px red;">a+b+c+d</div>
        <div class="cell">e</div>
      </div>
      <div class="row row-2">
        <div class="cell">a+b</div>
        <div class="cell" style="outline: solid 1px red;">c+d+e</div>
      </div>
      <div class="row row-3">
        <div class="cell">a</div>
        <div class="cell" style="outline: solid 1px red;">b+c+d</div>
        <div class="cell" style="outline: solid 1px red;">e</div>
      </div>
    Login or Signup to reply.
  2. I found a way to achieve exactly what you want, using Flexbox. It works exactly like Grid and it is fully responsive. I haven’t tested on real content yet, but I’m confident it will work.

    I created a few variables:

    • --nbr : number of columns (5 in this case)
    • --gap : the row-gap of the flex grid
    • --col : the width of a single column in the flex grid.
      If the grid has 5 columns, then each columns should have a width of 100% / 5 = 20%.
      Unfortunately, when gap is added, it decreases the width.
      A grid with 5 columns has 4 gaps.
      So the real width of a column is (100% - (4 * gap)) / 5.
    • --span : the value of flex based on the number of columns merged together.
      For the record, flex is the shorthand for flex-grow, flex-shrink and flex-basis.
      flex: flex-grow flex-shrink flex-basis
      flex-grow is set to 0 (flex items are not allowed to grow).
      flex-shrink is set to 1 (all flex items are allowed to shrink at the same rate).
      If 3 columns are merged, the final width is (3 * col) + (2 * gap). Which is the value of flex-basis.
      --span-1 means the flex-item is merging 1 column, --span-3 means the flex-item is merging 3 columns, …
      If your flex grid has 12 columns, you should add variables up to --span-12.

    Now you can just assign the --span value to every item’s flex property.

    I hope all of this makes sense.

    * {
      box-sizing: border-box;
    }
    
    :root {
      --nbr: 5;
      --gap : 5px;
      --col: calc((100% - (var(--nbr) - 1) * var(--gap)) / var(--nbr));
      --span-1: 0 1 var(--col);
      --span-2: 0 1 calc(2 * var(--col) + 1 * var(--gap));
      --span-3: 0 1 calc(3 * var(--col) + 2 * var(--gap));
      --span-4: 0 1 calc(4 * var(--col) + 3 * var(--gap));
      --span-5: 0 1 calc(5 * var(--col) + 4 * var(--gap));
    }
    
    .row {
      display: flex;
      flex-wrap: nowrap;
      gap: var(--gap);
      max-width: 460px;
      outline: solid 1px #000;
      text-align: center;
      margin-bottom: 5px;
      background-color: pink;
    }
    
    .cell {
      flex: var(--span-1);
      padding: 10px;
      background: #eee;
      border: 1px solid;
    }
    
    .row-1 .cell:nth-child(1) {
      flex: var(--span-4);
    }
    .row-1 .cell:nth-child(2) {
      flex: var(--span-1);
    }
    
    .row-2 .cell:nth-child(1) {
      flex: var(--span-2);
    }
    .row-2 .cell:nth-child(2) {
      flex: var(--span-3);
    }
    
    .row-3 .cell:nth-child(1) {
      flex: var(--span-1);
    }
    .row-3 .cell:nth-child(2) {
      flex: var(--span-3);  
    }
    .row-3 .cell:nth-child(3) {
      flex: var(--span-1);
    }
      <div class="row">
        <div class="cell">a</div>
        <div class="cell">b</div>
        <div class="cell">c</div>
        <div class="cell">d</div>
        <div class="cell">e</div>
      </div>
      <div class="row row-1">
        <div class="cell" style="outline: solid 1px red;">a+b+c+d</div>
        <div class="cell">e</div>
      </div>
      <div class="row row-2">
        <div class="cell">a+b</div>
        <div class="cell" style="outline: solid 1px red;">c+d+e</div>
      </div>
      <div class="row row-3">
        <div class="cell">a</div>
        <div class="cell" style="outline: solid 1px red;">b+c+d</div>
        <div class="cell" style="outline: solid 1px red;">e</div>
      </div>
    Login or Signup to reply.
  3. Just target each specific .row and .cell in your CSS and use flex-grow.

    The flex-grow CSS property sets the flex grow factor of a flex item’s main size.

    See <number> for valid values. Negative values are invalid. Defaults is 0.

    * {
      box-sizing: border-box;
    }
    
    .row {
      display: flex;
      flex-wrap: wrap;
      max-width: 460px;
      outline: solid 1px #000;
    }
    
    .cell {
      display: flex;
      flex-grow: 1;
      margin: 10px;
      padding: 10px;
      background: #eee;
      max-width: 100%;
    }
    
    .row:nth-child(3)>.cell:last-child {
      flex-grow: .2;
    }
    
    .row:nth-child(4)>.cell:last-child {
      flex-grow: 2;
    }
    <div class="row">
      <div class="cell">auto with adjust</div>
      <div class="cell">auto with adjust</div>
    </div>
    <div class="row">
      <div class="cell">a</div>
      <div class="cell">b</div>
      <div class="cell">c</div>
      <div class="cell">d</div>
      <div class="cell">e</div>
      <div class="cell">auto new line + auto full width</div>
    </div>
    <div class="row">
      <div class="cell" style="outline: solid 1px red;">a+b+c+d</div>
      <div class="cell">e</div>
    </div>
    <div class="row">
      <div class="cell">a+b</div>
      <div class="cell" style="outline: solid 1px red;">c+d+e</div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search