By Guybrush Threepwood


2015-12-27 13:16:22 8 Comments

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?

5 comments

@Michael_B 2015-12-27 13:59:09

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.

enter image description here

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.

enter image description here

enter image description here

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:

  1. It expands the container horizontally, not vertically (like the Pinterest layout).
  2. It requires the container to have a fixed height, so the items know where to wrap.
  3. 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

@G-Cyr 2017-04-20 20:12:35

the column approach seems a good compromise if you set column-width via vmin or vmax units and drop column-count (first snippet) , display:grid and vmin is also an option for the futur (second snippet).

snippet inspired from @Lanti answer.

test demo with vmin

.container {

}

ul {
  margin: 0;
  padding: 0;
}

ul li {
  list-style: none;
  font-size: 0;
}

.portfolio ul {
  -webkit-column-width:50vmin;
     -moz-column-width:50vmin;
          column-width:50vmin;
  -webkit-column-fill:balance;
     -moz-column-fill:balance;
          column-fill:balance;
  -webkit-column-gap: 3px;
     -moz-column-gap: 3px;
          column-gap: 3px;
}

.portfolio ul:hover img {
  opacity: 0.3;
}

.portfolio ul:hover img:hover {
  opacity: 1;
}

.portfolio ul li {
  margin-bottom: 3px;
}

.portfolio ul li img {
  max-width: 100%;
  transition: 0.8s opacity;
}
<section class="container portfolio">
  <ul>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_2959-1400px.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-010.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_6188-dng-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151220-csaladi-peregi-046-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151230-csalad-szalai-0194-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-001(1).jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171819-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171829-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171938-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171953-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528194754-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528184948-portfolio.jpg" alt="" /></li>
  </ul>
</section>

a link among others https://web-design-weekly.com/2014/11/18/viewport-units-vw-vh-vmin-vmax/


display:grid coud make it also easy with auto-fill but will require to set a span value to tallest image so rows and columns can inbricate

.container {}

ul {
  margin: 0;
  padding: 0;
}

ul li {
  list-style: none;
  font-size: 0;
}

.portfolio ul {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(50vmin, 1fr));
  grid-gap: 5px;
  grid-auto-rows: minmax(10px, 1fr);
  grid-auto-flow: dense;
}

.portfolio ul:hover img {
  opacity: 0.3;
}

.portfolio ul:hover img:hover {
  opacity: 1;
}

.portfolio ul li {
  margin-bottom: 3px;
}

.portfolio ul li img {
  max-width: 100%;
  transition: 0.8s opacity;
}

li {
  border: solid blue;
  grid-row-end: span 1;
  display: flex;
  align-items: center;
  background: lightgray;
}

li:nth-child(1),
li:nth-child(3),
li:nth-child(6),
li:nth-child(7),
li:nth-child(8),
li:nth-child(9),
li:nth-child(10),
li:nth-child(11) {
  border: solid red;
  grid-row-end: span 2
}
<section class="container portfolio">
  <ul>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_2959-1400px.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-010.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_6188-dng-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151220-csaladi-peregi-046-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151230-csalad-szalai-0194-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-001(1).jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171819-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171829-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171938-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171953-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528194754-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528184948-portfolio.jpg" alt="" /></li>
  </ul>
</section>

you can see https://css-tricks.com/snippets/css/complete-guide-grid/

@Guybrush Threepwood 2017-04-21 13:36:57

The 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

@Lanti 2016-11-29 13:25:09

Instead of flexbox, I recommend to use columns for grids like this. As you can see, the spacing on the bottom images can be better, but for a native CSS solution I think it's pretty neat. No more JS:

.container {
  max-width: 900px;
  width: 100%;
  margin: 0 auto;
}

ul {
  margin: 0;
  padding: 0;
}

ul li {
  list-style: none;
  font-size: 0;
}

.portfolio ul {
  -moz-column-count: 4;
  -webkit-column-count: 4;
  column-count: 4;
  -moz-column-gap: 3px;
  -webkit-column-gap: 3px;
  column-gap: 3px;
}

.portfolio ul:hover img {
  opacity: 0.3;
}

.portfolio ul:hover img:hover {
  opacity: 1;
}

