Simple Masonry
This sill achieve a simple masonry layout, similar to those of Pinterest. The grid will be three rows in large screen sizes, two rows in medium screen sizes and one row in mobile;
In order to achieve this – we will use SASS and a simple JavaScript. The HTML layout is as follows:
<div class="item-container">
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
<div class="item">{content}</div>
</div>
The CSS styling is this:
.item-container {
display: flex;
flex-direction: column;
flex-wrap: wrap
}
.item {
width: 100%;
margin-bottom: 10px;
margin-right: 0;
@media (min-width: 640px) {
&:nth-child(3n+1),
&:nth-child(3n+2),
&:nth-child(3n) {
order: unset;
}
width: calc((100% - 15px)/2);
margin-right: 15px;
margin-bottom: 15px;
&:nth-child(2n+1) {
order: 1;
}
&:nth-child(2n) {
order: 2;
margin-right: 0;
}
}
@media (min-width: 1024px) {
&:nth-child(2n+1),
&:nth-child(2n) {
order: unset;
}
width: calc((100% - 30px)/3);
margin-right: 15px;
margin-bottom: 15px;
&:nth-child(3n+1) {
order: 1;
}
&:nth-child(3n+2) {
order: 2;
}
&:nth-child(3n) {
order: 3;
margin-right: 0;
}
}
}
Now, this was the easy part. In order for this to work – we need to set the min-height of the container. Now this is the tricky part – we do this with JS.
const container = document.querySelector('item-container');
const _overflowHack = (itemContainer) => {
if (itemContainer.offsetWidth === itemContainer.scrollWidth) {
return;
}
let maxHeight = itemContainer.style.maxHeight;
if ('none' === maxHeight) {
return;
}
maxHeight = parseInt(maxHeight.replace('px', '')) + 50 + 'px';
itemContainer.style.maxHeight = maxHeight;
_overflowHack(itemContainer);
}
const _setMaxHeight = (itemContainer, childClass) => {
childClass = childClass ? childClass : 'archive-item';
const width = window.innerWidth;
let entireHeight = 0;
const elements = document.getElementsByClassName(childClass);
for (let i = 0; i < elements.length; i++) {
const item = elements[i];
entireHeight += item.offsetHeight;
}
let maximum;
if (width < 640) {
maximum = 'none';
} else if (width > 640 && width < 1024) {
maximum = (entireHeight / 2) + 500 + 'px';
} else {
maximum = (entireHeight / 3) + 500 + 'px';
}
itemContainer.style.maxHeight = maximum;
_overflowHack(itemContainer);
}
if (container) {
_setMaxHeight(container);
window.onresize = () => {
_setMaxHeight(container);
}
}
So, a bit of explanation – the idea behind is to be scaleable and with elements with different sizes in mind. So the _setMaxHeight function calculates all children div’s combined height and then divides by either two or three, depending on the screen size. Then it adds some more pixels for good measure.
The ugly hacky part is the _overflowHack function – it checks whether some element is going out of the screen border and if this happens – adds 50 pixels to the max height and reruns it again, till there’s no overflow. I preferred this way, because adding too much max height in advance can mess up the layout.