[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"quiz-css-grid-lanes-native-masonry-layout":44,"search-suggestions":60,"quiz-article-css-grid-lanes-native-masonry-layout":108,"path-membership-css-grid-lanes-native-masonry-layout":287},[4,20,32],{"id":5,"slug":6,"name":7,"tagline":8,"description":9,"accentFrom":10,"accentTo":11,"icon":12,"defaultLocale":13,"locales":14,"features":16,"position":19},"019fe637-3d33-714b-b57f-23e163ffca0c","dev","Web Development","Read it. Run it. Prove it.","A post a day on modern web development — most with an editable playground and a quiz that explains every answer. Free, no account needed.","violet-500","cyan-400","◇","en",[13,15],"fa",{"courses":17,"paths":17,"articles":17,"exams":18,"flashcards":18,"packages":17,"community":17,"certificates":17,"teams":17,"commerce":17},true,false,0,{"id":21,"slug":22,"name":23,"tagline":24,"description":25,"accentFrom":26,"accentTo":10,"icon":27,"defaultLocale":13,"locales":28,"features":30,"position":31},"019fe637-3dc2-754c-8657-0f175bfee7c6","lang","Languages","Learn a language the way you learn a codebase.","Grammar explained the way good documentation explains an API — one idea at a time, each with a quiz.","amber-400","⌘",[13,15,29],"es",{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":17,"packages":18,"community":17,"certificates":17,"teams":18,"commerce":18},2,{"id":33,"slug":34,"name":35,"tagline":36,"description":37,"accentFrom":38,"accentTo":39,"icon":40,"defaultLocale":13,"locales":41,"features":42,"position":43},"7b3c16f2-931d-410e-802e-e1fa4edab7de","soft","Soft Skills","The half of the job nobody wrote documentation for.","Weekly, on the parts of working life that decide more than your code does — first weeks, meetings, interviews, promotions, and the people around you. Written from what actually happens, and recorded as a podcast you can listen to on the walk.","emerald-400","teal-300","◉",[13],{"courses":18,"paths":18,"articles":17,"exams":18,"flashcards":18,"packages":18,"community":17,"certificates":18,"teams":18,"commerce":18},3,{"id":45,"slug":46,"kind":47,"title":48,"description":49,"config":50,"verticalId":5,"vertical":55,"course":52,"_count":56,"access":57,"attempts":59,"questionCount":51},"01a1749f-2836-72e4-9974-9b9656b2529a","css-grid-lanes-native-masonry-layout","PRACTICE_QUIZ","CSS Grid Lanes and native masonry layout","Checks the real takeaways: why plain Grid can't do masonry on its own, what was actually wrong with the column-count hack, how display: grid-lanes packs items, and the honest state of browser support.",{"questionCount":51,"timeLimitSec":52,"shuffleQuestions":18,"shuffleOptions":17,"negativeMarking":19,"passScorePct":53,"maxAttempts":52,"revealAnswers":54,"allowFlagging":18,"allowBacktracking":17},7,null,70,"AFTER_SUBMIT",{"slug":6,"name":7},{"questions":51},{"allowed":17,"reason":58},"FREE",[],[61,65,69,73,77,81,85,89,93,97,100,104],{"slug":62,"name":63,"articles":64},"webdev","Webdev",159,{"slug":66,"name":67,"articles":68},"javascript","Javascript",129,{"slug":70,"name":71,"articles":72},"frontend","Frontend",90,{"slug":74,"name":75,"articles":76},"tutorial","Tutorial",63,{"slug":78,"name":79,"articles":80},"css","Css",48,{"slug":82,"name":83,"articles":84},"performance","Performance",27,{"slug":86,"name":87,"articles":88},"typescript","Typescript",23,{"slug":90,"name":91,"articles":92},"react","React",19,{"slug":94,"name":95,"articles":96},"programming","Programming",15,{"slug":98,"name":99,"articles":96},"browser","Browser",{"slug":101,"name":102,"articles":103},"node","Node",14,{"slug":105,"name":106,"articles":107},"html","Html",11,{"id":109,"slug":46,"title":110,"subtitle":52,"excerpt":111,"coverUrl":112,"locale":13,"readingMinutes":113,"publishedAt":114,"viewCount":115,"likeCount":19,"commentCount":19,"author":116,"vertical":121,"topic":122,"tags":124,"_count":129,"playground":131,"body":133,"bodyMd":273,"seo":274,"translationGroupId":277,"series":52,"podcastUrl":52,"verticalId":5,"thread":278,"assessments":280,"translations":283,"quiz":285},"01a1749f-27d5-773f-8c09-13beb3128da0","Stop Using a JS Masonry Library. CSS Grid Lanes Does It Natively.","Masonry layouts have meant a JS library or a CSS column-count hack that scrambles reading order ever since Pinterest made the look popular. CSS Grid Lanes finally does it natively — here's the real support story and how to ship it today.","\u002Fmedia\u002Fcovers\u002Fcss-grid-lanes-native-masonry-layout.png",6,"2026-10-30T05:36:15.418Z",44,{"id":117,"name":118,"username":119,"avatarUrl":52,"headline":120},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":78,"name":123},"CSS",[125,126,127,128],{"slug":78,"name":79,"color":52},{"slug":62,"name":63,"color":52},{"slug":70,"name":71,"color":52},{"slug":74,"name":75,"color":52},{"assessments":130},1,{"slug":46,"title":132},"CSS Grid Lanes — native masonry, DOM order intact",{"blocks":134,"version":130},[135,139,142,146,149,154,157,160,163,166,169,173,177,180,183,186,189,192,195,198,202,205,208,211,215,218,221,224,231,234,237,240,243,246,249,252,255,258,261,264,267],{"id":136,"html":137,"type":138},"b1","\u003Cp>Open any &quot;masonry&quot; npm package&#39;s GitHub issues and you&#39;ll find the same complaint, filed every few months in different words: items jump on resize, SSR renders everything in one column until JS hydrates, and the bundle is 15–40KB for something that is, conceptually, &quot;pack boxes into the shortest column.&quot; It&#39;s a layout problem. It has needed a JavaScript library to solve because CSS Grid — for all its power — has never been able to do it. Every row in a CSS grid has to be the same height across every column. A masonry layout is defined by \u003Cem>not\u003C\u002Fem> having that constraint.\u003C\u002Fp>","paragraph",{"id":140,"html":141,"type":138},"b2","\u003Cp>So most teams land on one of two compromises. Neither is actually masonry.\u003C\u002Fp>",{"id":143,"html":144,"text":144,"type":145,"level":31},"b3","The fix everyone reaches for first","heading",{"id":147,"html":148,"type":138},"b4","\u003Cp>The CSS-only version looks like this, and it&#39;s seductive because it needs zero JavaScript:\u003C\u002Fp>",{"id":150,"code":151,"type":152,"language":78,"highlight":153},"b5",".gallery {\n  columns: 3;\n  column-gap: 16px;\n}\n\n.gallery > * {\n  break-inside: avoid;\n  margin-bottom: 16px;\n}","code",[],{"id":155,"html":156,"type":138},"b6","\u003Cp>It renders a Pinterest-ish grid. Ship it, move on — until someone tabs through the gallery with a keyboard, or a screen reader user navigates it, and the order makes no sense. \u003Ccode>columns\u003C\u002Fcode> fills the \u003Cem>first\u003C\u002Fem> column top-to-bottom before it starts the second, so if your 12 items are numbered 1–12 in the markup, the visual layout reads \u003Cstrong>1, 2, 3, 4 down the left column, then 5, 6, 7, 8 down the middle, then 9–12 on the right\u003C\u002Fstrong> — not left-to-right the way a grid of cards normally reads, and not the order a screen reader announces it in either. Nobody notices in a quick visual QA pass. It shows up as &quot;why does the keyboard focus jump to the bottom of the page and then back to the middle&quot; three sprints later.\u003C\u002Fp>",{"id":158,"html":159,"type":138},"b7","\u003Cp>The other common fix is a JS library (\u003Ccode>masonry-layout\u003C\u002Fcode>, \u003Ccode>react-masonry-css\u003C\u002Fcode>, or rolling your own \u003Ccode>ResizeObserver\u003C\u002Fcode> + &quot;find the shortest column, append there&quot; loop). That one gets the packing right, but it pays for it: a layout pass that runs on every resize and every image load, a flash of an unstyled single column before JS hydrates, and a dependency for something that feels like it should be CSS&#39;s job.\u003C\u002Fp>",{"id":161,"html":162,"type":138},"b8","\u003Cp>It should be. As of 2026, in one browser, it finally is.\u003C\u002Fp>",{"id":164,"html":165,"text":165,"type":145,"level":31},"b9","What was actually missing",{"id":167,"html":168,"type":138},"b10","\u003Cp>CSS Grid lays out in two full passes: define the tracks (rows and columns), then place items into cells that already have a fixed size. That&#39;s precisely why Grid can&#39;t do masonry on its own — masonry \u003Cem>is\u003C\u002Fem> &quot;don&#39;t fix the row heights, just pack each item into whichever column currently has the most room.&quot; The CSS Working Group spent years on this as &quot;Grid Level 3,&quot; tried a Firefox-only \u003Ccode>grid-template-rows: masonry\u003C\u002Fcode> syntax behind a flag, and in January 2026 settled on a cleaner final design: a new \u003Ccode>display\u003C\u002Fcode> value, \u003Ccode>grid-lanes\u003C\u002Fcode> (and its inline counterpart, \u003Ccode>inline-grid-lanes\u003C\u002Fcode>), instead of overloading an existing grid property.\u003C\u002Fp>",{"id":170,"html":171,"text":172,"type":145,"level":31},"b11","The fix: \u003Ccode>display: grid-lanes\u003C\u002Fcode>","The fix: display: grid-lanes",{"id":174,"code":175,"type":152,"language":78,"highlight":176},"b12",".gallery {\n  display: grid-lanes;\n  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n  gap: 16px;\n}",[],{"id":178,"html":179,"type":138},"b13","\u003Cp>That&#39;s the whole layout. You still declare \u003Ccode>grid-template-columns\u003C\u002Fcode> exactly like ordinary Grid — fixed count, \u003Ccode>auto-fill\u003C\u002Fcode>, \u003Ccode>minmax()\u003C\u002Fcode>, all of it. The difference is what the browser does with your items: instead of requiring every row to line up across columns, it walks them \u003Cstrong>in DOM order\u003C\u002Fstrong> and drops each one into whichever lane (column) currently has the least content. That&#39;s a real improvement over the \u003Ccode>columns\u003C\u002Fcode> hack&#39;s worst case — which deterministically exhausts column 1 before column 2 even starts — but it&#39;s not a complete guarantee. Because lane heights can drift unevenly, tab order can still zigzag across lanes for some content mixes (DOM item 4 landing, say, in the lane that item 6 &quot;should&quot; occupy). The spec gives you a \u003Ccode>flow-tolerance\u003C\u002Fcode> property to dampen how far an item is allowed to jump lanes, and a full fix needs a separate, still-experimental property (\u003Ccode>reading-flow\u003C\u002Fcode>) that no browser currently wires into \u003Ccode>grid-lanes\u003C\u002Fcode>. What you get today is markup order that \u003Cem>usually\u003C\u002Fem> tracks visual order far more closely than the \u003Ccode>columns\u003C\u002Fcode> hack ever did — not a watertight promise.\u003C\u002Fp>",{"id":181,"html":182,"type":138},"b14","\u003C!-- playground:start -->",{"id":184,"html":185,"text":185,"type":145,"level":31},"b15","🎮 Try it yourself",{"id":187,"html":188,"type":138},"b16","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-grid-lanes-native-masonry-layout\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":190,"html":191,"type":138},"b17","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":193,"html":194,"type":138},"b18","\u003C!-- playground:end -->",{"id":196,"html":197,"type":138},"b19","\u003Cp>Ordinary Grid placement still works on top of it. An item can jump several lanes with the same syntax you already use:\u003C\u002Fp>",{"id":199,"code":200,"type":152,"language":78,"highlight":201},"b20",".gallery .featured {\n  grid-column: span 2;\n}",[],{"id":203,"html":204,"text":204,"type":145,"level":31},"b21","The honest catch",{"id":206,"html":207,"type":138},"b22","\u003Cp>This is the part most &quot;masonry is here!&quot; posts skip. As of this writing, \u003Cstrong>Safari is the only browser shipping \u003Ccode>display: grid-lanes\u003C\u002Fcode> unflagged\u003C\u002Fstrong> — it landed in the stable Safari 26.4 release. Chrome and Firefox both have implementations, but both ship them \u003Cstrong>disabled by default\u003C\u002Fstrong>, behind an experimental-platform-features flag. There&#39;s no date yet for either to flip that switch. If you write \u003Ccode>display: grid-lanes\u003C\u002Fcode> into production CSS today, the vast majority of your visitors get whatever your fallback declares — not masonry.\u003C\u002Fp>",{"id":209,"html":210,"type":138},"b23","\u003Cp>That&#39;s not a reason to wait. It&#39;s a reason to use \u003Ccode>@supports\u003C\u002Fcode> the way it was built for:\u003C\u002Fp>",{"id":212,"code":213,"type":152,"language":78,"highlight":214},"b24",".gallery {\n  \u002F* Fallback: plain grid, every item the same visual weight.\n     Not masonry, but DOM order stays reading order. *\u002F\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n  gap: 16px;\n}\n\n@supports (display: grid-lanes) {\n  .gallery {\n    display: grid-lanes;\n  }\n}",[],{"id":216,"html":217,"type":138},"b25","\u003Cp>Visitors on Safari 26.4+ get real masonry today. Everyone else gets a perfectly readable uniform grid instead of a broken one — not the layout you want long-term, but never a layout that embarrasses you. When Chrome and Firefox unflag it, your fallback quietly becomes dead code you can delete, with zero migration.\u003C\u002Fp>",{"id":219,"html":220,"text":220,"type":145,"level":31},"b26","When the JS library still earns its place",{"id":222,"html":223,"type":138},"b27","\u003Cp>Don&#39;t rip out a masonry library the moment you read this. Keep it if you need:\u003C\u002Fp>",{"id":225,"type":226,"items":227,"ordered":18},"b28","list",[228,229,230],"\u003Cstrong>Masonry everywhere today\u003C\u002Fstrong>, with no visually-degraded fallback acceptable on Chrome or Firefox.","\u003Cstrong>Re-flowing based on content you fetch after layout\u003C\u002Fstrong> in a way your current library already handles well (infinite scroll galleries with dynamic image dimensions).","\u003Cstrong>Fine control over packing order\u003C\u002Fstrong> beyond &quot;shortest lane wins&quot; — some libraries support column-balancing heuristics \u003Ccode>grid-lanes\u003C\u002Fcode> doesn&#39;t expose.",{"id":232,"html":233,"type":138},"b29","\u003Cp>For a new project, or the next redesign of an existing gallery, ship the \u003Ccode>@supports\u003C\u002Fcode> version above. You get the real thing where it&#39;s supported and a safe grid everywhere else, for four lines of CSS and zero kilobytes of JavaScript.\u003C\u002Fp>",{"id":235,"html":236,"type":138},"b30","\u003C!-- quiz:start -->",{"id":238,"html":239,"text":239,"type":145,"level":31},"b31","🧠 Test yourself",{"id":241,"html":242,"type":138},"b32","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-grid-lanes-native-masonry-layout\u002Fquiz\">Take the 7-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":244,"html":245,"type":138},"b33","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":247,"html":248,"type":138},"b34","\u003C!-- quiz:end -->",{"id":250,"html":251,"text":251,"type":145,"level":31},"b35","The lesson",{"id":253,"html":254,"type":138},"b36","\u003Cp>\u003Ccode>columns: N\u003C\u002Fcode> was never masonry — it was a print-style multi-column reflow that happened to \u003Cem>look\u003C\u002Fem> like masonry until you checked tab order. The JS libraries got the packing right but paid for it in bundle size and a hydration flash. \u003Ccode>display: grid-lanes\u003C\u002Fcode> is CSS finally modeling what Pinterest-style layout actually is — a placement algorithm, not a side effect — and \u003Ccode>@supports\u003C\u002Fcode> means you don&#39;t have to choose between &quot;ship it now&quot; and &quot;ship it correctly everywhere.&quot;\u003C\u002Fp>",{"id":256,"html":257,"type":138},"b37","\u003Cp>Are you going to drop \u003Ccode>display: grid-lanes\u003C\u002Fcode> into a gallery today behind \u003Ccode>@supports\u003C\u002Fcode>, or wait for Chrome and Firefox to unflag it first? Tell me which, and why, in the comments.\u003C\u002Fp>",{"id":259,"type":260},"b38","divider",{"id":262,"html":263,"type":138},"b39","\u003Cp>🚀 \u003Cstrong>Want more like this?\u003C\u002Fstrong> Every guide, playground, and quiz lives on \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">bestpractic.org\u003C\u002Fa>\u003C\u002Fstrong> — open it and \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002F\">sign up free\u003C\u002Fa>\u003C\u002Fstrong> so the next one finds you.\u003C\u002Fp>",{"id":265,"html":266,"type":138},"b40","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":268,"type":226,"items":269,"ordered":18},"b41",[270,271,272],"⭐ \u003Cstrong>GitHub\u003C\u002Fstrong> — follow me and star the projects: \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fparsajiravand\">github.com\u002Fparsajiravand\u003C\u002Fa>","💬 \u003Cstrong>Discord\u003C\u002Fstrong> — join the frontend best-practices community: \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ\">discord.gg\u002Fd9KRhuAwQ\u003C\u002Fa>","📸 \u003Cstrong>Instagram\u003C\u002Fstrong> — frontend best practices, daily: \u003Ca href=\"https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F\">@bestpractice___\u003C\u002Fa>","Open any \"masonry\" npm package's GitHub issues and you'll find the same complaint, filed every few months in different words: items jump on resize, SSR renders everything in one column until JS hydrates, and the bundle is 15–40KB for something that is, conceptually, \"pack boxes into the shortest column.\" It's a layout problem. It has needed a JavaScript library to solve because CSS Grid — for all its power — has never been able to do it. Every row in a CSS grid has to be the same height across every column. A masonry layout is defined by *not* having that constraint.\n\nSo most teams land on one of two compromises. Neither is actually masonry.\n\n## The fix everyone reaches for first\n\nThe CSS-only version looks like this, and it's seductive because it needs zero JavaScript:\n\n```css\n.gallery {\n  columns: 3;\n  column-gap: 16px;\n}\n\n.gallery > * {\n  break-inside: avoid;\n  margin-bottom: 16px;\n}\n```\n\nIt renders a Pinterest-ish grid. Ship it, move on — until someone tabs through the gallery with a keyboard, or a screen reader user navigates it, and the order makes no sense. `columns` fills the *first* column top-to-bottom before it starts the second, so if your 12 items are numbered 1–12 in the markup, the visual layout reads **1, 2, 3, 4 down the left column, then 5, 6, 7, 8 down the middle, then 9–12 on the right** — not left-to-right the way a grid of cards normally reads, and not the order a screen reader announces it in either. Nobody notices in a quick visual QA pass. It shows up as \"why does the keyboard focus jump to the bottom of the page and then back to the middle\" three sprints later.\n\nThe other common fix is a JS library (`masonry-layout`, `react-masonry-css`, or rolling your own `ResizeObserver` + \"find the shortest column, append there\" loop). That one gets the packing right, but it pays for it: a layout pass that runs on every resize and every image load, a flash of an unstyled single column before JS hydrates, and a dependency for something that feels like it should be CSS's job.\n\nIt should be. As of 2026, in one browser, it finally is.\n\n## What was actually missing\n\nCSS Grid lays out in two full passes: define the tracks (rows and columns), then place items into cells that already have a fixed size. That's precisely why Grid can't do masonry on its own — masonry *is* \"don't fix the row heights, just pack each item into whichever column currently has the most room.\" The CSS Working Group spent years on this as \"Grid Level 3,\" tried a Firefox-only `grid-template-rows: masonry` syntax behind a flag, and in January 2026 settled on a cleaner final design: a new `display` value, `grid-lanes` (and its inline counterpart, `inline-grid-lanes`), instead of overloading an existing grid property.\n\n## The fix: `display: grid-lanes`\n\n```css\n.gallery {\n  display: grid-lanes;\n  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n  gap: 16px;\n}\n```\n\nThat's the whole layout. You still declare `grid-template-columns` exactly like ordinary Grid — fixed count, `auto-fill`, `minmax()`, all of it. The difference is what the browser does with your items: instead of requiring every row to line up across columns, it walks them **in DOM order** and drops each one into whichever lane (column) currently has the least content. That's a real improvement over the `columns` hack's worst case — which deterministically exhausts column 1 before column 2 even starts — but it's not a complete guarantee. Because lane heights can drift unevenly, tab order can still zigzag across lanes for some content mixes (DOM item 4 landing, say, in the lane that item 6 \"should\" occupy). The spec gives you a `flow-tolerance` property to dampen how far an item is allowed to jump lanes, and a full fix needs a separate, still-experimental property (`reading-flow`) that no browser currently wires into `grid-lanes`. What you get today is markup order that *usually* tracks visual order far more closely than the `columns` hack ever did — not a watertight promise.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-grid-lanes-native-masonry-layout\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\nOrdinary Grid placement still works on top of it. An item can jump several lanes with the same syntax you already use:\n\n```css\n.gallery .featured {\n  grid-column: span 2;\n}\n```\n\n## The honest catch\n\nThis is the part most \"masonry is here!\" posts skip. As of this writing, **Safari is the only browser shipping `display: grid-lanes` unflagged** — it landed in the stable Safari 26.4 release. Chrome and Firefox both have implementations, but both ship them **disabled by default**, behind an experimental-platform-features flag. There's no date yet for either to flip that switch. If you write `display: grid-lanes` into production CSS today, the vast majority of your visitors get whatever your fallback declares — not masonry.\n\nThat's not a reason to wait. It's a reason to use `@supports` the way it was built for:\n\n```css\n.gallery {\n  \u002F* Fallback: plain grid, every item the same visual weight.\n     Not masonry, but DOM order stays reading order. *\u002F\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));\n  gap: 16px;\n}\n\n@supports (display: grid-lanes) {\n  .gallery {\n    display: grid-lanes;\n  }\n}\n```\n\nVisitors on Safari 26.4+ get real masonry today. Everyone else gets a perfectly readable uniform grid instead of a broken one — not the layout you want long-term, but never a layout that embarrasses you. When Chrome and Firefox unflag it, your fallback quietly becomes dead code you can delete, with zero migration.\n\n## When the JS library still earns its place\n\nDon't rip out a masonry library the moment you read this. Keep it if you need:\n\n- **Masonry everywhere today**, with no visually-degraded fallback acceptable on Chrome or Firefox.\n- **Re-flowing based on content you fetch after layout** in a way your current library already handles well (infinite scroll galleries with dynamic image dimensions).\n- **Fine control over packing order** beyond \"shortest lane wins\" — some libraries support column-balancing heuristics `grid-lanes` doesn't expose.\n\nFor a new project, or the next redesign of an existing gallery, ship the `@supports` version above. You get the real thing where it's supported and a safe grid everywhere else, for four lines of CSS and zero kilobytes of JavaScript.\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 7-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-grid-lanes-native-masonry-layout\u002Fquiz)**\n\n_Instant feedback, a hint on every question, and an explanation for each answer — right or wrong._\n\n\u003C!-- quiz:end -->\n\n## The lesson\n\n`columns: N` was never masonry — it was a print-style multi-column reflow that happened to *look* like masonry until you checked tab order. The JS libraries got the packing right but paid for it in bundle size and a hydration flash. `display: grid-lanes` is CSS finally modeling what Pinterest-style layout actually is — a placement algorithm, not a side effect — and `@supports` means you don't have to choose between \"ship it now\" and \"ship it correctly everywhere.\"\n\nAre you going to drop `display: grid-lanes` into a gallery today behind `@supports`, or wait for Chrome and Firefox to unflag it first? Tell me which, and why, in the comments.\n\n---\n\n🚀 **Want more like this?** Every guide, playground, and quiz lives on **[bestpractic.org](https:\u002F\u002Fbestpractic.org\u002F)** — open it and **[sign up free](https:\u002F\u002Fbestpractic.org\u002F)** so the next one finds you.\n\n*Thanks for reading! Let's stay connected:*\n\n- ⭐ **GitHub** — follow me and star the projects: [github.com\u002Fparsajiravand](https:\u002F\u002Fgithub.com\u002Fparsajiravand)\n- 💬 **Discord** — join the frontend best-practices community: [discord.gg\u002Fd9KRhuAwQ](https:\u002F\u002Fdiscord.gg\u002Fd9KRhuAwQ)\n- 📸 **Instagram** — frontend best practices, daily: [@bestpractice___](https:\u002F\u002Fwww.instagram.com\u002Fbestpractice___\u002F)",{"title":110,"canonical":275,"description":276},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-grid-lanes-native-masonry-layout","Masonry layouts have meant a JS library or a CSS column-count hack that scrambles reading order ever since Pinterest made the look popular. CSS Grid Lanes finally does it natively ","01a1749f-27d5-773f-8c09-148bb3ce82a0",{"id":279,"locked":18},"01a1749f-27fb-724c-ad8f-151db8df6b71",[281],{"id":45,"slug":46,"title":48,"_count":282},{"questions":51},[284],{"locale":13,"slug":46},{"id":45,"slug":46,"title":48,"_count":286,"questionCount":51},{"questions":51},[]]