Bagzli
Bagzli

Reputation: 6569

Masonry Layout that can span multiple columns

I'm trying to create a masonry layout that can also span an item over 2 columns. So far I have made what I feel is a great start. Have a look:

.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: 5px;
  max-width: 600px;
  margin: 0 auto;
}
  
.wrapper  div {
  background: red;
}  

.two {
  grid-column-end: span 2;
}
<div class="wrapper">
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="two" style="grid-row-end: span 4; background-color: green;"></div>
  <div class="one" style="grid-row-end: span 4"></div>
  <div class="one" style="grid-row-end: span 2"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 2"></div>
  <div class="one" style="grid-row-end: span 5"></div>
</div>

Here is a JsFiddle if you want to play with it: http://jsfiddle.net/9o4de38u/2/

Now for this to work, I also have some javascript which determines how many rows the item needs to span. I don't think its relevant so I left it out and hard-coded values in the html for purposes of this demo.

My problem here is if you take a closer look at my demo, the green box spans over 2 columns, however the space before the green is empty. Because the green had to take up 2 spaces, the previous element only took one leaving a big gap. I want to fill this gap with the element that comes after the green. However, I'm not certain what would be the best way to do this.

My idea is to simply swap the order of elements in the html. If I swap green and the previous red then it will fill out nicely. The trouble is how to do this. My current thoughts are to use Javascript and use start position of the element to determine if a swap is needed. For Example if green box has a same starting position as the red box before it, swap them.

But I don't know how much I can rely on this, what if a browser renders it off different and its off by a pixel, it will have no effect.

My question is, what would be in your opinion the best way for me to accomplish what I want?

If there is a library out there that does what I want, I'll accept that as an answer as well. I just couldn't find any that can allow an item to span multiple columns.

Upvotes: 0

Views: 2970

Answers (1)

Steven Lambert
Steven Lambert

Reputation: 5891

Rafaela Ferro wrote an article on medium that goes into amazing detail on creating masonry style layouts using CSS grid that allow for great flexibility.

As @Paulie_D recommended, using grid-auto-flow: dense will tell the grid to fill in any holes produced by non-uniform layouts. Due to how you're setting up your heights though, some gaps will still occur.

.wrapper {
  display: grid;
  grid-gap: 20px;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  grid-auto-rows: 5px;
  max-width: 600px;
  margin: 0 auto;
  grid-auto-flow: dense;
}
  
.wrapper  div {
  background: red;
}  

.two {
  grid-column-end: span 2;
}
<div class="wrapper">
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="two" style="grid-row-end: span 4; background-color: green;"></div>
  <div class="one" style="grid-row-end: span 4"></div>
  <div class="one" style="grid-row-end: span 2"></div>
  <div class="one" style="grid-row-end: span 3"></div>
  <div class="one" style="grid-row-end: span 2"></div>
  <div class="one" style="grid-row-end: span 5"></div>
</div>

Upvotes: 3

Related Questions