Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Masonry grid with flexbox (or other CSS)

I would like to achieve a grid effect in CSS with elements that all have the same width in size but not in height. I would like the element underneath to be always at 50px of the bottom one, whatever is next.

I tried with floats, but that bug. So I tried with Flex, but it still does not do what I want.

.container
  display: flex
  flex-wrap wrap
  align-content flex-start
  align-items flex-start

What I would like:

enter image description here

What I have:

enter image description here

like image 331
Jeremy Avatar asked May 10 '17 20:05

Jeremy


People also ask

Can CSS grid do masonry?

A 2 dimensional grid with each block being arranged strictly by column AND row. As Rachel mentions, a Masonry like effect can be created by having blocks that span rows but CSS Grid can't apply this automatically.

Should I use flexbox or CSS grid?

CSS Grid and Flexbox are layout models that share similarities and can even be used together. The main difference is that you can use CSS Grid to create two-dimensional layouts. In contrast, you can only use Flexbox to create one-dimensional layouts.

Can you mix CSS grid and flexbox?

You can use them together but not necessarily one the same element. For instance I can place a div in a CSS-Grid parent container (which has display:grid ) but the child div could have display:flex to lay out it's children.


2 Answers

Try the new CSS Grid Layout:

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-container>
  <grid-item short></grid-item>
  <grid-item short></grid-item>
  <grid-item tall></grid-item>
  <grid-item tall></grid-item>
  <grid-item short></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-item tallest></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.
  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.


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.

enter image description here

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

like image 183
Michael Benjamin Avatar answered Oct 27 '22 10:10

Michael Benjamin


I would suggest a column layout. It can be easily made responsive to your liking by declaring both column-width and column-count. The benefit over Emonadeo's solution (no offense) is that it still remains responsive without any additional markup added. The drawback is, that the elements get sorted into columns first, not rows.

.container {
   /* min width of a single column */
   column-width: 140px;
   /* maximum amount of columns */
   column-count: 4;
   /* gap between the columns */
   column-gap: 16px;
}


.container div {
  /* important so a single div never gets distributed between columns */
  break-inside: avoid-column;

  background-color: #2C2F33;
  margin-bottom: 16px;
  color:white;
}
<div class="container">
    <div style="height: 200px">a</div>
    <div style="height: 100px">b</div>
    <div style="height: 200px">c</div>
    <div style="height: 150px">d</div>
    <div style="height: 250px">e</div>
    <div style="height: 200px">f</div>
    <div style="height: 300px">g</div>
    <div style="height: 150px">h</div>
    <div style="height: 100px">i</div>
</div>
like image 20
Christoph Avatar answered Oct 27 '22 10:10

Christoph