TransWikia.com

Repositioning items using getBoundingClientRect() data

Stack Overflow Asked on November 4, 2021

I’m trying to code a masonry layout (please don’t suggest using a library and yes, I know about the new Firefox CSS masonry feature, but I need better support) starting from a CSS grid layout.

The HTML looks something like this, a section with a bunch of images of various aspect ratios:

<section class='grid--masonry'>
    <img src='black_cat.jpg' alt='black cat'/>
    <!-- and so on, more images following the first -->
</section>

The styling is pretty basic, just setting up the grid:

$w: Min(8em, 100%);
$s: .5rem;

.grid--masonry {
  display: grid;
  grid-template-columns: repeat(auto-fit, $w);
  grid-gap: $s;
  padding: $s;
    
  > * { width: $w }
}

In the JS, the first step is to get the grid, its element nodes (filtering out text nodes), the grid gap and init the number of columns:

Then, after the page has loaded, I call the layout() function:

addEventListener('load', e => {     
  layout(); /* initial load */
  addEventListener('resize', layout, false) /* on resize */
}, false)

The layout() function does the following:

  • gets the left offset for every grid item
  • since these offsets are identical for items on the same column, it creates a set of offsets whose size is the current number of columns
  • if the current number of columns is identical to the grid.ncol we already have, we do nothing and exit the function
  • otherwise, we update the grid.ncol value and then…
  • remove any top margin we may have on the grid items,
  • check whether we have more than one column
  • if we only have one column, we just exit the layout() function, we’re done!
  • otherwise, for each column, we get the items on it (filtering by offset)
  • if we only have one row, we exit the layout() function and do nothing more
  • otherwise, we loop through the items on the current column, get the bottom edge of the previous item and the top edge of the current one and compute by how much we need to shift the current one up

Here’s the code doing just that:

function layout() {
  /* get left offset for every item of the grid */
  grid.items.forEach(c => { c.off = c._el.getBoundingClientRect().left });

  /* make a set out of the array of offsets we've just obtained */
  grid.off = new Set(grid.items.map(c => c.off));
            
  /* if the number of columns has changed */
  if(grid.ncol !== grid.off.size) {
    /* update number of columns */
    grid.ncol = grid.off.size;
                
    /* revert to initial positioning, no margin */
    grid.items.forEach(c => c._el.style.removeProperty('margin-top'));
                
    /* if we have more than one column */
    if(grid.ncol > 1) {         
      grid.off.forEach(o => { /* for each column */
        /* get items on that column */
        let col_items = grid.items.filter(c => c.off === o), 
            col_len = col_items.length;
                        
        /* if we have more than 1 item per column */
        if(col_len > 1) {
          for(let i = 1; i < col_len; i++) {
            let prev_fin = col_items[i - 1]._el.getBoundingClientRect().bottom /* bottom edge of item above */, 
                curr_ini = col_items[i]._el.getBoundingClientRect().top /* top edge of current item */;
                                
           col_items[i]._el.style.marginTop = `${prev_fin + grid.gap - curr_ini}px`
          }
        }
      })
    }
  }
}

I would have hoped this works, but it doesn’t. It seems to work for two columns, but not for more. And I just can’t figure out why.

let grid = { _el: document.querySelector('.grid--masonry'), ncol: 0 };

grid.items = [...grid._el.childNodes].filter(c => c.nodeType === 1).map(c => ({ _el: c }));
grid.gap = parseFloat(getComputedStyle(grid._el).gridRowGap);

function layout() {
  /* get left offset for every item of the current grid */
  grid.items.forEach(c => { c.off = c._el.getBoundingClientRect().left });
  /* make a set out of the array of offsets we've just obtained */
  grid.off = new Set(grid.items.map(c => c.off));

  /* if the number of columns has changed */
  if(grid.ncol !== grid.off.size) {
    /* update number of columns */
    grid.ncol = grid.off.size;

    /* revert to initial positioning, no margin */
    grid.items.forEach(c => c._el.style.removeProperty('margin-top'));

    /* if we have more than one column */
    if(grid.ncol > 1) {         
      grid.off.forEach(o => { /* for each column */
        /* get items on that column */
        let col_items = grid.items.filter(c => c.off === o), 
            col_len = col_items.length;

        /* if we have more than 1 item per column */
        if(col_len > 1) {
          for(let i = 1; i < col_len; i++) {
            let prev_fin = col_items[i - 1]._el.getBoundingClientRect().bottom /* bottom edge of item above */, 
                curr_ini = col_items[i]._el.getBoundingClientRect().top /* top edge of current item */;

            col_items[i]._el.style.marginTop = `${prev_fin + grid.gap - curr_ini}px`
          }
        }
      })
    }
  }
}

