Quick point before solution. The Moz grid-template mentioned above doesn't stack the divs.. they are still in a grid.. check the link
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_grid_layout/Masonry_layout#masonry_layout_with_spanning_items
External library is not needed if you have a set number of items and don't require an infinite scroll or A-Z ordering down the page.
!NOTE : The disadvantage with this approach is the ordering of cards is A-Z down each column then across, instead of A-Z across the page and down.. meaning the last item could appear in the first row third column.
However it's really simple and doesn't require external libraries - and if you like to figure out your own approach using a bit of math and logic.. here it is.
Logic
Put all of the cards into a d-flex column with flex-wrap, then just a few lines of javascript or jquery that changes container height based the total height and width of cards, which casuses the columns to overflow with their wrapping to generate columns that do not overflow and are reasonably flush at the bottom.
Logic example
ie. peudocode
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
// card width is the based on column numbers, less a column gap
var cardWidth = (innerWidth / colNumber) - colGap
// the total cumulative height is the height of all the cards, plus all the gaps except one gap (don't include a gap at the end)
var layoutTotalCardHeight = cardArrayHeight + ((cardArray.length-1) * colGap)
// the container height, will be a gross down of the height to fit into the number of columns, LESS the gaps at the bottom of each folumn
var containerHeight = (layoutTotalCardHeight / (1+ (1/colNumber))) - (colNumber * colGap)
$('.cards-group').height(containerHeight);
$('.cards-group').css('gap',colGap);
$('.cards-group .card').css('width',cardWidth);
})
There's always more than one way to peel a banana.