Search code examples
cssflexboxcss-gridgrid-layoutstyled-components

How to set up a dynamic grid based on flex or grid


I want to create a dynamic grid system that should behave like this: first when there is only 1 item it should have a width and height of 100%.

When the second child has been dynamically added to the grid it should have a height of 100% and the 2 items both 50% width.

When the THIRD item has been added the first 2 items should have a height 0f 50% and a width of 50%, the third item should have a height of 50% and a width of 100%.

Fourth item should then again have a width of 50% and height 50%.

Example

fifth item again 100% width and all the items should have 33,33% height. No matter how many items are added the grid should always behave the same way.

Currently i have:

const StyledVideoContainer = styled.div`
  ${({ number }) => `
    display: grid;
    grid-template-columns: repeat(${number}, 1fr);
    grid-template-rows: repeat(auto-fill, 100%);

    .videoContent {
      flex-grow: 1;
    }
  `}
`;

Solution

  • You can do it with flexbox like below:

    .container {
      border: 1px solid;
      display: inline-flex;
      flex-wrap: wrap; /* enable the wrap */
      margin:5px;
      vertical-align: top;
      width: 150px;
      height: 150px;
    }
    
    .container>* {
      flex-basis: 50%; /* width = 50% */
      flex-grow: 1; /* grow if alone in the last row */
      border: 1px solid red;
      box-sizing: border-box;
    }
    <div class="container">
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
    
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
    
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>

    It would be a bit tricky with CSS grid but you can do it like below:

    .container {
      border: 1px solid;
      display: inline-grid;
      grid-template-columns:1fr 1fr; /* 2 columns */
      grid-auto-rows:1fr; /* equal rows */
      margin:5px;
      vertical-align: top;
      width: 150px;
      height: 150px;
    }
    
    .container>* {
      border: 1px solid red;
    }
    .container>*:nth-child(odd):last-child {
      grid-column:span 2; /* take 2 columns */
    }
    <div class="container">
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
    </div>
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
    
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>
    
    <div class="container">
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
      <div></div>
    </div>