addEventListener('load', e => {     
  layout(); /* initial load */
  addEventListener('resize', layout, false) /* on resize */
}, false);
.grid--masonry {
  display: grid;
  grid-template-columns: repeat(auto-fit, Min(8em, 100%));
  justify-content: center;
  grid-gap: .5rem;
  padding: .5rem;
  background: violet;
}
.grid--masonry > * {
  width: Min(8em, 100%);
}
<section class='grid--masonry'>
    <img src='https://images.unsplash.com/photo-1510137600163-2729bc6959a6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=900&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587041403375-ddce288f4c49?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1580697895575-883f7c755346?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''/>
    <img src='https://images.unsplash.com/photo-1581200459935-685903de7d62?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1578264050450-ccc2f77796a1?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1557153921-10129d0f5b6c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584049086295-9f2af90efbb4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1572196663741-b91b8f045330?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1558288215-664da65499af?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1592296109897-9c4d8e490e7a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1525104885119-8806dd94ad58?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576532116216-84f6a0aedaf6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1533629947587-7b04aaa0e837?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1568386895623-74df8a7406f0?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1573777058681-73b866833d90?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1552566852-06d10a5050f4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576759470820-77a440a4d45b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1586891622678-999a4419da34?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584797318381-5958ca2e6b39?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1529093589387-b486dcc37c15?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587421803669-b403d010dd80?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1570458436416-b8fcccfe883f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1518206245806-5c1f4d0c5a2a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
</section>

2 Answers

author of the Masonry js plugin here. Rather than calculate the margin-top offset by comparing the previous and current items in a column, I recommend keeping track of column heights. For each item, set its margin-top to the offset position of the that column height. Then update the the column height to account for the height of the item.

let grid = { _el: document.querySelector('.grid--masonry'), ncol: 0 };

grid.items = [...grid._el.childNodes].filter(c => c.nodeType === 1).map(c => ({ _el: c }));
grid.gap = parseFloat(getComputedStyle(grid._el).gridRowGap);

function layout() {
  /* keep track of column heights */
  let initial_height = grid.items[0]._el.getBoundingClientRect().top;
  grid.col_heights = new Map();
  grid.items.forEach(c => {
    /* get left offset for every item of the current grid */
    let rect = c._el.getBoundingClientRect();
    c.off = rect.left;
    grid.col_heights.set(c.off, initial_height);
  });

  /* if the number of columns has changed */
  if(grid.ncol === grid.col_heights.size) {
    return
  }
  /* update number of columns */
  grid.ncol = grid.col_heights.size;

  /* revert to initial positioning, no margin */
  grid.items.forEach(c => c._el.style.removeProperty('margin-top'));

  if(grid.ncol === 1) { 
    return
  }
  /* if we have more than one column */

  grid.items.forEach(grid_item => {
    let rect = grid_item._el.getBoundingClientRect();
    /* get height of masonry-ed column */
    let col_height = grid.col_heights.get(grid_item.off);
    /* set marginTop to different between where it is and where it should be */
    grid_item._el.style.marginTop = `${col_height - rect.top}px`;
    /* update col_height with element height */
    col_height += grid_item._el.offsetHeight + grid.gap;
    grid.col_heights.set(grid_item.off, col_height);
  })
}

