LAY003

Masonry Grid Layout

Modern responsive grid with variable height items

Layouts

Live Preview

Nature image

Small Item

Short description here

Nature image

Medium Item

This is a medium sized item

Nature image

Large Item

This is a large sized item with more content

Nature image

Another Medium

Description text here

Nature image

Another Small

Short info

Code

HTML
<div class="masonry-container">
  <div class="masonry-grid">
    <div class="masonry-item small">
      <img src="https://source.unsplash.com/random/300x200?nature,1" alt="Nature image">
      <div class="masonry-item-content">
        <h3 class="masonry-item-title">Small Item</h3>
        <p class="masonry-item-description">Short description here</p>
      </div>
    </div>
    <div class="masonry-item medium">
      <img src="https://source.unsplash.com/random/300x300?nature,2" alt="Nature image">
      <div class="masonry-item-content">
        <h3 class="masonry-item-title">Medium Item</h3>
        <p class="masonry-item-description">This is a medium sized item</p>
      </div>
    </div>
    <div class="masonry-item large">
      <img src="https://source.unsplash.com/random/300x400?nature,3" alt="Nature image">
      <div class="masonry-item-content">
        <h3 class="masonry-item-title">Large Item</h3>
        <p class="masonry-item-description">This is a large sized item with more content</p>
      </div>
    </div>
    <!-- Add more items as needed -->
  </div>
</div>
CSS
.masonry-container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

.masonry-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: 10px;
  grid-gap: 16px;
}

.masonry-item {
  position: relative;
  background-color: #fff;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
  transition: all 0.3s ease;
  grid-row-end: span var(--span);
}

.masonry-item:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 20px rgba(0, 0, 0, 0.15);
}

.masonry-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  border-radius: 8px;
}

.masonry-item-content {
  padding: 15px;
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: linear-gradient(to top, 
    rgba(0, 0, 0, 0.8) 0%, 
    rgba(0, 0, 0, 0) 100%);
  color: white;
  border-radius: 0 0 8px 8px;
}

.masonry-item-title {
  font-weight: 600;
  margin: 0 0 5px 0;
  font-size: 16px;
}

.masonry-item-description {
  font-size: 14px;
  opacity: 0.9;
  margin: 0;
}

/* Options for different item heights */
.masonry-item.small {
  --span: 15;
}

.masonry-item.medium {
  --span: 20;
}

.masonry-item.large {
  --span: 30;
}

/* Dark mode adjustments */
@media (prefers-color-scheme: dark) {
  .masonry-item {
    background-color: #222;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
  }
  
  .masonry-item:hover {
    box-shadow: 0 10px 20px rgba(0, 0, 0, 0.4);
  }
}

/* Mobile responsiveness */
@media (max-width: 768px) {
  .masonry-grid {
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    grid-gap: 12px;
  }
  
  .masonry-item.small {
    --span: 12;
  }
  
  .masonry-item.medium {
    --span: 16;
  }
  
  .masonry-item.large {
    --span: 24;
  }
}
JavaScript (Optional)
// Optional JavaScript to recalculate item heights on image load
document.addEventListener('DOMContentLoaded', function() {
  const masonryItems = document.querySelectorAll('.masonry-item');
  
  // Function to set the height span based on actual content height
  function calculateHeightSpan(item) {
    const image = item.querySelector('img');
    
    // Wait for images to load to get correct heights
    if (image) {
      if (image.complete) {
        setItemSpan(item);
      } else {
        image.addEventListener('load', () => setItemSpan(item));
      }
    } else {
      setItemSpan(item);
    }
  }
  
  function setItemSpan(item) {
    const height = item.getBoundingClientRect().height;
    // Grid row height is 10px, plus gap (16px / 2 = 8px per item)
    const rowSpan = Math.ceil((height + 8) / (10 + 8));
    item.style.gridRowEnd = `span ${rowSpan}`;
  }
  
  // Calculate spans for all items
  masonryItems.forEach(calculateHeightSpan);
  
  // Recalculate on window resize
  window.addEventListener('resize', function() {
    masonryItems.forEach(calculateHeightSpan);
  });
});