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.

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

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

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

    source: https://drafts.csswg.org/css-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:

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