Reputation: 544
I am building a web that would use Bootstrap 5, the web would have a section which displays several cards like this
As you can see, each card may have different sizes (Depending on the description and thumbnail)
How do I make them compact, as in like the Pinterest homepage
What class do I need to use (In bootstrap 5), or what layout
Upvotes: 6
Views: 15471
Reputation: 21
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.
Upvotes: 0
Reputation: 362630
As explained in the Bootstrap 5 docs, the Masonry JS plugin is the recommended option for this type of "Pinterest" layout. The multi-column card layout (card-columns) that was used in Bootstrap 4 is no longer available in Bootstrap 5.
Using the Masonry plugin is easy. Just use the appropriate col-*
class to set the number of columns across, and then the data-masonry
attribute on the containing row
...
<div class="container">
<div class="row" data-masonry='{"percentPosition": true }'>
<div class="col-*">
...
</div>
</div>
</div>
https://codeply.com/p/yrjCBwUeKR
Note: The CSS grid masonry (ie: grid-template-rows: masonry;
) option mentioned by others currently only works in Firefox, and is not yet a recommended option.
Upvotes: 11
Reputation: 5895
#cont {
columns:3;
column-gap: 5px;
}
#cont>div {
background: #c1c1ff;
margin-bottom: 5px;
break-inside:avoid;
}
<div id="cont">
<div style="height:30px"></div>
<div style="height:50px"></div>
<div style="height:70px"></div>
<div style="height:55px"></div>
<div style="height:90px"></div>
<div style="height:40px"></div>
<div style="height:60px"></div>
<div style="height:35px"></div>
</div>
Upvotes: 5
Reputation: 36
What you want to achieve is called a Masonry layout. There are different ways to do this, with CSS grid, Flexbox or with CSS' column functionality. Check out this link on css-tricks.com for details to the approaches.
Upvotes: -1
Reputation: 89
Don't use Bootstrap for this. Use CSS Grid Feature It can help you through the looping if dynamic content is loading as well as very easy to setup.
.grid-container {
width: 100%;
margin: 0 auto;
display: grid;
grid-gap: 20px;
text-align: center;
margin-top: 1rem;
grid-template-columns: repeat(3, 1fr);
}
Upvotes: 2