skip to Main Content

enter image description here

How I can create blocks like this? Of course I should use directive v-for to render items. But I have no idea how. And any masonry libs cant help me with that

I used "@yeger/vue-masonry-wall" but it doesnt help because it gave masonry by cols, but I need masonry by rows like in image.

My code looks like this:

<template>
  <masonry-wall 
    :items="items" 
    :column-width="200" 
    :gap="16" 
    :ssr="false"
    class="masonry-wall"
  >
    <template #default="{ item }">
      <div class="masonry-item">
        <img :src="item.img" :alt="item.title" class="masonry-img" />
        <div class="masonry-caption">
          <h1 class="masonry-title">{{ item.title }}</h1>
          <span class="masonry-description">{{ item.description }}</span>
        </div>
      </div>
    </template>
  </masonry-wall>
</template>

<script setup>
const items = [
  { img: 'link-to-image1.jpg', title: 'Ночник LEGO', description: 'Красивый ночник в форме LEGO' },
  { img: 'link-to-image2.jpg', title: 'Ночник LEGO', description: 'Идеален для детской комнаты' },
  { img: 'link-to-image3.jpg', title: 'Ночник LEGO', description: 'Яркий и стильный' },
  { img: 'link-to-image4.jpg', title: 'Ночник LEGO', description: 'Долговечный дизайн' },
  { img: 'link-to-image5.jpg', title: 'Ночник LEGO', description: 'Энергосберегающий' },
  { img: 'link-to-image6.jpg', title: 'Ночник LEGO', description: 'Идеальный подарок' },
];
</script>

2

Answers


  1. To achieve the desired design, you can use flex. I will provide sample code. The core of my code is determining the image viewport when displaying the image. That is, when displaying any image, you need to check whether it is a square image, portrait or landscape, and then use the correct class name. For example, you are using item so if item.img.width > item.img.height, you will use landScapeItem, if it’s reverse, will use portraitItem and they are same, will use squareItem.

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
          .galleryWrapper {
            width: 100%;
            height: 100%;
    
            display: flex;
            flex-wrap: wrap;
            align-content: baseline;
    
            overflow-y: scroll;
    
            .squareItem {
              width: 240px;
              height: 240px;
              position: relative;
    
              img {
                width: 100%;
                height: 100%;
                object-fit: cover;
              }
            }
            
            .landScapeItem {
              width: 360px;
              height: 240px;
              position: relative;
    
              img {
                width: 100%;
                height: 100%;
                object-fit: cover;
              }
            }
    
            .portraitItem {
              width: 160px;
              height: 240px;
              position: relative;
    
              img {
                width: 100%;
                height: 100%;
                object-fit: cover;
              }
            }
          }
        </style>
    </head>
    <body>
      <div>
        <div class="">
            <div class="galleryWrapper">
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="squareItem">
                <img src="./square-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="squareItem">
                <img src="./square-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="portraitItem">
                <img src="./portrait-1.jpg" />
              </div>
              <div class="squareItem">
                <img src="./square-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
              <div class="landScapeItem">
                <img src="./landscape-1.jpg" />
              </div>
            </div>
        </div>
      </div>
    </body>
    </html>
    

    example image

    Login or Signup to reply.
  2. There was already a similar question about Row Masonry Layout, answered here: Horizontal "masonry" type layout with variable row heights

    One of the commenters (SB3NDER) have offered an example of such layout, css-only, on codepen. It seems a simple and nice example with explanations and comments offering the way to build the functionality you need. You may want to check it out.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search