{"id":10445,"date":"2026-07-17T14:52:50","date_gmt":"2026-07-17T19:52:50","guid":{"rendered":"https:\/\/master.dev\/blog\/?p=10445"},"modified":"2026-07-17T14:52:51","modified_gmt":"2026-07-17T19:52:51","slug":"masonry-with-animation-in-css","status":"publish","type":"post","link":"https:\/\/master.dev\/blog\/masonry-with-animation-in-css\/","title":{"rendered":"Masonry (with Animation) in CSS"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Perhaps you&#8217;ve seen the good news that <code><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/Guides\/Grid_layout\/Masonry_layout\">display: grid-lanes;<\/a><\/code> is <a href=\"https:\/\/caniuse.com\/css-grid-lanes\">starting to arrive<\/a> in browsers which replicates what we generally call &#8220;masonry&#8221; layout in CSS. It&#8217;s in Safari and feature-flagged in Chrome and Firefox. It gives this staggered grid item layout (with <a href=\"https:\/\/gridlanes.webkit.org\/\">lots of possibilities<\/a>) reminiscent of a brick wall, hence the name. <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The name <em>really<\/em> comes from David DeSandro&#8217;s original library <a href=\"https:\/\/masonry.desandro.com\/\">Masonry.js<\/a> (and also <a href=\"https:\/\/packery.metafizzy.co\/\">Packery<\/a> and <a href=\"https:\/\/isotope.metafizzy.co\/layout-modes\/masonry\">Isotope<\/a>). Those libraries accomplished the staggered layout well. But the foundation of them was a bunch of elements <code>float<\/code>ed. Here&#8217;s an original demo of Masonry.js:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019f6ce7-1839-7816-95f9-544934543120\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019f6ce7-1839-7816-95f9-544934543120?height=450&amp;theme-id=1&amp;slug-hash=019f6ce7-1839-7816-95f9-544934543120&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019f6ce7-1839-7816-95f9-544934543120\" title=\"CodePen Embed 019f6ce7-1839-7816-95f9-544934543120\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">If you <em>resize<\/em> that, you&#8217;ll see that Masonry.js <strong>had another trick up its sleeve<\/strong>: animation! <\/p>\n\n\n\n<p class=\"wp-block-paragraph\">See, Masonry.js supported fluidity, such that if the number of items (based on an ideal width) that could &#8220;fit&#8221; on a horizontal row had to change, it would redo its calculation magic and animate the elements into new positions. Here&#8217;s a video of that.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe loading=\"lazy\" title=\"VideoPress Video Player\" aria-label=\"VideoPress Video Player\" width=\"500\" height=\"314\" src=\"https:\/\/videopress.com\/embed\/AoUVRbEo?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0\" frameborder=\"0\" allowfullscreen data-resize-to-parent=\"true\" allow=\"clipboard-write; presentation\"><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1770107250'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t\n\n\n<p class=\"wp-block-paragraph\">I thought about this when I saw a mind-blowing <a href=\"https:\/\/codepen.io\/bramus\/pen\/ogBYjgm\">demo from Bramus<\/a> in which grid items would animate to new positions under the same conditions. But Bramus&#8217; demo uses actual grid layout! And the re-calculating grid was by virtue of <code>repeat<\/code>\/<code>auto-fill<\/code> magic that grid has always been good at, like <code>grid-template-columns: repeat(auto-fill, 6rem);<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The trick in Bramus&#8217; demo is that it&#8217;s not actual the grid items themselves that animate into new positions. It&#8217;s actually a <em>child element<\/em> of the grid items, which is set to cover the entire grid area by virtue of anchor positioning and an <code>inset<\/code> value that tracks the parent cell&#8217;s position. <em>Super cool.<\/em><\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.grid<\/span> {\n  <span class=\"hljs-attribute\">display<\/span>: grid;\n  <span class=\"hljs-attribute\">grid-template-columns<\/span>: <span class=\"hljs-built_in\">repeat<\/span>(auto-fill, ...);\n\n  .cell {\n     <span class=\"hljs-attribute\">anchor-scope<\/span>: --grid-cell;\n     <span class=\"hljs-attribute\">anchor-name<\/span>: --grid-cell;\n\n     .cell-content {\n        <span class=\"hljs-attribute\">transition<\/span>: inset <span class=\"hljs-number\">0.2s<\/span> ease;\n        <span class=\"hljs-attribute\">position<\/span>: absolute;\n  \t<span class=\"hljs-attribute\">position-anchor<\/span>: --grid-cell;\n  \t<span class=\"hljs-attribute\">inset<\/span>: <span class=\"hljs-built_in\">anchor<\/span>(inside);\n     }\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p class=\"wp-block-paragraph\">You don&#8217;t have to nest it like that; I just did it to make the structure clearer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">That feels pretty darn magical to me. I don&#8217;t know I would have thought of it, as it feels like to cover the cell you&#8217;d do <code>inset: 0;<\/code> and then there is nothing really to animate as that never changes. But apparently the <code>anchor(inside)<\/code> is dynamic enough that it animates even if the end result it essentially the same as <code>inset: 0;<\/code><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So here&#8217;s David&#8217;s original demo, with the JavaScript and floating ripped out, and a grid layout put in place instead, with the magical CSS from above:<\/p>\n\n\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_019f6d4c-2831-73d7-9d53-521369dcf6f6\" src=\"\/\/codepen.io\/editor\/anon\/embed\/019f6d4c-2831-73d7-9d53-521369dcf6f6?height=450&amp;theme-id=1&amp;slug-hash=019f6d4c-2831-73d7-9d53-521369dcf6f6&amp;default-tab=result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed 019f6d4c-2831-73d7-9d53-521369dcf6f6\" title=\"CodePen Embed 019f6d4c-2831-73d7-9d53-521369dcf6f6\" class=\"cp_embed_iframe\" style=\"width:100%;overflow:hidden\">CodePen Embed Fallback<\/iframe><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a video of that, which is pretty darn close to the same as the JavaScript version.<\/p>\n\n\n\n\t\t<figure class=\"wp-block-jetpack-videopress jetpack-videopress-player\" style=\"\" >\n\t\t\t<div class=\"jetpack-videopress-player__wrapper\"> <iframe loading=\"lazy\" title=\"VideoPress Video Player\" aria-label=\"VideoPress Video Player\" width=\"500\" height=\"270\" src=\"https:\/\/videopress.com\/embed\/gAOicEMy?cover=1&amp;autoPlay=0&amp;controls=1&amp;loop=0&amp;muted=0&amp;persistVolume=1&amp;playsinline=0&amp;preloadContent=metadata&amp;useAverageColor=1&amp;hd=0\" frameborder=\"0\" allowfullscreen data-resize-to-parent=\"true\" allow=\"clipboard-write; presentation\"><\/iframe><script src='https:\/\/v0.wordpress.com\/js\/next\/videopress-iframe.js?m=1770107250'><\/script><\/div>\n\t\t\t\n\t\t\t\n\t\t<\/figure>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Masonry.js was famous for creating, uh, Masonry layouts. But it did something else, too: animate fluid grids. Here&#8217;s a way to get that in native CSS as well as the layout.<\/p>\n","protected":false},"author":1,"featured_media":10455,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[1],"tags":[100,7,123,508,165],"class_list":["post-10445","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-animation","tag-css","tag-grid","tag-grid-lanes","tag-masonry"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/master.dev\/blog\/wp-content\/uploads\/2026\/07\/masonry.jpg?fit=2000%2C1200&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/posts\/10445","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/comments?post=10445"}],"version-history":[{"count":5,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/posts\/10445\/revisions"}],"predecessor-version":[{"id":10457,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/posts\/10445\/revisions\/10457"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/media\/10455"}],"wp:attachment":[{"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/media?parent=10445"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/categories?post=10445"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/master.dev\/blog\/wp-json\/wp\/v2\/tags?post=10445"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}