Just a quick note before we jump into the solution. The grid-template in Moz mentioned earlier keeps the divs in a grid layout rather than stacking them, you can find more information at this link: here
If you have a fixed number of items and don't need features like infinite scrolling or A-Z ordering down the page, you won't require an external library.
One thing to keep in mind is that with this approach, the cards are ordered A-Z down each column and then across, instead of A-Z across the page and down, which could lead to the last item appearing in an unexpected spot.
But if you enjoy figuring things out on your own and don't want to rely on external libraries, here's a simple math and logic-based approach:
The Logic
You can place all the cards in a d-flex column with flex-wrap, and then use a few lines of JavaScript or jQuery to adjust the container height based on the total height and width of the cards, causing the columns to overflow with their wrapping to create neat columns without overflowing issues.
An Example of the Logic
Pseudocode:
arrayofcards = getallelements('cards'),
sumHeights = arrayofcards.map(arrayofcards.height),
height of container = sumHeights / numberOfDesiredColumns
width of cards = (innerWidth / numberOfDesiredColumns) - gapWidth
Actual Code Example
HTML
<div class="cards-group d-flex flex-column flex-wrap">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>
Jquery/Javascript
$(()=>{
// get the card dom elements
var cardArray = Array.from($('.cards-group').find('.card'));
// get width of the card container / parent div
var innerWidth = $('.cards-group').width();
// get the cumulative height for all the cards
var cardArrayHeight=0;
cardArray.map((card)=>{ cardArrayHeight += $(card).height() });
// your custom number of columns (which you could data-tag to parent div)
let colNumber = 3 // change to suit tastes
// your custom card gap (which you could data-tag to parent div)
let colGap = 16 //= 1 rem default for html/body // change to suit tastes
// calculate the card width based on the number of columns, minus the gap width
var cardWidth = (innerWidth / colNumber) - colGap
// calculate the total card height including gaps between each card except the last one
var layoutTotalCardHeight = cardArrayHeight + ((cardArray.length-1) * colGap)
// set the container height to fit into the specified number of columns while accounting for gaps
var containerHeight = (layoutTotalCardHeight / (1+ (1/colNumber))) - (colNumber * colGap)
$('.cards-group').height(containerHeight);
$('.cards-group').css('gap',colGap);
$('.cards-group .card').css('width',cardWidth);
})
Remember, there are always multiple ways to achieve the same result!