.portfolio ul li {
  margin-bottom: 3px;
}

.portfolio ul li img {
  max-width: 100%;
  transition: 0.8s opacity;
}
<section class="container portfolio">
  <ul>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_2959-1400px.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-010.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/IMG_6188-dng-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151220-csaladi-peregi-046-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/20151230-csalad-szalai-0194-k.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/lantosistvan-portfolio-001(1).jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171819-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171829-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171938-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528171953-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528194754-portfolio.jpg" alt="" /></li>
    <li><img src="http://lantosistvan.com/temp/freecodecamp/160528184948-portfolio.jpg" alt="" /></li>
  </ul>
</section>

@Guybrush Threepwood 2017-01-23 19:09:22

That looks good, but the order of the elements is wrong. The challenging part is to lay out the elements horizontally, then wrap vertically.

@David Chelliah 2016-08-08 18:54:44

You can achieve the masonry effect as per your screenshot, but you've set the height of the outer div dynamically

html {
  box-sizing: border-box;
}
*,
*:before,
*:after {
  box-sizing: inherit;
}
.item-list {
  max-width: 400px;
  border: 1px solid red;
  display: -ms-flexbox;
	-ms-flex-direction: column;
	-ms-flex-wrap: wrap;
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	height: 100vw;
}
.item-list__item {
  border: 1px solid green;
  width: 50%;
}
<div class="item-list" >
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
    county enough the figure former add. Do sang my he next mr soon. It merely waited do unable.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do.
  </div>
  <div class="item-list__item">
    Is we miles ready he might going. Own books built put civil fully blind fanny. Projection appearance at of admiration no. As he totally cousins warrant besides ashamed do. Therefore by applauded acuteness supported affection it. Except had sex limits
  </div>
</div>

@Andrei Gheorghiu 2015-12-27 13:46:49

What you want can be achieved in 3 2 ways, CSS wise:

1. 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;
    }

2. 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;
    }

3. Masonry plugin

absolute positioning after calculating rendered item sizes, via JavaScript (masonry plugin).

@Guybrush Threepwood 2015-12-27 15:05:22

#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.

@Andrei Gheorghiu 2015-12-27 17:33:41

You'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 2015-12-29 15:44:27

If 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

@Andrei Gheorghiu 2015-12-29 16:13:00

Fascinating. Can you spot any differences between grid and columns?

@Guybrush Threepwood 2015-12-29 16:14:33

lol, was that sarcasm? In any case, you're right.

Related Questions

Sponsored Content

10 Answered Questions

[SOLVED] How to Right-align flex item?

23 Answered Questions

[SOLVED] How can I reorder my divs with CSS?

  • 2008-10-20 23:16:40
  • devmode
  • 335471 View
  • 236 Score
  • 23 Answer
  • Tags:   html css css3

28 Answered Questions

[SOLVED] What methods of ‘clearfix’ can I use?

  • 2008-10-17 08:15:36
  • Chris J Allen
  • 455654 View
  • 835 Score
  • 28 Answer
  • Tags:   css clearfix

21 Answered Questions

[SOLVED] Expand a div to take the remaining width

24 Answered Questions

[SOLVED] Flex-box: Align last row to grid

3 Answered Questions

[SOLVED] Fill remaining vertical space with CSS using display:flex

  • 2014-08-02 18:15:57
  • Zilk
  • 126683 View
  • 134 Score
  • 3 Answer
  • Tags:   css layout flexbox

3 Answered Questions

[SOLVED] When flexbox items wrap in column mode, container does not grow its width

  • 2015-11-24 10:55:00
  • Anders Tornblad
  • 30779 View
  • 114 Score
  • 3 Answer
  • Tags:   html css css3 flexbox

0 Answered Questions

How do I achieve this in Flexbox? (vertically align a heading with flexbox item)

1 Answered Questions

Flexbox: Right Column should not be higher than Left one

2 Answered Questions

[SOLVED] How can I make my flexbox layout take 100% vertical space?

  • 2014-04-15 17:06:21
  • Evil Closet Monkey
  • 82769 View
  • 69 Score
  • 2 Answer
  • Tags:   html css css3 flexbox

Sponsored Content