I think the best way to do this is to break the data into "buckets" to order them based on the number of columns you have, then flatten those buckets back into a single-dimensional array for output/display purposes. The below solution will handle any data length and any number of columns and return a re-ordered array based on the number of columns you have. Hope this helps.
let data = [1, 2, 3, 4, 5, 6];
function dataColumnReorder (data, numColumns) {
// generate a list of "buckets" to order the items
let buckets = [];
for (let i = 0; i < numColumns; i++) {
buckets.push([]);
}
// fill the buckets, then flatten so all the data ends up in 1 flattened array
let reordered = data.reduce((res, curr, index) => {
// determine which bucket the item goes into based on index
let bucketIndex = index % numColumns;
res[bucketIndex].push(curr);
return res;
}, buckets).flat();
return reordered;
}
console.log(dataColumnReorder(data, 1));
console.log(dataColumnReorder(data, 2));
console.log(dataColumnReorder(data, 3));
console.log(dataColumnReorder(data, 4));
You can do this purely with CSS using CSS Grid to create a masonry-style layout, but keep in mind, this will not always preserve the order of the items depending on the height variance. If one item spans multiple rows, it will use the next items to fill the gap in space of the empty rows on other columns, meaning it won't always read left-to-right in order. If you want them to always be in order, set a fixed height of your rows and make each item 1 row, or make each item the same height. If you want them to be a masonry-style layout, it won't always preserve order. Here's an example with minimal effort inspired by this article. (Note: to change the # of columns, adjust the grid-template-columns property in css. You can have different classes to support the different column sizes):
function resizeGridItem(item){
grid = document.getElementsByClassName("grid")[0];
rowHeight = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-auto-rows'));
rowGap = parseInt(window.getComputedStyle(grid).getPropertyValue('grid-row-gap'));
rowSpan = Math.ceil((item.querySelector('.content').getBoundingClientRect().height+rowGap)/(rowHeight+rowGap));
item.style.gridRowEnd = "span "+rowSpan;
}
function resizeAllGridItems(){
allItems = document.getElementsByClassName("item");
for(x=0;x<allItems.length;x++){
resizeGridItem(allItems[x]);
}
}
function resizeInstance(instance){
item = instance.elements[0];
resizeGridItem(item);
}
let data = Array.from(Array(30)).map((_, i) => i+1);
let grid$ = document.querySelector('.grid');
for (item of data) {
let item$ = document.createElement('div');
item$.classList.add('item');
let content$ = document.createElement('div');
content$.classList.add('content');
content$.style.height = `${Math.floor(Math.random() * 100) + 160}px`;
content$.innerText = item;
item$.append(content$);
grid$.append(item$);
}
resizeAllGridItems();
window.addEventListener("resize", resizeAllGridItems);
.grid {
display: grid;
grid-gap: 10px;
grid-template-columns: repeat(3, minmax(250px,1fr));
grid-auto-rows: 20px;
}
/* Non-grid specific CSS */
body {
margin: 10px;
color: #374046;
background-color: #374046;
font-family: 'Open Sans Condensed', sans-serif;
font-size: 1.15em;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
}
.item {
background-color: #ffffff;
}
<div class="grid">
</div>