Grid system without empty space [duplicate] - html

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?

2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>

I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>

Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!

Related

How can i reduce the gap between items in flex wrap [duplicate]

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?
2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>
I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>
Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!

CSS Grid Consuming Extra Space [duplicate]

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?
2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>
I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>
Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!

Dynamic div column position [duplicate]

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?
2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>
I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>
Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!

how to wrap items different heights [duplicate]

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?
2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>
I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>
Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!

CSS flex fill blank [duplicate]

I need to implement a masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.
Parameters:
All elements have the same width
Elements have a height that cannot be calculated server side (an image plus various amounts of text)
I can live with a fixed number of columns if I have to
there is a trivial solution to this that works in modern browsers, the column-count property.
The problem with that solution is that elements are ordered in columns:
While I need the elements to be ordered in rows, at least approximately:
Approaches I've tried that don't work:
Making items display: inline-block: wastes vertical space.
Making items float: left: lol, no.
Now I could change the server side rendering and reorder the items dividing the number of items by the number of columns, but that's complicated, error-prone (based on how browsers decide to split the item list into columns), so I'd like to avoid it if possible.
Is there some flexbox magic that makes this possible?
2021 Update
CSS Grid Layout Level 3 includes a masonry feature.
Code will look like this:
grid-template-rows: masonry
grid-template-columns: masonry
As of March 2021, it's only available in Firefox (after activating the flag).
https://drafts.csswg.org/css-grid-3/#masonry-layout
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Masonry_Layout
end update; original answer below
Flexbox
A dynamic masonry layout is not possible with flexbox, at least not in a clean and efficient way.
Flexbox is a one-dimensional layout system. This means it can align items along horizontal OR vertical lines. A flex item is confined to its row or column.
A true grid system is two-dimensional, meaning it can align items along horizontal AND vertical lines. Content items can span across rows and columns simultaneously, which flex items cannot do.
This is why flexbox has a limited capacity for building grids. It's also a reason why the W3C has developed another CSS3 technology, Grid Layout.
row wrap
In a flex container with flex-flow: row wrap, flex items must wrap to new rows.
This means that a flex item cannot wrap under another item in the same row.
Notice above how div #3 wraps below div #1, creating a new row. It cannot wrap beneath div #2.
As a result, when items aren't the tallest in the row, white space remains, creating unsightly gaps.
column wrap
If you switch to flex-flow: column wrap, a grid-like layout is more attainable. However, a column-direction container has four potential problems right off the bat:
Flex items flow vertically, not horizontally (like you need in this case).
The container expands horizontally, not vertically (like the Pinterest layout).
It requires the container to have a fixed height, so the items know where to wrap.
As of this writing, it has a deficiency in all major browsers where the container doesn't expand to accommodate additional columns.
As a result, a column-direction container is not an option in this case, and in many other cases.
CSS Grid with item dimensions undefined
Grid Layout would be a perfect solution to your problem if the various heights of the content items could be pre-determined. All other requirements are well within Grid's capacity.
The width and height of grid items must be known in order to close gaps with surrounding items.
So Grid, which is the best CSS has to offer for building a horizontally-flowing masonry layout, falls short in this case.
In fact, until a CSS technology arrives with the ability to automatically close the gaps, CSS in general has no solution. Something like this would probably require reflowing the document, so I'm not sure how useful or efficient it would be.
You'll need a script.
JavaScript solutions tend to use absolute positioning, which removes content items from the document flow in order to re-arrange them with no gaps. Here are two examples:
Desandro Masonry
Masonry is a JavaScript grid layout library. It
works by placing elements in optimal position based on available
vertical space, sort of like a mason fitting stones in a wall.
source: http://masonry.desandro.com/
How to Build a Site that Works Like Pinterest
[Pinterest] really is a cool site, but what I find interesting is how these pinboards are laid out... So the purpose of this tutorial is to re-create this responsive block effect ourselves...
source: https://benholland.me/javascript/2012/02/20/how-to-build-a-site-that-works-like-pinterest.html
CSS Grid with item dimensions defined
For layouts where the width and height of content items are known, here's a horizontally-flowing masonry layout in pure CSS:
grid-container {
display: grid; /* 1 */
grid-auto-rows: 50px; /* 2 */
grid-gap: 10px; /* 3 */
grid-template-columns: repeat(auto-fill, minmax(30%, 1fr)); /* 4 */
}
[short] {
grid-row: span 1; /* 5 */
background-color: green;
}
[tall] {
grid-row: span 2;
background-color: crimson;
}
[taller] {
grid-row: span 3;
background-color: blue;
}
[tallest] {
grid-row: span 4;
background-color: gray;
}
grid-item {
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3em;
font-weight: bold;
color: white;
}
<grid-container>
<grid-item short>01</grid-item>
<grid-item short>02</grid-item>
<grid-item tall>03</grid-item>
<grid-item tall>04</grid-item>
<grid-item short>05</grid-item>
<grid-item taller>06</grid-item>
<grid-item short>07</grid-item>
<grid-item tallest>08</grid-item>
<grid-item tall>09</grid-item>
<grid-item short>10</grid-item>
<grid-item tallest>etc.</grid-item>
<grid-item tall></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item taller></grid-item>
<grid-item short></grid-item>
<grid-item tallest></grid-item>
<grid-item tall></grid-item>
<grid-item short></grid-item>
</grid-container>
jsFiddle demo
How it works
Establish a block-level grid container. (inline-grid would be the other option)
The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
The grid-gap property is a shorthand for grid-column-gap and grid-row-gap. This rule sets a 10px gap between grid items. (It doesn't apply to the area between items and the container.)
The grid-template-columns property sets the width of explicitly defined columns.
The repeat notation defines a pattern of repeating columns (or rows).
The auto-fill function tells the grid to line up as many columns (or rows) as possible without overflowing the container. (This can create a similar behavior to flex layout's flex-wrap: wrap.)
The minmax() function sets a minimum and maximum size range for each column (or row). In the code above, the width of each column will be a minimum of 30% of the container and maximum of whatever free space is available.
The fr unit represents a fraction of the free space in the grid container. It's comparable to flexbox's flex-grow property.
With grid-row and span we're telling grid items how many rows they should span across.
Browser Support for CSS Grid
Chrome - full support as of March 8, 2017 (version 57)
Firefox - full support as of March 6, 2017 (version 52)
Safari - full support as of March 26, 2017 (version 10.1)
Edge - full support as of October 16, 2017 (version 16)
IE11 - no support for current spec; supports obsolete version
Here's the complete picture: http://caniuse.com/#search=grid
Cool grid overlay feature in Firefox
In Firefox dev tools, when you inspect the grid container, there is a tiny grid icon in the CSS declaration. On click it displays an outline of your grid on the page.
More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts
This is recently discovered technique involving flexbox: https://tobiasahlin.com/blog/masonry-with-css/.
The article makes sense to me, but I haven't tried to use it, so I don't know if there are any caveats, other than mentioned in Michael's answer.
Here's a sample from the article, making use of the order property, combined with :nth-child.
Stack snippet
.container {
display: flex;
flex-flow: column wrap;
align-content: space-between;
/* Your container needs a fixed height, and it
* needs to be taller than your tallest column. */
height: 960px;
/* Optional */
background-color: #f7f7f7;
border-radius: 3px;
padding: 20px;
width: 60%;
margin: 40px auto;
counter-reset: items;
}
.item {
width: 24%;
/* Optional */
position: relative;
margin-bottom: 2%;
border-radius: 3px;
background-color: #a1cbfa;
border: 1px solid #4290e2;
box-shadow: 0 2px 2px rgba(0,90,250,0.05),
0 4px 4px rgba(0,90,250,0.05),
0 8px 8px rgba(0,90,250,0.05),
0 16px 16px rgba(0,90,250,0.05);
color: #fff;
padding: 15px;
box-sizing: border-box;
}
/* Just to print out numbers */
div.item::before {
counter-increment: items;
content: counter(items);
}
/* Re-order items into 3 rows */
.item:nth-of-type(4n+1) { order: 1; }
.item:nth-of-type(4n+2) { order: 2; }
.item:nth-of-type(4n+3) { order: 3; }
.item:nth-of-type(4n) { order: 4; }
/* Force new columns */
.break {
flex-basis: 100%;
width: 0;
border: 1px solid #ddd;
margin: 0;
content: "";
padding: 0;
}
body { font-family: sans-serif; }
h3 { text-align: center; }
<div class="container">
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 190px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 120px"></div>
<div class="item" style="height: 160px"></div>
<div class="item" style="height: 180px"></div>
<div class="item" style="height: 140px"></div>
<div class="item" style="height: 150px"></div>
<div class="item" style="height: 170px"></div>
<div class="item" style="height: 170px"></div>
<span class="item break"></span>
<span class="item break"></span>
<span class="item break"></span>
</div>
I find This solution, It is most probably compatible with all browsers.
Note: if anyone finds any error or browser support issues. please update this answer Or comments
CSS Profpery Support reference:
column-count, gap, fill break-inside, page-break-inside
Note: page-break-inside This property has been replaced by the break-inside property.
.container {
-moz-column-count: 1;
column-count: 1;
-moz-column-gap: 20px;
column-gap: 20px;
-moz-column-fill: balance;
column-fill: balance;
margin: 20px auto 0;
padding: 2rem;
}
.container .item {
display: inline-block;
margin: 0 0 20px;
page-break-inside: avoid;
-moz-column-break-inside: avoid;
break-inside: avoid;
width: 100%;
}
.container .item img {
width: 100%;
height: auto;
}
#media (min-width: 600px) {
.container {
-moz-column-count: 2;
column-count: 2;
}
}
#media (min-width: 900px) {
.container {
-moz-column-count: 3;
column-count: 3;
}
}
#media (min-width: 1200px) {
.container {
-moz-column-count: 4;
column-count: 4;
}
}
CSS-Only Masonry Layout
<div class="container">
<div class="item"><img src="https://placeimg.com/600/400/animals" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/arch" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/450/people" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/350/tech" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/800/animals/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/650/arch/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/300/nature/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/400/people/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/600/tech/grayscale" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/200/animals/sepia" alt=""></div>
<div class="item"><img src="https://placeimg.com/600/700/arch/grayscale" alt=""></div>
</div>
Finally a CSS-only solution to easily create masonry layout but we need to be patient since there is no support for it for now.
This feature was introduced in the CSS Grid Layout Module Level 3
This module introduces masonry layout as an additional layout mode for CSS Grid containers.
Then
Masonry layout is supported for grid containers by specifying the value masonry for one of its axes. This axis is called the masonry axis, and the other axis is called the grid axis.
A basic example would be:
.container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-template-rows: masonry; /* this will do the magic */
grid-gap: 10px;
}
img {
width: 100%;
}
<div class="container">
<img src="https://picsum.photos/id/1/200/300">
<img src="https://picsum.photos/id/17/200/400">
<img src="https://picsum.photos/id/18/200/100">
<img src="https://picsum.photos/id/107/200/200">
<img src="https://picsum.photos/id/1069/200/600">
<img src="https://picsum.photos/id/12/200/200">
<img src="https://picsum.photos/id/130/200/100">
<img src="https://picsum.photos/id/203/200/100">
<img src="https://picsum.photos/id/109/200/200">
<img src="https://picsum.photos/id/11/200/100">
</div>
This will produce the following result on Firefox if you enable the feature like explained here: https://caniuse.com/?search=masonry
open Firefox and write about:config in the url bar
do a search using masonry
you will get one flag, make it true
If we reduce the screen screen, the reponsive part is perfect!