Pure CSS Mosaic/Masonry layout
Nowadays, the internet is full of layouts to display several elements together. The most popular, in
the case of elements of different sizes, is “mosaic” or “masonry”, Pinterest being probably
Describing the layout style in words, it is presented to be several elements put together in an order that aims to fill the remaining empty space on both axes, like this:
PROBLEM: On the surface it seems easy to create a mosaic layout with flexbox. Just put there a few elements, make sure you set a max-height and a max-width on the items, make the container’s flex-flow: column wrap and there you go.
Unfortunately, in our case it is not that easy to reach this result, considering that our elements have the same width, but different height, and the container they are part of is also of variable height. We are only allowed to use PURE CSS.
AT FIRST: Knowing the power of Flexbox, I focused on finding a solution that would work, at least partially, without putting much effort and a lot of code. Thus, the search began and I tried different methods, but each involved at least one restricted thing in the list of requirements.
For starters, consider the following HTML and CSS:
That should create a page looking like below and as we can see, the items’ height is increased based on the largest one in the row:
As a matter of fact, if the elements had the same height, we could set a min-width and flex: auto on each item so it can take the remaining space and allow others to wrap accordingly. It would look like in the image below, but of course, it doesn’t respect the requirements we have(the elements are of different heights).
Another solution, perhaps closer to the result we want is adding flex-direction: column and make somehow the items wrap themselves for a new column. To get past this step, we need the container to have fixed height or at least items to have a max-height, which again...we are not allowed to have.
Anyway, at least let’s see how it was going to look by adding some random photos in.
Now it seems that we do not exactly have real chances of accomplishing what we want using only flexbox. However, there are two more options that are not very close to simple flex. Given our situation, we cannot really complain.
Combining flex-direction:column and n:th-child()
In this way the elements can wrap accordingly and still be in the right order in the row. The result will be exactly like in the photo above, but the code itself isn’t the easiest to maintain. Later on, if the order should be changed, we’ll be in the middle of a problem.
The code looks like this:
There must be something better than hardcoding the order...Here comes our saviour.
Using special CSS property column-count on the container
Probably the easiest to understand and not use Flexbox at all is setting column-count on the container and break-inside on the items to describe the column breaking behaviour.
Here we have the code:
and the result will be the desired one:
Depending on the available space, the browser will determine the width of the columns, unless you specify an exact width using the column-width property. Setting both column-count and column-width does not always make much sense, as it may restrict the flexibility and responsiveness of the layout, such as if you use absolute widths for the columns instead of percentage widths.
CONCLUSION: Flexbox has its limits
Eventually we came up with a suitable solution, but keep in mind that in turn, it is not easy to maintain and change the code. When rethinking the number of columns or the items’ width, we must be aware that the fixed sizes must also be changed.