12

I'm trying to create a Masonry layout using Tailwind CSS utility classes (not plain CSS), but going through all the official Tailwind documentation it seems there is not a way to do it already provided by the framework.

Bootstrap 5 allows you to do it but requires JavaScript libraries. https://getbootstrap.com/docs/5.0/examples/masonry/

Is there a way to do it with Tailwind CSS without using any extra JavaScript library?

TylerH
  • 20,799
  • 66
  • 75
  • 101
Davide Casiraghi
  • 15,591
  • 9
  • 34
  • 56
  • This post is being [discussed on Meta](https://meta.stackoverflow.com/questions/406492/is-it-possible-to-reopen-a-question-related-to-tailwindcss-and-not-to-plain-css). – TylerH Apr 02 '21 at 14:14
  • The solution you provided below using Tailwind doesn't seem to be novel/unique to Tailwind, but rather using generic CSS classes with a custom mixin so that you can just say you're "using Tailwind". I'm voting to close this again as a duplicate of the appropriate questions. Feel free to provide that solution on the canonical target instead, if you think others might find a custom Tailwind mixin useful. – TylerH Apr 02 '21 at 14:35

2 Answers2

19

I solved it like this using TailwindCSS @layer and @variants directives.
The following code provides a 3 column grid layout on LG breakpoint that turns to 2 columns on MD breakpoint and just 1 column on mobile.

Add this your SCSS file:

@layer utilities {
    @variants responsive {
        .masonry-3-col {
            column-count: 3;
            column-gap: 1em;
        }
        .masonry-2-col {
            column-count: 2;
            column-gap: 1em;
        }
        .break-inside {
            break-inside: avoid;
        }
    }
}

And the HTML:

<div class="md:masonry-2-col lg:masonry-3-col box-border mx-auto before:box-inherit after:box-inherit">
  <div class="break-inside p-8 my-6 bg-gray-100 rounded-lg">
    <p>Really long content</p>
  </div>
  <div class="break-inside p-8 my-6 bg-gray-100 rounded-lg">
    <p>Really long content</p>
  </div>
  <div class="break-inside p-8 my-6 bg-gray-100 rounded-lg">
    <p>Really long content</p>
  </div>
  <div class="break-inside p-8 my-6 bg-gray-100 rounded-lg">
    <p>Really long content</p>
  </div>
  <div class="break-inside p-8 my-6 bg-gray-100 rounded-lg">
    <p>Really long content</p>
  </div>
</div>

My solution is an evolution of the answer that I have found in this nice article that was not providing the switch 1-2-3 columns on page resize.
https://blog.marclucraft.co.uk/masonry-layout-with-tailwindcss

Update With Tailwind v3

<div class="relative flex min-h-screen flex-col justify-center py-6 sm:py-12">
  <div
    class="columns-2 2xl:columns-3 gap-10 [column-fill:_balance] box-border mx-auto before:box-inherit after:box-inherit">
    <div class="break-inside-avoid p-8 mb-6 bg-gray-100 rounded-lg">
        <p>Really long content</p>
    </div>
    <div class="break-inside-avoid p-8 mb-6 bg-gray-100 rounded-lg">
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
    </div>
    <div class="break-inside-avoid p-8 mb-6 bg-gray-100 rounded-lg">
        <p>Really long content</p>
        <p>Really long content</p>
    </div>
    <div class="break-inside-avoid p-8 mb-6 bg-gray-100 rounded-lg">
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
    </div>
    <div class="break-inside-avoid p-8 mb-6 bg-gray-100 rounded-lg">
        <p>Really long content</p>
        <p>Really long content</p>
        <p>Really long content</p>
    </div>
</div>
</div>
OLIVIERS
  • 334
  • 3
  • 13
Davide Casiraghi
  • 15,591
  • 9
  • 34
  • 56
  • 5
    The problem with this is if you are trying to show items in date order, you will get all your latest items in the left column, and then older items at the top of the page in columns 2 and 3. It's a nice idea but just doesn't work in reality. – YodasMyDad Dec 14 '21 at 10:13
  • I'll suggest instead using my-6 on blocks, mb-6 will make more sense to line them up more precisely togethor – Kaustubh Jan 12 '22 at 11:20
  • @YodasMyDad It works in reality, just not for ordering by dates. – Jnr Feb 26 '22 at 08:43
  • Here is a playground of masonry grid with Tailwind v3: https://play.tailwindcss.com/waaDDm3Gg6 – OLIVIERS Apr 19 '22 at 08:19
3

It looks like that only this is required nowadays to do a proper masonry layout without the need to add any libraries:

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: masonry;
}

So, you could probably extend Tailwind's capabilities with few grid values.

More details on this article: https://www.smashingmagazine.com/native-css-masonry-layout-css-grid/

Current status of this can be found here: https://drafts.csswg.org/css-grid-3/

Wes Bos also do have a free CSS grid course on which, he emulates that kind of behavior with only CSS grid (no masonry prop).


EDIT: Masonry is not easy because it depends on what you're looking for exactly but even columns can be useful in some cases !

kissu
  • 40,416
  • 14
  • 65
  • 133
  • Thank you for your answer! Very interesting approach. I found also another strategy using css that is a little different and I'm working on it now. I will share it here later – Davide Casiraghi Apr 02 '21 at 05:58
  • Will be glad to see what this one is ! :3 Btw, I've edited my answer to incorporate `columns`, another neat CSS property that may be useful. – kissu Apr 02 '21 at 06:03
  • 1
    "grid-template-rows: masonry" is not a valid property. It does not work – Matthew C Dec 22 '21 at 18:05
  • @MatthewC more details [on MDN](https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-rows). – kissu Dec 22 '21 at 18:10