Wednesday, July 26, 2017

CSS-only masonry layout but with elements ordered horizontally

Leave a Comment

I need to implement a fairly run-off-the-mill masonry layout. However, for a number of reasons I don't want to use JavaScript to do it.

enter image description here

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:

enter image description here

While I need the elements to be ordered in rows, at least approximately:

enter image description here

Approaches I've tried that don't work:

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 newfangled flexbox magic that makes this possible?

1 Answers

Answers 1

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.

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:


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

  1. Establish a block-level grid container. (inline-grid would be the other option)
  2. The grid-auto-rows property sets the height of automatically generated rows. In this grid each row is 50px tall.
  3. 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.)
  4. 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.

  5. 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
  • Firefox - full support as of March 6, 2017
  • Safari - full support as of March 26, 2017
  • Edge - currently in development
  • 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.

enter image description here

More details here: https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Examine_grid_layouts

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment