Search code examples
htmlcssflexboxcss-grid

How to make Flex Grid width relative to the biggest child's width?


I have something like this :

.wrapper {
  display: flex;
  width: 300px;
}

.content {
  flex: auto;
}

.row {
  display: flex;
  flex-flow: row wrap;
}

.col {
  width: 25%;
  padding: 5px;
  border: 1px solid black;
  box-sizing: border-box;
}
<div class='wrapper'>
  <div class='content'>Content</div>
  <div class='row'>
    <div class='col'>aa</div>
    <div class='col'>aaaa</div>
    <div class='col'>aaaaaa</div>
    <div class='col'>aaaaaaaa</div>
  </div>
</div>

I can't understand how :

  • The width of the .row element is calculated
  • The width of the .col elements are calculated
  • Why some content overflows the box and some don't

What I want is a grid system that gets its size relative to the largest child, so that each content fits in its .col cell.

I saw that I could do that with display: grid and grid-template-columns: 1fr 1fr 1fr 1fr, but then how do you make it responsive and how well is it supported ?


Solution

  • To answer your 3 first questions, you simly need to remove the width:25% to have the following:

    .wrapper {
      display: flex;
      width: 300px;
    }
    
    .content {
      flex: auto;
    }
    
    .row {
      display: flex;
      flex-flow: row wrap;
    }
    
    .col {
      padding: 5px;
      border: 1px solid black;
      box-sizing: border-box;
    }
    <div class='wrapper'>
      <div class='content'>Content</div>
      <div class='row'>
        <div class='col'>aa</div>
        <div class='col'>aaaa</div>
        <div class='col'>aaaaaa</div>
        <div class='col'>aaaaaaaa</div>
      </div>
    </div>

    We didn't define any width, so each col will fit its content and the row will have the width equal to the sum of all the col.

    Now since we have the width of the row defined based on the content, it won't change and it will get used as a reference for the percentage. Using 25% for the col means that each one will get 25% of the previously defined width and we will logically have some overflow since the content inside each col isn't the same.

    .wrapper {
      display: flex;
      width: 300px;
    }
    
    .content {
      flex: auto;
    }
    
    .row {
      display: flex;
      flex-flow: row wrap;
    }
    
    .col {
      padding: 5px;
      border: 1px solid black;
      box-sizing: border-box;
    }
    .width .col {
      width:25%;
    }
    <div class='wrapper'>
      <div class='content'>before width</div>
      <div class='row'>
        <div class='col'>aa</div>
        <div class='col'>aaaa</div>
        <div class='col'>aaaaaa</div>
        <div class='col'>aaaaaaaa</div>
      </div>
    </div>
    <div class='wrapper'>
      <div class='content'>after width</div>
      <div class='row width'>
        <div class='col'>aa</div>
        <div class='col'>aaaa</div>
        <div class='col'>aaaaaa</div>
        <div class='col'>aaaaaaaa</div>
      </div>
    </div>


    To obtain what you want, I think the 1fr of CSS grid is the way to go (like you already noticed). Actually CSS grid is well supported. You will simply have issues with IE and you can follow this link to see the known bugs: https://caniuse.com/#feat=css-grid


    In order to make it responsive you may consider media query to switch to a column layout on small screens:

    .wrapper {
      display: flex;
      width: 300px;
    }
    .row {
      display: grid;
      grid-auto-columns:1fr;
      grid-auto-flow:column;
    }
    
    .col {
      padding: 5px;
      border: 1px solid black;
      box-sizing: border-box;
    }
    
    @media all and (max-width:500px) {
    .row {
      grid-auto-flow:row;
    }
    }
    <div class='wrapper'>
      <div class='content'>Content</div>
      <div class='row'>
        <div class='col'>aa</div>
        <div class='col'>aaaa</div>
        <div class='col'>aaaaaa</div>
        <div class='col'>aaaaaaaa</div>
      </div>
    </div>