search

Home  >  Q&A  >  body text

How to implement this responsive layout using flexbox

I'm making a React app that renders xy number of cards and a single widget inside a Flex container. All cards have the same width and height, but the widget's height is equal to card height * 2 row-gap. The width of the container changes based on the viewport width and should visually look like 2 or 3 columns with cards respectively. For further clarity, I've provided a mockup image of the required layout, with the widgets represented in blue.

No matter what I try, I can't get the widgets to display in the correct position without changing the height of the row to its size, leaving a "blank row" where 1 or 2 more cards should be rendered , as shown in the figure below.

My current solution involves Javascript, and depending on the viewport width, I load 2 or 4 cards into a separate small Flex container, which is rendered as the first child of the main Flex container. This workaround works great visually, but makes my code more complex since I have to cover a lot of different situations to get it to work properly. I'd like to achieve the same goal using css/flexbox, but I'm still a beginner and have never done a layout like this before and obviously have no idea how to do it. The widget cannot be absolutely positioned because this would break the scrolling functionality of its child elements.

I'm providing test HTML and CSS measurements in correct proportions in case it helps.

.container {
  margin: 50px 300px;
  display: flex;
  flex-wrap: wrap;
  row-gap: 20px;
  column-gap: 20px;
  min-width: 320px; /* Width for 2 columns */
  max-width: 490px; /* Width for 3 columns */
  border: 3px solid rgb(0, 22, 117);
}

.card {
  width: 150px;
  height: 100px;
  background-color: bisque;
}

.widget {
  height: 220px; /* card height * 2 row-gap */
  width: 150px;
  background-color: rgb(134, 204, 245);
}
<div class="container">
  <div class="widget"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
  <div class="card"></div>
</div>

<!-- Original jsx
<div className='container'>
  <div className='widget'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
  <div className='card'></div>
</div>
-->

I would really like to learn how to create a layout like this in Flexbox, not only for my current project, but also to expand my knowledge and understanding. If you have any ideas on how to solve this problem, please help me. Thank you in advance :)

P粉733166744P粉733166744300 days ago416

reply all(2)I'll reply

  • P粉391677921

    P粉3916779212024-02-27 15:38:05

    这可以使用网格布局来完成,无需 JavaScript,下面是一个示例:

    .container {
      margin: 50px 300px;
      display: grid;
      /* auto calculate columns, minimun cell width is 140px */  
      grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
      
      /* height of each cell */
      grid-auto-rows: 100px;
      
      grid-auto-flow: row dense;
      gap: 20px;
      min-width: 320px;
      max-width: 490px;
      border: 3px solid rgb(0, 22, 117);
    }
    
    .card {
      background-color: bisque;
    }
    
    .widget {
      background-color: rgb(134, 204, 245);
      /* widget, span for 2 rows */
      grid-row: auto / span 2;
      
      /* set the widget to the right most column */
      grid-column-end: -1;
    }
    <div class="container">
      <div class="widget"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
    </div>
    
    <!-- Original jsx
    <div className='container'>
      <div className='widget'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
      <div className='card'></div>
    </div>
    -->

    正如@ralph.m 提到的。您始终可以通过将 grid-column-end: -1; 设置为 .widget.widget >

    reply
    0
  • P粉321584263

    P粉3215842632024-02-27 09:10:49

    Flexbox layout can't do this, it doesn't create a 2d grid, you have to use gridbox layout. , so elements can span rows and columns without leaving gaps.

    This is an example:

    .grid {
    /* give some space gutters */
      margin: 1em auto;
      padding:1em;
      gap: 1em;
     /* build a grid */
      display: grid;
      grid-auto-flow: row dense;/* fill any holes that could show up */
      grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); /* auto calculate size of the grid */
      grid-auto-rows: 75px; /* give an height row for the demo */
      max-width: 80%;/* whatever */
      border: solid;/* see my boundaries */
    }
    
    .card {
      background-color: salmon;
    }
    
    .bigger {
      background-color: lightblue;
      grid-row: 1/ span 2;/* keep me on first row and lay over 2 rows */
      grid-column-end: -1; /* keep me on the last column no matter how many */
    }
    <div class="grid">
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="bigger">I can be anywhere in the flow but I'll show on top end</div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
      <div class="card"></div>
    </div>

    reply
    0
  • Cancelreply