Search code examples
htmlcsslayoutgridvuetify.js

Vuetify grid of cards aligned with a divider


I'm trying to make a grid of cards that hold an image and a title using Vuetify.

I have managed to make a grid with the help of a few examples and managed to make this (This is on breakpoint XL):

Grid in XL breakpoint

But the problem is that, if the screen goes smaller, the grid isn't much of a grid anymore, but rather looks like this (this is on breakpoint LG):

Grid in LG breakpoint

I'm using justification: space-between but if I use start this is the result:

Grid in LG breakpoint with justify-start

My goal is to have a grid aligned with the v-divider above and also is justified in the start without the awkward gap in the second row in the LG breakpoint.

Here's my code:

<v-container>
    <v-row justify="space-between">
      <v-col md="6" cols="12">
        <h1>Grid</h1>
      </v-col>

      <v-col md="6" cols="12">
        <v-text-field
          outlined
          dense
          hide-details
          :placeholder="$t('search')"
          prepend-inner-icon="mdi-magnify"
          :class="$vuetify.breakpoint.smAndUp ? 'mt-2' : ''"
        ></v-text-field>
      </v-col>
    </v-row>

    <v-row justify="space-between">
      <v-col cols="12">
        <v-divider></v-divider>
      </v-col>
    </v-row>

    <v-row :justify="$vuetify.breakpoint.smAndDown ? 'center' : 'start'">
        <v-col cols="auto" v-for="(item, index) in machines" :key="index">
          <v-hover v-slot="{ hover }">
            <v-card class="mb-4" :elevation="hover ? 5 : 2">
              <v-card-text>
                <v-img
                src="https://static.wikia.nocookie.net/bc87eadb-62dd-4748-bcb6-cc4f38594988"
                contain
                :width="$vuetify.breakpoint.lgAndUp ? '300' : '385'"
                height="250"
              ></v-img>
              </v-card-text>

              <v-card-actions>
                <v-btn text color="deep-orange">
                  Arthur Morgan
                </v-btn>
              </v-card-actions>
            </v-card>
          </v-hover>
        </v-col>
    </v-row>
  </v-container>

Solution

  • I guess, the correct answer is: you should not use flexboxes from v-col and v-row classes for these purposes.

    In this question you can find a wide variety of answers. But most of them looks like crutches or lead to unexpected effects.

    But you may use CSS Grid Layouts to fix your problem.

    So change your row code to:

    <v-row :justify="$vuetify.breakpoint.smAndDown ? 'center' : 'space-between'" :class="getClassByScreenSize()">
      ...
    </v-row>
    

    Then create some CSS classes using grid layouts (fr unit explanation is here):

    .two-cols {
      display: grid;
      grid-template-columns: repeat(2, 1fr);
    }
    
    .three-cols {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
    }
    
    .five-cols {
      display: grid;
      grid-template-columns: repeat(5, 1fr);
    }
    

    And then create getClassByScreenSize method to put classes to your template based on current vuetify breakpoint:

    ...
    methods: {
      getClassByScreenSize() {
        if (this.$vuetify.breakpoint.xlOnly) {
          return 'five-cols'
        }
        if (this.$vuetify.breakpoint.lgOnly) {
          return 'three-cols'
        }
        if (this.$vuetify.mdOnly) {
          return 'two-cols'
        }
        return ''
      }
    }
    

    Check this at CodePen.