addEventListener('load', e => {     
  layout(); /* initial load */
  addEventListener('resize', layout, false) /* on resize */
}, false);
.grid--masonry {
  display: grid;
  grid-template-columns: repeat(auto-fit, Min(8em, 100%));
  justify-content: center;
  grid-gap: .5rem;
  padding: .5rem;
  background: violet;
}
.grid--masonry > * {
  width: Min(8em, 100%);
}
<section class='grid--masonry'>
    <img src='https://images.unsplash.com/photo-1510137600163-2729bc6959a6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=900&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587041403375-ddce288f4c49?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1580697895575-883f7c755346?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''/>
    <img src='https://images.unsplash.com/photo-1581200459935-685903de7d62?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1578264050450-ccc2f77796a1?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1557153921-10129d0f5b6c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584049086295-9f2af90efbb4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1572196663741-b91b8f045330?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1558288215-664da65499af?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1592296109897-9c4d8e490e7a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1525104885119-8806dd94ad58?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576532116216-84f6a0aedaf6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1533629947587-7b04aaa0e837?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1568386895623-74df8a7406f0?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1573777058681-73b866833d90?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1552566852-06d10a5050f4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576759470820-77a440a4d45b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1586891622678-999a4419da34?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584797318381-5958ca2e6b39?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1529093589387-b486dcc37c15?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587421803669-b403d010dd80?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1570458436416-b8fcccfe883f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1518206245806-5c1f4d0c5a2a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
</section>

Answered by desandro on November 4, 2021

It seems that, since items in different columns of the Grid are not independent, changing the height of the cells in the earlier rows can affect the position of the cells in the earlier columns of the next rows. Changing the order of updating items from "column-by-column" to "one-by-one" seems to fix it:

let grid = { _el: document.querySelector('.grid--masonry'), ncol: 0 };

grid.items = [...grid._el.childNodes].filter(c => c.nodeType === 1).map(c => ({ _el: c }));
grid.gap = parseFloat(getComputedStyle(grid._el).gridRowGap);

function layout() {
  /* get left offset for every item of the current grid */
  grid.items.forEach(c => { c.off = c._el.getBoundingClientRect().left });
  /* make a set out of the array of offsets we've just obtained */
  grid.off = new Set(grid.items.map(c => c.off));

  /* if the number of columns has changed */
  if(grid.ncol !== grid.off.size) {
    /* update number of columns */
    grid.ncol = grid.off.size;

    /* revert to initial positioning, no margin */
    grid.items.forEach(c => c._el.style.removeProperty('margin-top'));

    /* if we have more than one column */
    if(grid.ncol > 1) {         
      grid.items.forEach((item, n) => { /* for each item*/
        /* if we have more than 1 item per column */
        if(n >= grid.ncol) {
            let prev_fin = grid.items[n - grid.ncol]._el.getBoundingClientRect().bottom /* bottom edge of item above */, 
                curr_ini = item._el.getBoundingClientRect().top /* top edge of current item */;

            item._el.style.marginTop = `${prev_fin + grid.gap - curr_ini}px`;
        }
      })
    }
  }
}

addEventListener('load', e => {     
  layout(); /* initial load */
  addEventListener('resize', layout, false); /* on resize */
}, false);
.grid--masonry {
  display: grid;
  grid-template-columns: repeat(auto-fit, Min(8em, 100%));
  justify-content: center;
  grid-gap: .5rem;
  padding: .5rem;
  background: violet;
}
.grid--masonry > * {
  width: Min(8em, 100%);
}
<section class='grid--masonry'>
    <img src='https://images.unsplash.com/photo-1510137600163-2729bc6959a6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=900&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587041403375-ddce288f4c49?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1580697895575-883f7c755346?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt=''/>
    <img src='https://images.unsplash.com/photo-1581200459935-685903de7d62?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1578264050450-ccc2f77796a1?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1557153921-10129d0f5b6c?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584049086295-9f2af90efbb4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1572196663741-b91b8f045330?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1558288215-664da65499af?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1592296109897-9c4d8e490e7a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1525104885119-8806dd94ad58?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576532116216-84f6a0aedaf6?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1533629947587-7b04aaa0e837?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1568386895623-74df8a7406f0?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1573777058681-73b866833d90?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1552566852-06d10a5050f4?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1576759470820-77a440a4d45b?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1586891622678-999a4419da34?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1584797318381-5958ca2e6b39?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1529093589387-b486dcc37c15?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1587421803669-b403d010dd80?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1570458436416-b8fcccfe883f?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
    <img src='https://images.unsplash.com/photo-1518206245806-5c1f4d0c5a2a?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=400&fit=max&ixid=eyJhcHBfaWQiOjE0NTg5fQ' alt='black cat'/>
</section>

Answered by Ilya Streltsyn on November 4, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP