Search code examples
htmlcssflexboxgrid-layout

I am using flexbox to create my layout, however, I can't properly position the elements on my last row. Can I recreate the same layout with grid?


I have a flex container with a width that is not fixed and a bunch of children inside of it with fixed width. I've set flex-wrap to wrap and justify-content to space-evenly. This works fine and dandy for most parts, however, the position of the elements on the last row are not where I want them to be

I understand that the element on the last row are where they are because of justify-content: space-evenly. I am wondering if it is possible to space the content evenly when the row is full whilst keeping the children on the last line to the left side of the div. It should look something like this:

enter image description here

Sadly, I read that targeting elements on the last row is not actually possible with flexbox right now and that I should look into other alternatives. This is why I am wondering if its possible to recreate the same layout with grid whilst fixing the last row issues I'm having

    .cards-list {
        padding-top: 20px;
        display: flex;
        flex-wrap: wrap;
        justify-content: space-evenly;
    }
    .card {
        width: 120px;
        height: 180px;
        background-color: red;
        margin-bottom: 10px;
    }
<div class='cards-list'>
   <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>


Solution

  • I usually do this when using flex for grid layout when I need a fallback for display: grid;. You can add empty grid fillers with the same width/margin as the regular cards, and set the height to 0. The formula is to have 1 less filler then your card row count, so 4 cards > 3 fillers, 8 cards > 7 fillers. Hope it's clear.

    If you don't need a fallback you can use the class .grid in my example below.

    EDIT
    As you work with Vue you could do this. Remember that min-width is just a value I took it would have to change it to represent your breakpoints. If you like you don't even need that part. This is just a starter kit for you, it can be modified to your liking and project needs.

    <template v-if="window.matchMedia('(min-width: 998px)').matches">
      <div v-for="i of 15" :key="`card-filler-grid-name-${i}`" class="card--filler" />
    </template>
    

    .cards-list {
      padding-top: 20px;
      display: flex;
      flex-wrap: wrap;
      justify-content: space-evenly;
      max-width: 40rem;
      margin-bottom: 4rem;
    }
    
    .grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
      max-width: 40rem;
    }
    
    .card {
      width: 120px;
      height: 180px;
      background-color: red;
      margin-bottom: 10px;
    }
    
    .card--filler {
      width: 120px;
      height: 0;
    }
    <div class='cards-list'>
      <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--filler'></div>
      <div class='card--filler'></div>
      <div class='card--filler'></div>
      <div class='card--filler'></div>
    </div>
    
    <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='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
      <div class='card'></div>
    </div>