Is it possible for flex items to align tightly to the items above them?
Solution 1
Flexbox is a "1-dimensional" layout system: It can align items along horizontal OR vertical lines.
A true grid system is "2-dimensional": It can align items along horizontal AND vertical lines. In other words, cells can span across columns and rows, which flexbox 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 (see below).
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.
image credit: Jefree Sujit
column wrap
Solution
If you switch to flex-flow: column wrap
, flex items will stack vertically and a grid-like layout is more attainable. However, a column-direction container has three potential problems right off the bat:
- It expands the container 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 may not be feasible in many cases.
Other Solutions
-
Add containers
In the first two images above, consider wrapping items 2 and 3 in a separate container. This new container can be a sibling to item 1. Done.
Here's a detailed example: Calculator keypad layout with flexbox
One downside worth highlighting: If you're wanting to use the
order
property to re-arrange your layout (such as in media queries), this method may eliminate that option. -
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 Layout Module Level 1
This CSS module defines a two-dimensional grid-based layout system, optimized for user interface design. In the grid layout model, the children of a grid container can be positioned into arbitrary slots in a predefined flexible or fixed-size layout grid.
Grid Layout example: CSS-only masonry layout but with elements ordered horizontally
Solution 2
What you want can be achieved in 3 2 ways, CSS wise:
-
flexbox: =
.parent { display: flex; flex-direction: column; flex-wrap: wrap; max-width: {max-width-of-container} /* normally 100%, in a relative container */ min-height: {min-height-of-container}; /* i'd use vh here */ } .child { width: {column-width}; display: block; }
-
CSS columns = (this solution has the very neat advantage of built-in
column-span
- pretty handy for titles). The disadvantage is ordering items in columns (first column contains first third of the items and so on...). I made a jsFiddle for this..parent { -webkit-columns: {column width} {number of columns}; /* Chrome, Safari, Opera */ -moz-columns: {column width} {number of columns}; /* Firefox */ columns: {column width} {number of columns}; } .child { width: {column width}; } /* where {column width} is usually fixed size * and {number of columns} is the maximum number of columns. * Additionally, to avoid breaks inside your elements, you want to add: */ .child { display: inline-block; -webkit-column-break-inside: avoid; page-break-inside: avoid; break-inside: avoid-column; }
-
Masonry plugin
absolute positioning after calculating rendered item sizes, via JavaScript (masonry plugin).
Related videos on Youtube
Guybrush Threepwood
My name is Guybrush Threepwood, and I want to be a pirate! I aim to be a technology-agnostic engineer, meaning that I see more value in exploring different paradigms and working out where they converge or diverge, than in getting locked into one specific language or technology. Having said that, most of my practical experience is in Go, JavaScript (currently React, node), PHP and Python.
Updated on July 05, 2022Comments
-
Guybrush Threepwood almost 2 years
This is, in effect, the Pinterest layout. However, the solutions found online are wrapped in columns, which means the container inadvertently grows horizontally. That is not the Pinterest layout, and it does not work well with dynamically-loaded content.
What I want to do is have a bunch of images of fixed width and asymmetrical height, laid out horizontally but wrapping in a new row when the limits of the fixed-width container are met:
Can flexbox do this, or do I have to resort to a JS solution like Masonry?
-
tao over 8 yearsIt is not clear what the order of your elements should be and it is quite important. Could you add numbers to them?
-
Guybrush Threepwood over 8 yearsI though about that, but it might restrict the possible answers. I do know that the top three would be 1, 2, 3 from left to right, but I don't really care if 4 is placed below 1, 2 or 3. (If vertical placement is the criteria, it should be below 3; if it is horizontal placement, it should be below 1.) Anything goes!
-
Nenad Vracar over 8 yearsNo flexbox is not good solution for this layout, you should use masonry or in worst case css columns, its similar to my answer on this question so it might help you stackoverflow.com/questions/34417059/…
-
Paulie_D over 8 years
-
tao about 7 yearsA bit late at the party, here's the
answer to a similar question
by Evan Sharp, author of the Pinterest script and co-founder of Pinterest, explaining the logic. -
tao about 7 years@Michael_B I believe Evan Sharp's answer and his logic should be promoted for the efficiency and lightness of the script, outlined in the last sentence. The bar is set pretty high for all other options.
-
Michael Benjamin about 7 years@AndreiGheorghiu, this particular question was asking if there's a way to achieve a Pinterest-like layout with flexbox. I focused my answer on that priority. That's why the alternatives are at the end. They don't address the question. I included them solely for informational purposes.
-
-
Guybrush Threepwood over 8 years#1 does not work for me on the latest Firefox (I should update with a playground example; will do so). #2 actually came very close with a few quirks to be worked out, but I understand it uses the new CSS grid system that has very poor browser support.
-
tao over 8 yearsYou're right about #1. I wasn't able to make it work using flex. Not sure what you mean by "very poor browser support". Can you point me to some numbers, please? I think #2 has problems for less than 5% of users. Correct me if I'm wrong.
-
Guybrush Threepwood over 8 yearsIf you look at the Usage Relative stats, the grid system is unsupported for a huge number of users, so it's probably not production-ready yet. It's a great solution though, thanks for that. caniuse.com/#search=grid
-
tao over 8 years
-
Guybrush Threepwood over 7 yearsThat looks good, but the order of the elements is wrong. The challenging part is to lay out the elements horizontally, then wrap vertically.
-
Guybrush Threepwood about 7 yearsThe order of images in the first snippet is wrong, that's the problem with arranging in columns. But the second one seems to be on point! Really nice