0

I have an image gallery with various image sizes (that are constantly being changed). I want to be able to move image cards up to sit right below the above image card.

Ideal layout

However, it's very important that the images remain in date order. The solutions I've tried all shift the order around. They mostly involve using flex to order by column, which produces the following result:

1 4 7
2 5
3 6

I still want:

1 2 3 4
5 6 7

Is there a way to do this, preferably in CSS Grid but I can use flexbox if necessary and it doesn't mess with ordering.

My current styling is very simplistic:

.cards-container-not-home {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
}

Ordering is determined by date desc. Images are stored with a timestamp on upload. Then I call firebase and get them back in date order and push them into an array:

  let picturesData = [];
  let snapshot = await db
    .collection(collection)
    .orderBy("timestamp", "desc")
    .get();
  snapshot.forEach((doc) => {
    let appData = doc.data();
    appData.id = doc.id;
    picturesData.push(appData);
  });
  return picturesData;

I iterate over the array, then do a v-for loop to print the image cards tot he page in that desc date order.

Here's the template:

<template>
  <div v-bind:class="{ 'cards-container-not-home': notHome }">
    <div v-for="data in imageData" :key="data.id">
      <div class="card">
        <img :src="data.source" :alt="data.caption" class="card-img" />
        <div class="text-box">
          <p>{{ moment(data.timestamp.toDate()).format("MMM Do YYYY") }}</p>
          <p>{{ data.caption }}</p>
          <Geolocation v-bind:address="data.location" />
        </div>
      </div>
    </div>
  </div>
</template>
crevulus
  • 1,658
  • 12
  • 42

1 Answers1

-1

You could use a flex grid and js mix to make a Masonry layout since it is a grid layout based on columns. Unlike other grid layouts, it doesn’t have fixed height rows

https://codepen.io/inorganik/pen/pREYPJ

Vue

<template>
  <div id="block-contain" v-bind:class="{ 'cards-container-not-home': notHome }">
    <div v-for="data in imageData" :key="data.id" class="block">
      <div class="card">
        <img :src="data.source" :alt="data.caption" class="card-img" />
        <div class="text-box">
          <p>{{ moment(data.timestamp.toDate()).format("MMM Do YYYY") }}</p>
          <p>{{ data.caption }}</p>
          <Geolocation v-bind:address="data.location" />
        </div>
      </div>
    </div>
  </div>
</template>

CSS

#block-contain { 
  display: flex;
  flex-flow: column wrap;
  max-width:100%;
}
.block {
  padding:20px;
  flex: 1 0 auto;
  overflow:hidden;
}
.card{
  width: 100%;
  height: 100%;
  display: flex;
  flex: 1 0 auto;
  justify-content:center;
  align-items:center;
  min-height:100px;
}

Script to adapt

var COL_COUNT = 3; // set this to however many columns you want
var col_heights = [], 
    container = document.getElementById('block-contain');
for (var i = 0; i <= COL_COUNT; i++) {
  col_heights.push(0);
}
for (var i = 0; i < container.children.length; i++) {
  var order = (i + 1) % COL_COUNT || COL_COUNT;
  container.children[i].style.order = order;
  col_heights[order] += parseFloat(container.children[i].style.height);
}
var highest = Math.max.apply(Math, col_heights);
container.style.height = highest+'px';
Dan M. CISSOKHO
  • 1,070
  • 1
  • 12
  • 27
  • I think that will just leave me with three equal columns. The effect I'm trying to achieve is ensuring the images stack in their columns without whitespace, as shown in the image. the 1234567 number blocks are just a demonstration of how flexbox didn't work for me because of the change in ordering. – crevulus Oct 04 '20 at 21:11