2

I have been searching for a while a Masonry gallery with grid layout, I didn't found it so I decided to do it for myself. I use a customElement with grid layout but I get blocked when I assign dynamically the grid rows.
I would like your feedback and help to improve it.

Some Error that I have detected are:

  • Need to run 2 times to works
  • Blank spaces when image/container height is not multiple of 100

HTML

<masonry-gallery></masonry-gallery>

JS

 class MasonryGallery extends HTMLElement {

    items = [
    { image:'https://unsplash.it/200/100/' },
    { image:'https://unsplash.it/200/200/' },
    { image:'https://unsplash.it/200/300/' },
    { image:'https://unsplash.it/200/400/' },
    { image:'https://unsplash.it/200/300/' },
    { image:'https://unsplash.it/200/200/' },
    { image:'https://unsplash.it/200/100/' },
    { image:'https://unsplash.it/200/300/' },
    { image:'https://unsplash.it/200/700/' },
    { image:'https://unsplash.it/200/300/' },
    { image:'https://unsplash.it/200/200/' },
    { image:'https://unsplash.it/200/600/' },
    { image:'https://unsplash.it/200/100/' }
  ]

  constructor() {
    super()
    this.attachShadow({ mode: 'open'})
    this.create()
    this.append()
  }

  create() {
    this.style.display = 'grid'
    this.style.gridTemplateColumns = 'repeat(auto-fill, 200px)'
    this.style.gridTemplateRows = 'repeat(auto-fill, 1fr)'
    this.style.gridGap = '1rem'
    this.style.gridAutoFlow = 'row dense'
  }

  append() {

    this.items.map(item => {

        const div = document.createElement('DIV');
      const image = document.createElement('IMG')

      image.src = item.image
      div.appendChild(image)

      this.shadowRoot.appendChild(div)

      div.style.gridRow = 'auto / span ' + [...String(image.height)][0]
    })

  }

}

customElements.define('masonry-gallery', MasonryGallery)

FIDDLE https://jsfiddle.net/znhybgb6/6/

I haz kode
  • 1,587
  • 3
  • 19
  • 39
DanyNsg
  • 355
  • 3
  • 10
  • 1
    https://stackoverflow.com/q/44377343/3597276 – Michael Benjamin Aug 21 '17 at 17:24
  • Did you check the docs? https://isotope.metafizzy.co/layout-modes/masonry.html Plenty of examples there. Doing a gallery layout is what it does. – Nathaniel Flick Aug 21 '17 at 18:58
  • Please check the following fork of your fiddle: https://jsfiddle.net/znhybgb6/12/. Main changes: calculate image heights after they are loaded, 100px-tall auto grid rows, accounting for gap height in calculations. – Ilya Streltsyn Aug 23 '17 at 11:35

1 Answers1

1

Your "bugs" have the following reasons:

  1. You try to calculate the height of the image just after it is attached to the component, but its height is unknown at that point, it gets known only after the image has loaded.
  2. You have 1rem (16px) gaps between grid rows, so each 100px-tall image adds 116px to the grid height.

This behavior can be fixed, e.g., by the following edit of your append method:

append() {

    let gap = parseInt(getComputedStyle(this).gridRowGap)

    this.items.map(item => {

        const div = document.createElement('DIV');
      const image = document.createElement('IMG')
      image.style.display = 'block';

      image.src = item.image
      div.appendChild(image)
      image.onload = function() {
          this.parentNode.style.gridRow = 'auto / span ' + ((this.height + gap)/(100 + gap));
      }

      this.shadowRoot.appendChild(div)

    })

  }

and replacing gridRows with gridAutoRows = '100px' for making the vertical rhythm uniform, and adjusting the heights of the images accordingly.

You can see the result in the edited Fiddle.

Ilya Streltsyn
  • 13,076
  • 2
  • 37
  • 57