Hari Anugrah
Hari Anugrah

Reputation: 544

Bootstrap 5 layout for different sizes cards - like Pinterest

I am building a web that would use Bootstrap 5, the web would have a section which displays several cards like this enter image description here

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

enter image description here

What class do I need to use (In bootstrap 5), or what layout

Upvotes: 6

Views: 15471

Answers (5)

realWorldCoder
realWorldCoder

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

Carol Skelly
Carol Skelly

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

Yosef Tukachinsky
Yosef Tukachinsky

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

marlisa
marlisa

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

susanta96
susanta96

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

Related Questions