<div class="masonry" style="--item-width:200px">
<div class="box" style="--span:2">
1. Lorem ipsum dolor sit amet consectetur adipisicing elit.
<img src="https://picsum.photos/1200/800" alt="" />
</div>
<div class="box">
2. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voluptatibus? Vero, dicta dolore distinctio nulla
</div>
<div class="box" style="--span:2">
3. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voluptatibus? Vero, dicta dolore distinctio nulla
amet consequatur ab, voluptatibus omnis recusandae commodi eius nisi fat
non quos? Obcaecati?
</div>
<div class="box">
4. Lorem ipsum dolor sit amet consectetur adipisicing elit.at non quos?
Obcaecati?
</div>
<div class="box" >
5. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium volunon quos? Obcaecati?
</div>
<div class="box">6. Lorem</div>
<div class="box" >
7. Loa amet consequatur ab, voluptatibus omnis recusandae commodi eius
nisi fat non quos? Obcaecati?
</div>
<div class="box">
8. Lorem ipsum dolor sit amet consectetur adipisicing us omnis
recusandae commodi eius nisi fat non quos? Obcaecati?
</div>
<div class="box">
9. Lorem ipsum dolor sit amet consectetur adipisicing elit. Mro, dicta
dolore distinctio nulla amet consequatur ab, voluptatibus omnis
recusandae commodi eius nisi fat non quos? Obcaecati?
</div>
<div class="box">
10. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium vol quos? Obcaecati?
</div>
<div class="box">
11. Lorem ipsum dolor sit amet consectetur adipisicing elit. Mta dolore
distinctio nulla amet consequatur ab, voluptatibus omnis recusandae
commodi eius nisi fat non quos? Obcaecati?
</div>
<div class="box">
12. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentVero, dicta dolore distinctio nulla amet consequatur ab,
voluptatibus omnis recusandae commodi eius nisi fat non quos? Obcaecati?
</div>
<div class="box">
13. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium omnis recusandae commodi eius nisi fat non quos?
Obcaecati?
</div>
<div class="box">
14. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voero, dicta dolore distinctio nulla amet
consequatur ab, voluptatibus omnis recusandae commodi eius nisi fat non
quos? Obcaecati?
</div>
<div class="box">
15. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voluptatibus? Vero, dicta dolore distinctio nulla
amet consequatur ab, voluptatibus omnis recusandae commodi eius nisi fat
non quos? Obcaecati?
</div>
<div class="box">
16. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voluptatibus? Vero, dicta dolore distinctio nulla
amet consequatur ab, voluptatibus omnis recusandae commodi eius nisi fat
non quos? Obcaecati?
</div>
<div class="box">
17. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentiums omnis recusandae commodi eius nisi fat non quos?
Obcaecati?
</div>
<div class="box">
18. Lorem ipsum dolor sit amet consectetur adipisics recusandae commodi
eius nisi fat non quos? Obcaecati?
</div>
<div class="box">
19. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentium voluptatibus? Vero, dicta dolore distinctio null
consequatur ab, voluptatibus omnis recusandae commodi eius nisi fat non
quos? Obcaecati?
</div>
<div class="box">
20. Lorem ipsum dolor sit amet consectetur adipisicing elit. Maxime
impedit praesentibus omnis recusandae commodi eius nisi fat non quos?
Obcaecati?
</div>
</div>
.masonry {
display: grid;
grid-template-columns: repeat(
auto-fit,
minmax(min(var(--item-width, 200px), 100%), 1fr)
);
grid-template-rows: masonry;
gap: 1rem;
grid-auto-flow: dense;
> *,
> astro-slot > * {
align-self: start;
grid-column-end: span var(--span, 1);
}
}
/* Stylistic Purposes */
html {
font-family: system-ui, sans-serif;
}
body {
margin: 1rem;
}
.box {
display: flex;
flex-flow: column;
gap: 1rem;
border: 2px solid black;
padding: 1rem;
border-radius: 0.5rem;
background: white;
}
img {
display: block;
max-width: 100%;
}
const masonryLayouts = document.querySelectorAll('.masonry')
masonryLayouts.forEach(async container => {
if (isMasonrySupported(container)) return
const colGap = parseFloat(getComputedStyle(container).columnGap)
const items = getChildren(container)
container.style.gridAutoRows = '0px'
container.style.setProperty('row-gap', '1px', 'important')
try {
await Promise.all([areImagesLoaded(container), areVideosLoaded(container)])
} catch(e) {}
layout({colGap, items})
const observer = new ResizeObserver(observerFn)
observer.observe(container)
function observerFn(entries) {
for (const entry of entries) {
layout({colGap, items})
}
}
})
function isMasonrySupported(container) {
if (typeof window === 'undefined') return
return getComputedStyle(container).gridTemplateRows === 'masonry'
}
function getChildren(container) {
let children = container.children
// Compensate for Astro Slots
if (children[0]?.nodeName === 'ASTRO-SLOT') children = children[0].children
return Array.from(children)
}
async function areImagesLoaded(container) {
const images = Array.from(container.querySelectorAll('img'))
const promises = images.map(img => {
return new Promise((resolve, reject) => {
if (img.complete) return resolve()
img.onload = resolve
img.onerror = reject
})
})
return Promise.all(promises)
}
function areVideosLoaded(container) {
const videos = Array.from(container.querySelectorAll('video'))
const promises = videos.map(video => {
return new Promise((resolve, reject) => {
if (video.readyState === 4) return resolve() // HAVE_ENOUGH_DATA
video.onloadedmetadata = resolve
video.onerror = reject
})
})
return Promise.all(promises)
}
async function layout({colGap, items}) {
items.forEach(item => {
const ib = item.getBoundingClientRect()
item.style.gridRowEnd = `span ${Math.round(ib.height + colGap)}`
})
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.