Inspired by CSS Grid Masonry in the sense that CSS grid nearly does what we want and we can help it with a little JS I have the following solution:
We choose the maximum number of columns in our grid and the minimum width for a column. We have any number of grid items which can span between 1 and our maximum number of columns.
This example uses a maximum of 4 columns with a minimum width of 256px.
HTML:
<div class="grid">
<div class="w1"></div>
<div class="w1"></div>
<div class="w2"></div>
<div class="w1"></div>
<div class="w3"></div>
<div class="w4"></div>
...
</div>
CSS:
.grid {
display: grid;
}
.w1 {
grid-column-end: span 1;
}
.w2 {
grid-column-end: span 2;
}
.w3 {
grid-column-end: span 3;
}
.w4 {
grid-column-end: span 4;
JS:
// The minimum width in pixels for our columns
const colWidth = 256;
// The maximum number of columns in our grid
const maxCols = 4;
function resizeGrid() {
const grid = document.getElementsByClassName("grid")[0];
// Calculate the number of cols we can have by dividing the grid width by our colWidth.
// This is the maximum number of cols we can have if they are all colWidth.
const gridWidth = grid.getBoundingClientRect().width;
let cols = Math.floor(gridWidth / colWidth);
// Clamp this to our maxCols.
cols = Math.min(maxCols, cols);
// Set the number of cols in the grid
grid.style.gridTemplateColumns = "repeat(" + cols + ", 1fr)";
// Update grid-column spans limiting them to the number of cols we have.
// We must do this as grid with an item that spans n columns will automatically have a default of n columns.
for (let j = 1; j < maxCols + 1; j++) {
for (const gridItem of grid.getElementsByClassName("w" + j)) {
gridItem.style.gridColumnEnd = "span " + Math.min(j, cols);
}
}
}
window.addEventListener("resize", resizeGrid);
resizeGrid();
This works by calculating the number of columns which will fit into our grid given the minimum width. We then set our grid to have that number of columns and we limit our items to span up to the number of columns. This has the effect of collapsing the number of columns based on the width of the grid.
You can see this working in this Codepen.