[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"verticals":3,"article-css-clamp-fluid-typography":44,"search-suggestions":224,"related-css-clamp-fluid-typography":262,"code:css:true:pdc6le":390,"code:css:true:1b5syrq":391,"code:css:true:1f5afuh":392,"code:css:true:jg9593":393,"comments-01a0042a-852e-7338-83ed-a1f581d6c501":394},[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,"title":47,"subtitle":48,"excerpt":49,"coverUrl":50,"locale":13,"readingMinutes":51,"publishedAt":52,"viewCount":53,"likeCount":19,"commentCount":19,"author":54,"vertical":59,"topic":60,"tags":63,"_count":75,"playground":77,"body":79,"bodyMd":208,"seo":209,"translationGroupId":211,"thread":212,"assessments":214,"translations":220,"quiz":222},"01a0042a-852e-7338-83ed-a1f581d6c501","css-clamp-fluid-typography","Stop Writing Media Queries for Font Size",null,"A design system audit found five breakpoints for one heading. clamp() replaces all of them with one line that never jumps.","\u002Fmedia\u002Fcovers\u002Fcss-clamp-fluid-typography.png",4,"2026-08-19T06:51:54.290Z",67,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},"019fe637-3c25-7088-9034-39c9f15dc3c8","Parsa Jiravand","parsa","Frontend engineer · building bestpractic",{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},"css","CSS",[64,66,69,72],{"slug":61,"name":65,"color":48},"Css",{"slug":67,"name":68,"color":48},"webdev","Webdev",{"slug":70,"name":71,"color":48},"frontend","Frontend",{"slug":73,"name":74,"color":48},"accessibility","Accessibility",{"assessments":76},1,{"slug":46,"title":78},"clamp() fluid type — interactive playground",{"blocks":80,"version":76},[81,85,90,93,96,101,104,108,111,114,118,121,125,128,131,134,137,140,143,146,149,153,156,160,163,166,169,172,175,178,181,184,187,190,193,196,199],{"id":82,"html":83,"type":84},"b1","\u003Cp>A teammate opened a PR titled &quot;fix hero heading on small screens.&quot; The diff added a media query. Mine, reviewing it, found four more already in that file — one per breakpoint, added over eighteen months by four different people, each one patching the width the last person didn&#39;t think of:\u003C\u002Fp>","paragraph",{"id":86,"code":87,"type":88,"language":61,"highlight":89},"b2",".hero-heading {\n  font-size: 3rem;\n}\n\n@media (max-width: 1200px) {\n  .hero-heading { font-size: 2.5rem; }\n}\n\n@media (max-width: 992px) {\n  .hero-heading { font-size: 2.25rem; }\n}\n\n@media (max-width: 768px) {\n  .hero-heading { font-size: 1.75rem; }\n}\n\n@media (max-width: 480px) {\n  .hero-heading { font-size: 1.5rem; }\n}","code",[],{"id":91,"html":92,"type":84},"b3","\u003Cp>Five rules to make one number — the font size of one heading — track the width of the screen it&#39;s on. And it still didn&#39;t work everywhere: resize the window to 850px and the heading is stuck at the 992px value, a little too big for the space it actually has. Every gap between breakpoints is a size nobody chose, it&#39;s just whatever the nearest rule left behind.\u003C\u002Fp>",{"id":94,"html":95,"type":84},"b4","\u003Cp>Here&#39;s the part that stings: none of this has been necessary since 2020.\u003C\u002Fp>",{"id":97,"html":98,"text":99,"type":100,"level":31},"b5","The fix that isn&#39;t a breakpoint at all","The fix that isn't a breakpoint at all","heading",{"id":102,"html":103,"type":84},"b6","\u003Cp>\u003Ccode>clamp()\u003C\u002Fcode> takes three values — a minimum, a preferred value, and a maximum — and returns whichever one the situation calls for:\u003C\u002Fp>",{"id":105,"code":106,"type":88,"language":61,"highlight":107},"b7",".hero-heading {\n  font-size: clamp(1.5rem, 1rem + 2vw, 3rem);\n}",[],{"id":109,"html":110,"type":84},"b8","\u003Cp>Read it as a sentence: \u003Cem>never smaller than 1.5rem, never bigger than 3rem, and in between, scale with the viewport.\u003C\u002Fem> The five media queries above collapse into that one line — and unlike them, it doesn&#39;t have gaps. \u003Ccode>clamp()\u003C\u002Fcode> recalculates the size continuously, every pixel the viewport moves, so there&#39;s no &quot;850px value&quot; that got left behind. It&#39;s a formula, not a lookup table.\u003C\u002Fp>",{"id":112,"html":113,"type":84},"b9","\u003Cp>The middle value is where the &quot;preferred&quot; size lives, and it&#39;s \u003Ccode>1rem + 2vw\u003C\u002Fcode> — a fixed part plus a viewport-relative part — not just \u003Ccode>4vw\u003C\u002Fcode> on its own. That&#39;s not decoration. It&#39;s the one part of this pattern worth getting right, because the shortcut version quietly breaks something.\u003C\u002Fp>",{"id":115,"html":116,"text":117,"type":100,"level":31},"b10","The version that looks fine and isn&#39;t","The version that looks fine and isn't",{"id":119,"html":120,"type":84},"b11","\u003Cp>The formula you&#39;ll see in half the blog posts about this is:\u003C\u002Fp>",{"id":122,"code":123,"type":88,"language":61,"highlight":124},"b12","font-size: clamp(1.5rem, 4vw, 3rem);",[],{"id":126,"html":127,"type":84},"b13","\u003Cp>Simpler, and it scales exactly the same way visually. Try it in the playground below and you won&#39;t see a difference — until you go into your browser&#39;s settings and bump the default font size up, the way a low-vision reader routinely does. The \u003Ccode>4vw\u003C\u002Fcode>-only heading doesn&#39;t move. Not a little — not at all.\u003C\u002Fp>",{"id":129,"html":130,"type":84},"b14","\u003Cp>\u003Ccode>vw\u003C\u002Fcode> is a percentage of the viewport&#39;s width. It has no relationship to the page&#39;s root font size, so a user&#39;s default-font-size preference — a real accessibility setting, not an edge case — has nothing to attach to. \u003Ccode>rem\u003C\u002Fcode> does have that relationship: it&#39;s relative to the root element&#39;s font size, which is exactly what that setting changes. Mix a \u003Ccode>rem\u003C\u002Fcode> term into the preferred value and the heading grows when the user&#39;s preference does. Drop the \u003Ccode>rem\u003C\u002Fcode> term and you&#39;ve built a heading that&#39;s fluid for you, in your browser, at your settings, and static for the one person turning a knob specifically to make it bigger.\u003C\u002Fp>",{"id":132,"html":133,"type":84},"b15","\u003Cp>The fix costs nothing: \u003Ccode>1rem + 2vw\u003C\u002Fcode> instead of \u003Ccode>4vw\u003C\u002Fcode>. Same visual curve, but now it answers to two inputs instead of one.\u003C\u002Fp>",{"id":135,"html":136,"type":84},"b16","\u003C!-- playground:start -->",{"id":138,"html":139,"text":139,"type":100,"level":31},"b17","🎮 Try it yourself",{"id":141,"html":142,"type":84},"b18","\u003Cp>\u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-clamp-fluid-typography\u002Fplayground\">▶️ Open the interactive playground →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":144,"html":145,"type":84},"b19","\u003Cp>\u003Cem>Runs right in your browser — poke at it and watch the concept react live.\u003C\u002Fem>\u003C\u002Fp>",{"id":147,"html":148,"type":84},"b20","\u003C!-- playground:end -->",{"id":150,"html":151,"text":152,"type":100,"level":31},"b21","It&#39;s not just font-size","It's not just font-size",{"id":154,"html":155,"type":84},"b22","\u003Cp>Once \u003Ccode>clamp()\u003C\u002Fcode> clicks for type, the same three-value shape solves the same problem everywhere else a design system hardcodes a size per breakpoint: section padding, a hero&#39;s \u003Ccode>min-height\u003C\u002Fcode>, a sidebar&#39;s \u003Ccode>width\u003C\u002Fcode>, the \u003Ccode>max-width\u003C\u002Fcode> that controls line length in a paragraph. Anywhere the honest answer to &quot;what size should this be&quot; is &quot;it depends on the viewport, within limits&quot; — that&#39;s a \u003Ccode>clamp()\u003C\u002Fcode>, not a set of \u003Ccode>@media\u003C\u002Fcode> rules:\u003C\u002Fp>",{"id":157,"code":158,"type":88,"language":61,"highlight":159},"b23",".container {\n  padding-inline: clamp(1rem, 5vw, 4rem);\n}\n\n.article {\n  max-width: clamp(20rem, 60ch, 65rem);\n}",[],{"id":161,"html":162,"type":84},"b24","\u003Cp>The \u003Ccode>article\u003C\u002Fcode> line is worth a second look: mixing \u003Ccode>ch\u003C\u002Fcode> (a character-width unit) into the preferred value gives you a paragraph that keeps a readable line length as it grows, instead of one that just gets wider forever on an ultrawide monitor.\u003C\u002Fp>",{"id":164,"html":165,"text":165,"type":100,"level":31},"b25","Where media queries still win",{"id":167,"html":168,"type":84},"b26","\u003Cp>\u003Ccode>clamp()\u003C\u002Fcode> interpolates a \u003Cem>value\u003C\u002Fem>. It can&#39;t change layout — it won&#39;t swap a two-column grid to one column, hide a sidebar, or reorder flex items, because those are structural decisions, not points on a number line. If the real requirement is &quot;this should look and behave differently past a width,&quot; that&#39;s still a media query&#39;s job, and no amount of \u003Ccode>clamp()\u003C\u002Fcode> cleverness replaces it. The two aren&#39;t competing; \u003Ccode>clamp()\u003C\u002Fcode> just took over the part of the job — continuous scaling — that media queries were only ever approximating with a staircase.\u003C\u002Fp>",{"id":170,"html":171,"text":171,"type":100,"level":31},"b27","The one-line version",{"id":173,"html":174,"type":84},"b28","\u003Cp>Five media queries, four contributors, and gaps between every breakpoint were solving a problem \u003Ccode>clamp(MIN, PREFERRED, MAX)\u003C\u002Fcode> has handled in one line since 2020 — as long as the preferred value mixes a \u003Ccode>rem\u003C\u002Fcode> with the \u003Ccode>vw\u003C\u002Fcode>, so it still answers to the one setting that matters most.\u003C\u002Fp>",{"id":176,"html":177,"type":84},"b29","\u003Cp>Open your own stylesheet and search for \u003Ccode>@media\u003C\u002Fcode> rules that only ever change a \u003Ccode>font-size\u003C\u002Fcode> or a \u003Ccode>padding\u003C\u002Fcode>. How many of them are a \u003Ccode>clamp()\u003C\u002Fcode> waiting to happen?\u003C\u002Fp>",{"id":179,"html":180,"type":84},"b30","\u003C!-- quiz:start -->",{"id":182,"html":183,"text":183,"type":100,"level":31},"b31","🧠 Test yourself",{"id":185,"html":186,"type":84},"b32","\u003Cp>Think it clicked? \u003Cstrong>\u003Ca href=\"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-clamp-fluid-typography\u002Fquiz\">Take the 8-question quiz →\u003C\u002Fa>\u003C\u002Fstrong>\u003C\u002Fp>",{"id":188,"html":189,"type":84},"b33","\u003Cp>\u003Cem>Instant feedback, a hint on every question, and an explanation for each answer — right or wrong.\u003C\u002Fem>\u003C\u002Fp>",{"id":191,"html":192,"type":84},"b34","\u003C!-- quiz:end -->",{"id":194,"type":195},"b35","divider",{"id":197,"html":198,"type":84},"b36","\u003Cp>\u003Cem>Thanks for reading! Let&#39;s stay connected:\u003C\u002Fem>\u003C\u002Fp>",{"id":200,"type":201,"items":202,"ordered":18},"b37","list",[203,204,205,206,207],"⭐ \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>","💼 \u003Cstrong>LinkedIn\u003C\u002Fstrong> — \u003Ca href=\"https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F\">linkedin.com\u002Fin\u002Fparsa-jiravand\u003C\u002Fa>","✉️ \u003Cstrong>Email\u003C\u002Fstrong> (work &amp; contract inquiries): \u003Ca href=\"mailto:bestpractice2026@gmail.com\">bestpractice2026@gmail.com\u003C\u002Fa>","A teammate opened a PR titled \"fix hero heading on small screens.\" The diff added a media query. Mine, reviewing it, found four more already in that file — one per breakpoint, added over eighteen months by four different people, each one patching the width the last person didn't think of:\n\n```css\n.hero-heading {\n  font-size: 3rem;\n}\n\n@media (max-width: 1200px) {\n  .hero-heading { font-size: 2.5rem; }\n}\n\n@media (max-width: 992px) {\n  .hero-heading { font-size: 2.25rem; }\n}\n\n@media (max-width: 768px) {\n  .hero-heading { font-size: 1.75rem; }\n}\n\n@media (max-width: 480px) {\n  .hero-heading { font-size: 1.5rem; }\n}\n```\n\nFive rules to make one number — the font size of one heading — track the width of the screen it's on. And it still didn't work everywhere: resize the window to 850px and the heading is stuck at the 992px value, a little too big for the space it actually has. Every gap between breakpoints is a size nobody chose, it's just whatever the nearest rule left behind.\n\nHere's the part that stings: none of this has been necessary since 2020.\n\n## The fix that isn't a breakpoint at all\n\n`clamp()` takes three values — a minimum, a preferred value, and a maximum — and returns whichever one the situation calls for:\n\n```css\n.hero-heading {\n  font-size: clamp(1.5rem, 1rem + 2vw, 3rem);\n}\n```\n\nRead it as a sentence: *never smaller than 1.5rem, never bigger than 3rem, and in between, scale with the viewport.* The five media queries above collapse into that one line — and unlike them, it doesn't have gaps. `clamp()` recalculates the size continuously, every pixel the viewport moves, so there's no \"850px value\" that got left behind. It's a formula, not a lookup table.\n\nThe middle value is where the \"preferred\" size lives, and it's `1rem + 2vw` — a fixed part plus a viewport-relative part — not just `4vw` on its own. That's not decoration. It's the one part of this pattern worth getting right, because the shortcut version quietly breaks something.\n\n## The version that looks fine and isn't\n\nThe formula you'll see in half the blog posts about this is:\n\n```css\nfont-size: clamp(1.5rem, 4vw, 3rem);\n```\n\nSimpler, and it scales exactly the same way visually. Try it in the playground below and you won't see a difference — until you go into your browser's settings and bump the default font size up, the way a low-vision reader routinely does. The `4vw`-only heading doesn't move. Not a little — not at all.\n\n`vw` is a percentage of the viewport's width. It has no relationship to the page's root font size, so a user's default-font-size preference — a real accessibility setting, not an edge case — has nothing to attach to. `rem` does have that relationship: it's relative to the root element's font size, which is exactly what that setting changes. Mix a `rem` term into the preferred value and the heading grows when the user's preference does. Drop the `rem` term and you've built a heading that's fluid for you, in your browser, at your settings, and static for the one person turning a knob specifically to make it bigger.\n\nThe fix costs nothing: `1rem + 2vw` instead of `4vw`. Same visual curve, but now it answers to two inputs instead of one.\n\n\u003C!-- playground:start -->\n\n## 🎮 Try it yourself\n\n**[▶️ Open the interactive playground →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-clamp-fluid-typography\u002Fplayground)**\n\n_Runs right in your browser — poke at it and watch the concept react live._\n\n\u003C!-- playground:end -->\n\n## It's not just font-size\n\nOnce `clamp()` clicks for type, the same three-value shape solves the same problem everywhere else a design system hardcodes a size per breakpoint: section padding, a hero's `min-height`, a sidebar's `width`, the `max-width` that controls line length in a paragraph. Anywhere the honest answer to \"what size should this be\" is \"it depends on the viewport, within limits\" — that's a `clamp()`, not a set of `@media` rules:\n\n```css\n.container {\n  padding-inline: clamp(1rem, 5vw, 4rem);\n}\n\n.article {\n  max-width: clamp(20rem, 60ch, 65rem);\n}\n```\n\nThe `article` line is worth a second look: mixing `ch` (a character-width unit) into the preferred value gives you a paragraph that keeps a readable line length as it grows, instead of one that just gets wider forever on an ultrawide monitor.\n\n## Where media queries still win\n\n`clamp()` interpolates a *value*. It can't change layout — it won't swap a two-column grid to one column, hide a sidebar, or reorder flex items, because those are structural decisions, not points on a number line. If the real requirement is \"this should look and behave differently past a width,\" that's still a media query's job, and no amount of `clamp()` cleverness replaces it. The two aren't competing; `clamp()` just took over the part of the job — continuous scaling — that media queries were only ever approximating with a staircase.\n\n## The one-line version\n\nFive media queries, four contributors, and gaps between every breakpoint were solving a problem `clamp(MIN, PREFERRED, MAX)` has handled in one line since 2020 — as long as the preferred value mixes a `rem` with the `vw`, so it still answers to the one setting that matters most.\n\nOpen your own stylesheet and search for `@media` rules that only ever change a `font-size` or a `padding`. How many of them are a `clamp()` waiting to happen?\n\n\u003C!-- quiz:start -->\n\n## 🧠 Test yourself\n\nThink it clicked? **[Take the 8-question quiz →](https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-clamp-fluid-typography\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---\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)\n- 💼 **LinkedIn** — [linkedin.com\u002Fin\u002Fparsa-jiravand](https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Fparsa-jiravand\u002F)\n- ✉️ **Email** (work & contract inquiries): [bestpractice2026@gmail.com](mailto:bestpractice2026@gmail.com)",{"title":47,"canonical":210,"description":49},"https:\u002F\u002Fbestpractic.org\u002Fblog\u002Fcss-clamp-fluid-typography","01a0042a-852f-729c-a65b-250c5e3a3aff",{"id":213,"locked":18},"01a0042a-8583-77a1-8526-37819a33c542",[215],{"id":216,"slug":46,"title":217,"_count":218},"01a0042a-85ad-75ae-bd1f-c727da9a8f79","clamp() and fluid sizing",{"questions":219},8,[221],{"locale":13,"slug":46},{"id":216,"slug":46,"title":217,"_count":223,"questionCount":219},{"questions":219},[225,227,229,233,235,239,242,246,250,253,256,259],{"slug":67,"name":68,"articles":226},58,{"slug":70,"name":71,"articles":228},52,{"slug":230,"name":231,"articles":232},"javascript","Javascript",50,{"slug":61,"name":65,"articles":234},23,{"slug":236,"name":237,"articles":238},"typescript","Typescript",10,{"slug":240,"name":241,"articles":219},"performance","Performance",{"slug":243,"name":244,"articles":245},"grammar","Grammar",6,{"slug":247,"name":248,"articles":249},"react","React",5,{"slug":251,"name":252,"articles":51},"tutorial","Tutorial",{"slug":254,"name":255,"articles":51},"node","Node",{"slug":257,"name":258,"articles":43},"ai","Ai",{"slug":260,"name":261,"articles":43},"html","Html",{"items":263,"meta":388},[264,276,294,312,332,350,370],{"id":45,"slug":46,"title":47,"subtitle":48,"excerpt":49,"coverUrl":50,"locale":13,"readingMinutes":51,"publishedAt":52,"viewCount":265,"likeCount":19,"commentCount":19,"author":266,"vertical":267,"topic":268,"tags":269,"_count":274,"playground":275,"hasQuiz":17,"hasPlayground":17},68,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[270,271,272,273],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":73,"name":74,"color":48},{"assessments":76},{"slug":46},{"id":277,"slug":278,"title":279,"subtitle":48,"excerpt":280,"coverUrl":281,"locale":13,"readingMinutes":51,"publishedAt":282,"viewCount":283,"likeCount":19,"commentCount":19,"author":284,"vertical":285,"topic":286,"tags":287,"_count":292,"playground":293,"hasQuiz":17,"hasPlayground":17},"019fff35-4908-727e-b7a3-dafd1ada4784","css-scroll-snap-native-carousel","I Ripped Out a Carousel Library. CSS Replaced It.","A scroll listener, a debounce, and 200 lines of carousel-library glue code — replaced by three CSS properties that snap smoother than any of it did.","\u002Fmedia\u002Fcovers\u002Fcss-scroll-snap-native-carousel.png","2026-08-18T06:50:52.267Z",184,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[288,289,290,291],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":251,"name":252,"color":48},{"assessments":76},{"slug":278},{"id":295,"slug":296,"title":297,"subtitle":48,"excerpt":298,"coverUrl":299,"locale":13,"readingMinutes":51,"publishedAt":300,"viewCount":301,"likeCount":19,"commentCount":19,"author":302,"vertical":303,"topic":304,"tags":305,"_count":310,"playground":311,"hasQuiz":17,"hasPlayground":17},"019ffa10-eeed-707d-9b50-7d83664c7a9a","css-trigonometric-functions-radial-layout","Stop Writing Math.cos() in a Resize Listener","CSS learned trigonometry. Here's the radial menu that used to need a resize listener — and doesn't anymore.","\u002Fmedia\u002Fcovers\u002Fcss-trigonometric-functions-radial-layout.png","2026-08-17T07:03:57.776Z",319,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[306,307,308,309],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":230,"name":231,"color":48},{"slug":70,"name":71,"color":48},{"assessments":76},{"slug":296},{"id":313,"slug":314,"title":315,"subtitle":48,"excerpt":316,"coverUrl":317,"locale":13,"readingMinutes":245,"publishedAt":318,"viewCount":319,"likeCount":19,"commentCount":19,"author":320,"vertical":321,"topic":322,"tags":323,"_count":330,"playground":331,"hasQuiz":17,"hasPlayground":17},"019ff73a-ed77-732e-a13f-8be6d6939332","calc-size-animate-to-auto","I Can Finally Delete My max-height: 9999px Animation Hack","CSS transitions have never been able to animate to height: auto, because auto isn't a number the engine can interpolate. calc-size() and interpolate-size finally give it real numbers — no JavaScript, no magic-number ceiling.","\u002Fmedia\u002Fcovers\u002Fcalc-size-animate-to-auto.png","2026-08-16T06:46:49.217Z",284,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[324,325,326,327],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":328,"name":329,"color":48},"animation","Animation",{"assessments":76},{"slug":314},{"id":333,"slug":334,"title":335,"subtitle":48,"excerpt":336,"coverUrl":337,"locale":13,"readingMinutes":51,"publishedAt":338,"viewCount":339,"likeCount":19,"commentCount":19,"author":340,"vertical":341,"topic":342,"tags":343,"_count":348,"playground":349,"hasQuiz":17,"hasPlayground":17},"019ff19b-f763-70e0-abdf-eded59c8e69a","overscroll-behavior-scroll-containment","You're blocking touchmove events to contain scroll. `overscroll-behavior` does it natively.","When a scrollable container hits its edge, the page behind it starts scrolling too. Developers block this with JavaScript event handlers or body overflow tricks. overscroll-behavior is the CSS property that turns off scroll chaining in one line.","\u002Fmedia\u002Fcovers\u002Foverscroll-behavior-scroll-containment.png","2026-08-12T07:38:53.786Z",363,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[344,345,346,347],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":230,"name":231,"color":48},{"assessments":76},{"slug":334},{"id":351,"slug":352,"title":353,"subtitle":48,"excerpt":354,"coverUrl":355,"locale":13,"readingMinutes":51,"publishedAt":356,"viewCount":357,"likeCount":19,"commentCount":19,"author":358,"vertical":359,"topic":360,"tags":361,"_count":368,"playground":369,"hasQuiz":17,"hasPlayground":17},"019fe660-e5d0-756a-9ae2-20c6ff4c2f48","css-style-queries-react-to-custom-properties","Container queries can check more than size — style queries let components read custom property values","Size queries react to container width. Style queries react to CSS custom property values on a container ancestor — enabling component-level theming and variant switching in pure CSS, no JavaScript involved.","\u002Fmedia\u002Fcovers\u002Fcss-style-queries-react-to-custom-properties.png","2026-08-06T08:44:20.136Z",178,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[362,363,364,365],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":70,"name":71,"color":48},{"slug":366,"name":367,"color":48},"components","Components",{"assessments":76},{"slug":352},{"id":371,"slug":372,"title":373,"subtitle":48,"excerpt":374,"coverUrl":375,"locale":13,"readingMinutes":249,"publishedAt":376,"viewCount":377,"likeCount":19,"commentCount":19,"author":378,"vertical":379,"topic":380,"tags":381,"_count":386,"playground":387,"hasQuiz":17,"hasPlayground":17},"019fe660-d6d5-7099-89bb-af60e48fcb28","content-visibility-skip-offscreen-rendering","Your browser renders everything, even what you can't see — `content-visibility: auto` fixes that","Browsers lay out and paint the entire page on load, including the 80% below the fold. `content-visibility: auto` tells the browser to skip that work for off-screen elements — and it's Baseline 2024.","\u002Fmedia\u002Fcovers\u002Fcontent-visibility-skip-offscreen-rendering.png","2026-08-04T08:44:59.227Z",391,{"id":55,"name":56,"username":57,"avatarUrl":48,"headline":58},{"slug":6,"name":7,"accentFrom":10,"accentTo":11},{"slug":61,"name":62},[382,383,384,385],{"slug":61,"name":65,"color":48},{"slug":67,"name":68,"color":48},{"slug":240,"name":241,"color":48},{"slug":70,"name":71,"color":48},{"assessments":76},{"slug":372},{"page":76,"perPage":389,"total":234,"totalPages":51},7,"\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003Cdiv>8\u003C\u002Fdiv>\u003Cdiv>9\u003C\u002Fdiv>\u003Cdiv>10\u003C\u002Fdiv>\u003Cdiv>11\u003C\u002Fdiv>\u003Cdiv>12\u003C\u002Fdiv>\u003Cdiv>13\u003C\u002Fdiv>\u003Cdiv>14\u003C\u002Fdiv>\u003Cdiv>15\u003C\u002Fdiv>\u003Cdiv>16\u003C\u002Fdiv>\u003Cdiv>17\u003C\u002Fdiv>\u003Cdiv>18\u003C\u002Fdiv>\u003Cdiv>19\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">3\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">@media\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">1200\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">2.5\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">@media\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">992\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">2.25\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">@media\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">768\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">1.75\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-kwd\">@media\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-kwd\">max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">480\u003C\u002Fspan>\u003Cspan class=\"shj-var\">px\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan> \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-num\">1.5\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>; \u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">.hero-heading\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">clamp\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">1.5\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">1\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan> + \u003Cspan class=\"shj-num\">2\u003C\u002Fspan>vw, \u003Cspan class=\"shj-num\">3\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-oneline\" data-lang=\"css\">\u003Cspan class=\"shj-var\">font-size\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">clamp\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">1.5\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">4\u003C\u002Fspan>vw, \u003Cspan class=\"shj-num\">3\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\u003C\u002Fdiv>","\u003Cdiv class=\"shj shj-lang-css shj-multiline\" data-lang=\"css\">\u003Cdiv class=\"shj-scroll\">\u003Cdiv class=\"shj-numbers\">\u003Cdiv>1\u003C\u002Fdiv>\u003Cdiv>2\u003C\u002Fdiv>\u003Cdiv>3\u003C\u002Fdiv>\u003Cdiv>4\u003C\u002Fdiv>\u003Cdiv>5\u003C\u002Fdiv>\u003Cdiv>6\u003C\u002Fdiv>\u003Cdiv>7\u003C\u002Fdiv>\u003C\u002Fdiv>\u003Cdiv class=\"shj-code\">\u003Cspan class=\"shj-var\">.container\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">padding-inline\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">clamp\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">1\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">5\u003C\u002Fspan>vw, \u003Cspan class=\"shj-num\">4\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\n\n\u003Cspan class=\"shj-var\">.article\u003C\u002Fspan> \u003Cspan class=\"shj-bracket\">{\u003C\u002Fspan>\n  \u003Cspan class=\"shj-var\">max-width\u003C\u002Fspan>: \u003Cspan class=\"shj-func\">clamp\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">(\u003C\u002Fspan>\u003Cspan class=\"shj-num\">20\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">60\u003C\u002Fspan>\u003Cspan class=\"shj-var\">ch\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>, \u003Cspan class=\"shj-num\">65\u003C\u002Fspan>\u003Cspan class=\"shj-var\">rem\u003C\u002Fspan>\u003Cspan class=\"shj-num\">\u003C\u002Fspan>\u003Cspan class=\"shj-bracket\">)\u003C\u002Fspan>;\n\u003Cspan class=\"shj-bracket\">}\u003C\u002Fspan>\u003C\u002Fdiv>\u003C\u002Fdiv>\u003C\u002Fdiv>",{"locked":18,"total":19,"comments":395},[]]