<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lauri Lännenmäki</title>
    <description>The latest articles on DEV Community by Lauri Lännenmäki (@laurilllll).</description>
    <link>https://dev.to/laurilllll</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F378290%2F11b59b59-9c72-401f-82fe-a64c33d52b25.jpg</url>
      <title>DEV Community: Lauri Lännenmäki</title>
      <link>https://dev.to/laurilllll</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/laurilllll"/>
    <language>en</language>
    <item>
      <title>HTML vs React vs Framer: which website template edition should you buy?</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Mon, 05 Oct 2026 10:14:55 +0000</pubDate>
      <link>https://dev.to/laurilllll/html-vs-react-vs-framer-which-website-template-edition-should-you-buy-3o02</link>
      <guid>https://dev.to/laurilllll/html-vs-react-vs-framer-which-website-template-edition-should-you-buy-3o02</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://no-code.supply/blog/html-vs-react-vs-framer-templates/" rel="noopener noreferrer"&gt;no-code.supply&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every no-code.supply template comes as &lt;strong&gt;HTML&lt;/strong&gt; and &lt;strong&gt;React&lt;/strong&gt;. Three of them (Oda, Signal and Tender) also come as &lt;strong&gt;Framer&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML&lt;/strong&gt;: plain files, no build step, goes on any host. The easiest edition to hand to an AI agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt;: a Next.js project. Pick it if you'll keep building on the site, or you already live in React.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Framer&lt;/strong&gt;: a remix link. Pick it if you or your client edit in Framer's visual editor, by hand or with Framer Agent. You get no source files.&lt;/li&gt;
&lt;li&gt;Unsure? Get the &lt;strong&gt;Bundle&lt;/strong&gt; (HTML + React) and decide later.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://no-code.supply/" rel="noopener noreferrer"&gt;Browse the templates&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why this post exists
&lt;/h2&gt;

&lt;p&gt;I get the same question a lot: "Which edition should I buy?" The honest answer is that none of them is better. They're the same design, built for different ways of working.&lt;/p&gt;

&lt;p&gt;So here's what's in each one, who it fits, and where it will annoy you. I make these templates, so I know the weak spots. Let's dig in!&lt;/p&gt;




&lt;h2&gt;
  
  
  The three editions at a glance
&lt;/h2&gt;

&lt;p&gt;The design, the copy and the sections are the same in every edition. What changes is what you get to work with.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;HTML&lt;/th&gt;
&lt;th&gt;React&lt;/th&gt;
&lt;th&gt;Framer&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;What you download&lt;/td&gt;
&lt;td&gt;A folder of static files&lt;/td&gt;
&lt;td&gt;A Next.js project&lt;/td&gt;
&lt;td&gt;A remix link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Build step&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;npm install&lt;/code&gt;, &lt;code&gt;npm run dev&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;None, it's Framer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where it runs&lt;/td&gt;
&lt;td&gt;Any static host, or straight from disk&lt;/td&gt;
&lt;td&gt;Vercel, Netlify or any static host&lt;/td&gt;
&lt;td&gt;Framer hosting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You edit it in&lt;/td&gt;
&lt;td&gt;Any code editor or AI agent&lt;/td&gt;
&lt;td&gt;Any code editor or AI agent&lt;/td&gt;
&lt;td&gt;Framer's visual editor, by hand or with Framer Agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Source files&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No, it stays a Framer project&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Available for&lt;/td&gt;
&lt;td&gt;Every template&lt;/td&gt;
&lt;td&gt;Every template&lt;/td&gt;
&lt;td&gt;Oda, Signal, Tender&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  HTML: just files
&lt;/h2&gt;

&lt;p&gt;The HTML edition is plain HTML, CSS and JavaScript. Unzip it, double-click &lt;code&gt;index.html&lt;/code&gt;, and the site opens. No accounts, no plugins, no framework.&lt;/p&gt;

&lt;p&gt;In the zip: &lt;code&gt;index.html&lt;/code&gt;, an &lt;code&gt;assets&lt;/code&gt; folder with the CSS and JS, a &lt;code&gt;404.html&lt;/code&gt;, a privacy page and the usual extras (&lt;code&gt;robots.txt&lt;/code&gt;, a web manifest). Plus a &lt;code&gt;README.md&lt;/code&gt;, a &lt;code&gt;DESIGN.md&lt;/code&gt; and an &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's for you if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You want the least amount of moving parts. Edit a file, refresh the page.&lt;/li&gt;
&lt;li&gt;You're putting it on a cheap or odd host: Netlify, Vercel, GitHub Pages, shared hosting, an S3 bucket.&lt;/li&gt;
&lt;li&gt;You want your AI coding agent to do the editing. There's nothing to install and nothing to break, and &lt;a href="https://no-code.supply/blog/how-to-write-agents-md/" rel="noopener noreferrer"&gt;the &lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/a&gt; tells it the rules.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No components or templating. If you add ten pages, you'll copy the header ten times.&lt;/li&gt;
&lt;li&gt;No CMS. Content lives in the HTML.&lt;/li&gt;
&lt;li&gt;Growing it into an app means switching to something else.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every one of mine is built so it still works opened from disk, with no build step and no CDN. That's a rule, not an accident.&lt;/p&gt;




&lt;h2&gt;
  
  
  React: a project you can grow
&lt;/h2&gt;

&lt;p&gt;The React edition is a Next.js 16 project with React 19, Tailwind 4 and Motion. It's set up as a static export. All the copy lives in one content file, so changing the words doesn't mean hunting through components.&lt;/p&gt;

&lt;p&gt;You run &lt;code&gt;npm install&lt;/code&gt;, then &lt;code&gt;npm run dev&lt;/code&gt;, like any Next.js app. &lt;code&gt;npm run check&lt;/code&gt; runs lint, typecheck and build in one go. It also ships with an &lt;code&gt;AGENTS.md&lt;/code&gt;, a &lt;code&gt;DESIGN.md&lt;/code&gt; and a &lt;code&gt;README.md&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's for you if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You already work in React or Next.js and want to build on top of the design.&lt;/li&gt;
&lt;li&gt;The site will grow: more pages, a CMS later, a form that talks to something, maybe an app section.&lt;/li&gt;
&lt;li&gt;You want components, types and a linter catching mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need Node and a terminal. That's a real hurdle if you've never used them.&lt;/li&gt;
&lt;li&gt;A bit more to maintain: dependencies update, and sooner or later you'll run an upgrade.&lt;/li&gt;
&lt;li&gt;For a five-section landing page that never changes, it's more machinery than you need. HTML does that job with less.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Framer: edit it visually, by hand or with Framer Agent
&lt;/h2&gt;

&lt;p&gt;The Framer edition is the whole project, copied into your own Framer workspace through a remix link. That includes the pages, the CMS collections, the code components and the Framer Skills that teach Framer Agent how the site is built.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's for you if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You design in Framer and want to restyle things in the visual editor by hand, or ask Framer Agent to do it, not write code.&lt;/li&gt;
&lt;li&gt;A client will edit the site themselves, and Framer's editor is what they know.&lt;/li&gt;
&lt;li&gt;You want hosting, publishing and a CMS in one place.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The trade-offs:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No source files to hand to a code editor. The project stays inside Framer.&lt;/li&gt;
&lt;li&gt;You depend on Framer's platform and its pricing for hosting.&lt;/li&gt;
&lt;li&gt;Only three templates have one so far: &lt;a href="https://no-code.supply/templates/oda/" rel="noopener noreferrer"&gt;Oda&lt;/a&gt;, &lt;a href="https://no-code.supply/templates/signal/" rel="noopener noreferrer"&gt;Signal&lt;/a&gt; and &lt;a href="https://no-code.supply/templates/tender/" rel="noopener noreferrer"&gt;Tender&lt;/a&gt;. You can buy it on its own, and it's also part of All-Access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I come from Framer, so I'm fond of it. But "no code" has a flip side. If you want a developer to own the site, one of the code editions is a better start.&lt;/p&gt;




&lt;h2&gt;
  
  
  So which one?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick HTML if…&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you want the simplest thing that works, anywhere&lt;/li&gt;
&lt;li&gt;you'll edit it by hand or with an AI agent&lt;/li&gt;
&lt;li&gt;the site is a landing page or a small brochure site&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pick React if…&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you or your developer already use React&lt;/li&gt;
&lt;li&gt;you expect the site to keep growing&lt;/li&gt;
&lt;li&gt;you want components and a proper dev setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pick Framer if…&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;you or your client edit in Framer's visual editor, by hand or with Framer Agent&lt;/li&gt;
&lt;li&gt;you want hosting and a CMS handled for you&lt;/li&gt;
&lt;li&gt;you don't need the source files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A rough rule: &lt;strong&gt;HTML for the fewest surprises, React for the longest runway, Framer for the least code.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Bundle, bundle-all and All-Access
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bundle&lt;/strong&gt; is HTML + React in one download. It makes sense when you're not sure yet. Prototype in HTML, move to React when the site outgrows it, or give a client the simple one and keep the other.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTML + React + Framer&lt;/strong&gt; is the same idea for the three templates that have all three. It's for studios and freelancers who deliver in different tools depending on the client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://no-code.supply/all-access/" rel="noopener noreferrer"&gt;All-Access&lt;/a&gt;&lt;/strong&gt; is every template in every edition it comes in (HTML, React, and Framer where there is one), including the ones that arrive in later drops. It pays off if you'll use more than a couple of templates. It doesn't include Grit UI (the Framer UI kit) or the separately sold Framer code components.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you only need one template for one site, one edition is plenty. Prices and what's included are on each &lt;a href="https://no-code.supply/" rel="noopener noreferrer"&gt;template's page&lt;/a&gt; and on the &lt;a href="https://no-code.supply/all-access/" rel="noopener noreferrer"&gt;All-Access page&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Can I switch editions later?
&lt;/h3&gt;

&lt;p&gt;Not by converting one into the other. They're separate builds of the same design. That's why the Bundle exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is there any difference in design between editions?
&lt;/h3&gt;

&lt;p&gt;No. The design, sections and copy are the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to know how to code?
&lt;/h3&gt;

&lt;p&gt;Not for HTML, if you edit with an AI agent or just change text. React needs Node and a terminal. Framer needs neither.&lt;/p&gt;

&lt;h3&gt;
  
  
  Which edition is best with an AI coding agent?
&lt;/h3&gt;

&lt;p&gt;HTML or React. Both ship with an &lt;code&gt;AGENTS.md&lt;/code&gt;. HTML has nothing to install, so there's less that can go wrong. The Framer edition has its own Framer Skills for Framer's agent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do updates cost extra?
&lt;/h3&gt;

&lt;p&gt;No. Updates to a template you own are free and show up in Polar's customer portal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;If you're still stuck, start with HTML. It's the easiest to change your mind from, and you can always buy React later. The &lt;a href="https://no-code.supply/license/" rel="noopener noreferrer"&gt;license&lt;/a&gt; and &lt;a href="https://no-code.supply/refunds/" rel="noopener noreferrer"&gt;refunds&lt;/a&gt; pages spell out the details.&lt;/p&gt;

&lt;p&gt;Thanks for reading! 🙏&lt;/p&gt;

&lt;p&gt;Want to see the editions for yourself? Open any &lt;a href="https://no-code.supply/" rel="noopener noreferrer"&gt;no-code.supply template&lt;/a&gt; and check what's included.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>react</category>
      <category>framer</category>
      <category>html</category>
    </item>
    <item>
      <title>How to write an AGENTS.md your AI agent actually follows</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Sun, 04 Oct 2026 19:26:16 +0000</pubDate>
      <link>https://dev.to/laurilllll/how-to-write-an-agentsmd-your-ai-agent-actually-follows-5g7m</link>
      <guid>https://dev.to/laurilllll/how-to-write-an-agentsmd-your-ai-agent-actually-follows-5g7m</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://no-code.supply/blog/how-to-write-agents-md/" rel="noopener noreferrer"&gt;no-code.supply&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An &lt;code&gt;AGENTS.md&lt;/code&gt; is a file that tells your AI coding agent how a project works and which rules it must not break.&lt;/li&gt;
&lt;li&gt;Most of them get ignored because they're written like a wiki page. &lt;strong&gt;Write it like instructions for a new colleague on their first day.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;What works: &lt;strong&gt;where things live&lt;/strong&gt;, &lt;strong&gt;numbered rules with the reason next to them&lt;/strong&gt;, &lt;strong&gt;one recipe for the most common task&lt;/strong&gt;, and &lt;strong&gt;a checklist for when it's done&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;What doesn't: vague advice ("write clean code"), things the agent can read from the code anyway, and docs nobody updates.&lt;/li&gt;
&lt;li&gt;Every template I sell ships with one, and here's exactly how they're written.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://no-code.supply/" rel="noopener noreferrer"&gt;See the templates&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I care about this file
&lt;/h2&gt;

&lt;p&gt;I built 15 website templates with an AI coding agent, Claude Code, in about a week. (&lt;a href="https://no-code.supply/blog/building-website-templates-with-ai/" rel="noopener noreferrer"&gt;The whole story is here&lt;/a&gt;.) Two repositories, dozens of sessions, and the agent starting from zero every single time.&lt;/p&gt;

&lt;p&gt;That's the thing people forget: &lt;strong&gt;your agent has no memory of yesterday.&lt;/strong&gt; Every session, it opens the project like a new hire on day one. Whatever it knows about how your project works, it learns from what's written down. If nothing is written down, it guesses. And guessing is where the weird bugs come from.&lt;/p&gt;

&lt;p&gt;Then there's the second reason. Every template I sell ships with an &lt;code&gt;AGENTS.md&lt;/code&gt;, because most buyers won't edit a template by hand. They'll open it in Cursor or Claude Code and say "make the hero blue." That file is the difference between their assistant following the template's rules and their assistant quietly breaking them.&lt;/p&gt;

&lt;p&gt;So I've written a lot of these by now. Let's dig in!&lt;/p&gt;




&lt;h2&gt;
  
  
  A quick caveat: this is how it works today
&lt;/h2&gt;

&lt;p&gt;Everything in this post is how things work in October 2026. AI coding tools change every few months, and the rules have already changed more than once. A year ago, every tool wanted its own file. Now most of them read &lt;code&gt;AGENTS.md&lt;/code&gt;, and even Claude Code reads it.&lt;/p&gt;

&lt;p&gt;So take the file names and tool details with a pinch of salt. The thinking behind them should last longer: &lt;strong&gt;write down what the agent can't read from the code, and say why.&lt;/strong&gt; That was good advice for onboarding human developers long before AI, and I don't see it going away.&lt;/p&gt;




&lt;h2&gt;
  
  
  What AGENTS.md is (and CLAUDE.md)
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;AGENTS.md&lt;/code&gt; is a plain markdown file in the root of a project. AI coding agents read it before they start working. It's an open convention, so one file works in most tools: Codex, Cursor, GitHub Copilot and others read it.&lt;/p&gt;

&lt;p&gt;Claude Code has its own file, &lt;code&gt;CLAUDE.md&lt;/code&gt;. You don't need two copies. My &lt;code&gt;CLAUDE.md&lt;/code&gt; files have one line in them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;@AGENTS.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That tells Claude Code to pull in &lt;code&gt;AGENTS.md&lt;/code&gt;. One source of truth, every tool covered.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Claude Code can now read &lt;code&gt;AGENTS.md&lt;/code&gt; on its own, so a project with only an &lt;code&gt;AGENTS.md&lt;/code&gt; works out of the box. But if there's also a &lt;code&gt;CLAUDE.md&lt;/code&gt; in the project, Claude Code reads that one instead by default. So if you have both, keep the one-line import. (&lt;a href="https://code.claude.com/docs/en/memory#agents-md" rel="noopener noreferrer"&gt;Claude Code docs&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also have more than one. My templates have an &lt;code&gt;AGENTS.md&lt;/code&gt; per edition, one for the HTML version and one for the React version, because the rules are different. A plain HTML site that has to open from a double-clicked file has nothing in common with a Next.js build.&lt;/p&gt;

&lt;p&gt;When there's more than one, the closest file wins. Agents read the &lt;code&gt;AGENTS.md&lt;/code&gt; nearest to the file they're editing, so a subfolder's file can add to or override the root one. Put the rules that apply everywhere in the root file, and the rules for one part of the project next to that part. Claude Code works the same way with &lt;code&gt;CLAUDE.md&lt;/code&gt;: a subfolder's file loads when Claude starts working in that folder.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to put in it
&lt;/h2&gt;

&lt;p&gt;Every &lt;code&gt;AGENTS.md&lt;/code&gt; I write has the same five parts. Here they are, with real pieces from &lt;a href="https://no-code.supply/templates/oda/" rel="noopener noreferrer"&gt;Oda&lt;/a&gt;, an architecture studio template.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. What this is, in two sentences
&lt;/h3&gt;

&lt;p&gt;Start with what the project is and the one constraint that shapes everything else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## What this is&lt;/span&gt;
A static, dependency-free landing page for an architecture studio:
&lt;span class="sb"&gt;`index.html`&lt;/span&gt; + CSS + classic JS. There is no build step and there must
never be one. The page must keep working when &lt;span class="sb"&gt;`index.html`&lt;/span&gt; is opened
directly from disk.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That last sentence does a lot of work. Without it, the first thing a helpful agent does is add a bundler.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Where things live
&lt;/h3&gt;

&lt;p&gt;A map. Not every file, just the ones the agent needs to find to do its job, and &lt;strong&gt;where a change should go&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Where things live&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Copy and structure: &lt;span class="sb"&gt;`index.html`&lt;/span&gt;, one SECTION banner comment per
  section (Hero, Studio, Work, Process …).
&lt;span class="p"&gt;-&lt;/span&gt; Design tokens: &lt;span class="sb"&gt;`assets/css/tokens.css`&lt;/span&gt;. Change values here, not in &lt;span class="sb"&gt;`main.css`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Shared helpers: &lt;span class="sb"&gt;`assets/js/kit.js`&lt;/span&gt; + &lt;span class="sb"&gt;`assets/css/kit.css`&lt;/span&gt; (vendored —
  don't edit; call &lt;span class="sb"&gt;`kit.*`&lt;/span&gt; helpers instead of re-implementing).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the pattern? Each line says where something is &lt;em&gt;and&lt;/em&gt; what to do with it. "Change values here, not there." "Don't edit, call these instead." That's the part that changes the agent's behaviour.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Rules that must not break
&lt;/h3&gt;

&lt;p&gt;This is the heart of the file. Short, numbered, and each one with its reason.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Rules that must not break&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; No external requests: no CDNs, Google Fonts, analytics or remote images.
&lt;span class="p"&gt;2.&lt;/span&gt; Classic scripts with &lt;span class="sb"&gt;`defer`&lt;/span&gt; only. Never &lt;span class="sb"&gt;`type="module"`&lt;/span&gt; or &lt;span class="sb"&gt;`import`&lt;/span&gt;:
   they fail over &lt;span class="sb"&gt;`file://`&lt;/span&gt;.
&lt;span class="p"&gt;3.&lt;/span&gt; Respect &lt;span class="sb"&gt;`prefers-reduced-motion`&lt;/span&gt;: new animations need a static
   equivalent.
&lt;span class="p"&gt;6.&lt;/span&gt; Exactly one &lt;span class="sb"&gt;`&amp;lt;h1&amp;gt;`&lt;/span&gt;; keep headings ordered, landmarks, the skip link
   and &lt;span class="sb"&gt;`:focus-visible`&lt;/span&gt; styles.
&lt;span class="p"&gt;8.&lt;/span&gt; Use existing tokens. If you need a new one, add it to &lt;span class="sb"&gt;`tokens.css`&lt;/span&gt;
   with a comment. Text in the accent colour uses &lt;span class="sb"&gt;`--timber-ink`&lt;/span&gt; (large)
   or &lt;span class="sb"&gt;`--timber-deep`&lt;/span&gt; (small), never &lt;span class="sb"&gt;`--timber`&lt;/span&gt;, which fails contrast.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two things make these rules stick:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The reason.&lt;/strong&gt; "Never &lt;code&gt;type="module"&lt;/code&gt;" alone looks like a style preference, and an agent will happily trade a style preference for something it thinks is better. "They fail over &lt;code&gt;file://&lt;/code&gt;" is a fact it can't argue with.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Numbers.&lt;/strong&gt; A numbered list is easy to point at. "You broke rule 2" is a much shorter conversation than explaining it again.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rule 8 is my favourite kind of rule. It's oddly specific, and that's the point. The accent colour looks great, but it fails contrast on small text. Nothing in the code tells you that. Without the rule, the next agent would happily use it for a caption.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A recipe for the most common task
&lt;/h3&gt;

&lt;p&gt;Think about what people will ask for most. For a template, it's "add a section." So the file shows exactly how a section is built in this template, with a snippet to copy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Adding a section in the template's style&lt;/span&gt;
Copy the Materials or People section as a starting point:
&lt;span class="p"&gt;
-&lt;/span&gt; Header: the ruled &lt;span class="sb"&gt;`.sec-head`&lt;/span&gt; with &lt;span class="sb"&gt;`(NN) Name`&lt;/span&gt;, a subtitle and the
  next free sheet number.
&lt;span class="p"&gt;-&lt;/span&gt; Layout: &lt;span class="sb"&gt;`.wrap`&lt;/span&gt; + the 12-column &lt;span class="sb"&gt;`.g12`&lt;/span&gt;; spacing comes from &lt;span class="sb"&gt;`.sec`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Headings: &lt;span class="sb"&gt;`.h2`&lt;/span&gt; with the last word in &lt;span class="sb"&gt;`&amp;lt;span class="dim"&amp;gt;`&lt;/span&gt;.
&lt;span class="p"&gt;-&lt;/span&gt; Reveals: &lt;span class="sb"&gt;`data-reveal="draft"`&lt;/span&gt; with &lt;span class="sb"&gt;`data-reveal-delay`&lt;/span&gt; in ms.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how a new section ends up looking like it belongs, instead of looking like the agent's idea of a section. Agents copy what they see. Give them the right thing to copy.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. A checklist for "done"
&lt;/h3&gt;

&lt;p&gt;End with what to check before calling the work finished.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Before you finish&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] No console errors. No horizontal scroll at 390px wide.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] The page still works opened from disk.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Reduced motion shows a complete page.
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Keyboard: every control reachable, visible focus.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a code project, the best version of this is one command. My React editions just say: run &lt;code&gt;npm run check&lt;/code&gt; (lint, typecheck and build). If the agent can run it, it will, and it'll fix what fails before you ever see it.&lt;/p&gt;




&lt;h2&gt;
  
  
  What to leave out
&lt;/h2&gt;

&lt;p&gt;Just as important. Everything in the file competes for the agent's attention, so every line has to earn its place.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vague advice.&lt;/strong&gt; "Write clean, maintainable code." "Follow best practices." The agent already thinks it does. These lines change nothing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What the code already says.&lt;/strong&gt; Don't list every component or explain what React is. The agent can read the code. Write down what it &lt;em&gt;can't&lt;/em&gt; read: the intent, the constraints, the decisions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;History.&lt;/strong&gt; "We used to use X, then switched to Y." Unless the old way is a trap it'll fall into, leave it out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secrets.&lt;/strong&gt; No API keys, tokens or passwords. The file lives in the repo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Long essays.&lt;/strong&gt; If a section needs paragraphs of background, put it in its own doc (I use &lt;code&gt;DESIGN.md&lt;/code&gt; for the design rationale) and link to it from &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't have a line count I aim for. Mine ended up between 46 and 102 lines, depending on how much the template does. The test I use: if a part needs paragraphs of background, it belongs in another file.&lt;/p&gt;




&lt;h2&gt;
  
  
  Common mistakes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Describing instead of directing
&lt;/h3&gt;

&lt;p&gt;Compare these two. Describing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;The project uses design tokens for colours and spacing.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Directing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Use existing tokens. If you need a new one, add it to &lt;span class="sb"&gt;`tokens.css`&lt;/span&gt;
with a comment. Never hard-code hex values.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first one is true. The second one is useful. Write in the imperative: &lt;em&gt;use&lt;/em&gt;, &lt;em&gt;keep&lt;/em&gt;, &lt;em&gt;never&lt;/em&gt;, &lt;em&gt;change it here&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rules without a reason
&lt;/h3&gt;

&lt;p&gt;An agent weighs your rule against everything else it knows. A rule with a reason wins that fight. A rule without one often doesn't, especially when the agent has a "better" idea.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing it once and never touching it again
&lt;/h3&gt;

&lt;p&gt;A stale &lt;code&gt;AGENTS.md&lt;/code&gt; is worse than none, because the agent trusts it. If a file moved or a command changed, the agent follows the old map and gets lost confidently.&lt;/p&gt;

&lt;p&gt;My fix: &lt;strong&gt;every time the agent makes a mistake, I ask whether a line in &lt;code&gt;AGENTS.md&lt;/code&gt; would have prevented it.&lt;/strong&gt; If yes, it goes in. Most of my best rules came from bugs.&lt;/p&gt;

&lt;p&gt;Here's a real one. Every template's docs explain how to move a section, like the hero, into another site. On 26 September I had the agent actually do it: follow the steps word for word and move each template's hero into a separate test site with its own clashing styles.&lt;/p&gt;

&lt;p&gt;It broke in four templates. In some, the hero's entrance waited for a signal from the preloader or the nav. Move the hero without them, and the headline never appeared. In another, the hero's buttons needed a different section to exist.&lt;/p&gt;

&lt;p&gt;The fixes took minutes. The more important part was the new rule that went into every template's &lt;code&gt;AGENTS.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;9.&lt;/span&gt; Every section must start on its own. An entrance that waits for a
   boot/intro signal must not rely on the preloader or the nav to
   send it: call the fallback from the section's own effect as well.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now every agent that adds a section, mine or a buyer's, knows about it before it makes the mistake.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing it all yourself
&lt;/h3&gt;

&lt;p&gt;You don't have to. Ask the agent to write the first version after it has worked on the project for a while: "Write an &lt;code&gt;AGENTS.md&lt;/code&gt; for this project: where things live, rules that must not break, how to add a section, and a checklist for done." Then &lt;strong&gt;review it like any other part of the product.&lt;/strong&gt; Cut the vague lines, add the reasons, fix what's wrong.&lt;/p&gt;

&lt;p&gt;That's how all of mine were made. The agent that built the template also wrote down how it built it, and I edited it.&lt;/p&gt;




&lt;h2&gt;
  
  
  A template you can copy
&lt;/h2&gt;

&lt;p&gt;Here's the skeleton I start from. Fill in the brackets, delete what doesn't apply.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# AGENTS.md — [Project name]&lt;/span&gt;

Instructions for AI coding assistants working on this project.
Read this before editing.

&lt;span class="gu"&gt;## What this is&lt;/span&gt;
[One or two sentences. What it is, and the one constraint that shapes
everything else.]

&lt;span class="gu"&gt;## Where things live&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [Thing]: &lt;span class="sb"&gt;`path/to/file`&lt;/span&gt;. [What to change here, or what not to touch.]
&lt;span class="p"&gt;-&lt;/span&gt; [Thing]: &lt;span class="sb"&gt;`path/to/file`&lt;/span&gt;. [...]

&lt;span class="gu"&gt;## Rules that must not break&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; [Rule]: [why].
&lt;span class="p"&gt;2.&lt;/span&gt; [Rule]: [why].
&lt;span class="p"&gt;3.&lt;/span&gt; [Rule]: [why].

&lt;span class="gu"&gt;## [The most common task]&lt;/span&gt;
[Which file to copy, which patterns to reuse, where the copy goes.]

&lt;span class="gu"&gt;## Commands&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`[dev command]`&lt;/span&gt; — [what it does]
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="sb"&gt;`[check command]`&lt;/span&gt; — run before you finish.

&lt;span class="gu"&gt;## Before you finish&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; [ ] [Check]
&lt;span class="p"&gt;-&lt;/span&gt; [ ] [Check]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What's the difference between AGENTS.md and CLAUDE.md?
&lt;/h3&gt;

&lt;p&gt;They do the same job. &lt;code&gt;AGENTS.md&lt;/code&gt; is the shared convention most AI coding tools read. &lt;code&gt;CLAUDE.md&lt;/code&gt; is Claude Code's own file. Claude Code also reads &lt;code&gt;AGENTS.md&lt;/code&gt; now, but only when there's no &lt;code&gt;CLAUDE.md&lt;/code&gt;. Simplest setup: put everything in &lt;code&gt;AGENTS.md&lt;/code&gt;, and if you need a &lt;code&gt;CLAUDE.md&lt;/code&gt; too, make it a single line, &lt;code&gt;@AGENTS.md&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where does AGENTS.md go?
&lt;/h3&gt;

&lt;p&gt;In the root of the project. You can add more in subfolders when a part of the project has its own rules, like my templates' HTML and React editions. The agent reads the one closest to the file it's editing, so the most specific rules win.&lt;/p&gt;

&lt;h3&gt;
  
  
  How long should an AGENTS.md be?
&lt;/h3&gt;

&lt;p&gt;As short as it can be while still covering where things live, the rules, the most common task and the checklist. Mine are between 46 and 102 lines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does my AI agent actually follow it?
&lt;/h3&gt;

&lt;p&gt;Much better than without one, and much better when the rules come with reasons. It's not a guarantee. That's why the file ends with a checklist and, when possible, a command that checks the work.&lt;/p&gt;

&lt;h3&gt;
  
  
  Should I write it myself or let the AI write it?
&lt;/h3&gt;

&lt;p&gt;Both. Let the agent write the first draft from the project, then edit it yourself. You know the decisions and the reasons. It knows the files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;An &lt;code&gt;AGENTS.md&lt;/code&gt; is the cheapest quality tool you have. Ten minutes of writing saves you from explaining the same thing in every session, and it keeps your rules alive after you've forgotten why you made them.&lt;/p&gt;

&lt;p&gt;If you read this far, thank you! 🙏&lt;/p&gt;

&lt;p&gt;Want to see a real one in action? Every &lt;a href="https://no-code.supply/" rel="noopener noreferrer"&gt;no-code.supply template&lt;/a&gt; ships with an &lt;code&gt;AGENTS.md&lt;/code&gt;, a &lt;code&gt;DESIGN.md&lt;/code&gt; and a &lt;code&gt;README.md&lt;/code&gt;, so your own AI assistant can edit it the way it was built. 🔥&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>tutorial</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I built 15 website templates with an AI coding agent in a week</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Sat, 03 Oct 2026 11:18:26 +0000</pubDate>
      <link>https://dev.to/laurilllll/how-i-built-15-website-templates-with-an-ai-coding-agent-in-a-week-5f0h</link>
      <guid>https://dev.to/laurilllll/how-i-built-15-website-templates-with-an-ai-coding-agent-in-a-week-5f0h</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on &lt;a href="https://no-code.supply" rel="noopener noreferrer"&gt;no-code.supply&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I built 15 website templates, each with its own brand, in about a week, with an AI coding agent (Claude Code) doing the typing.&lt;/li&gt;
&lt;li&gt;The agent pretty much one-shotted the designs. My job moved from building to directing: the idea, the quality bar, and the final call.&lt;/li&gt;
&lt;li&gt;Where AI really shines: speed, bug hunting, and packaging it all as a business.&lt;/li&gt;
&lt;li&gt;Every template is AI-ready: it ships with docs your own AI assistant can read, so it edits the template the way it was built.&lt;/li&gt;
&lt;li&gt;Yes, some people call it AI slop. They're templates. A template is where your site starts, not where it ends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://no-code.supply/#templates" rel="noopener noreferrer"&gt;Browse the templates&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I did this
&lt;/h2&gt;

&lt;p&gt;I'm Lauri Lännenmäki, a design engineer. I've spent fifteen years designing and building for the web, most of it somewhere between Figma, Framer and code. I'm a consultant in Finland, and I freelance on nights and weekends. Before this I made Grit UI and Fhibli UI for Framer, and a handful of Framer code components. I'm also a certified Framer Pro Expert.&lt;/p&gt;

&lt;p&gt;I've wanted my own template shop for a long time. What stopped me was always the same thing: time. Before this I only made Framer templates, and a good one took me at least a month, on and off. Doing fifteen of them, each drawn from scratch and shipped in two code editions, was never going to happen on nights and weekends.&lt;/p&gt;

&lt;p&gt;So I wanted to find out: can one designer build a real template business with an AI agent doing most of the typing?&lt;/p&gt;

&lt;p&gt;Short answer: yes. Let's dig in!&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Two repositories and one agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The templates repo:&lt;/strong&gt; where every template is designed, built, reviewed and packaged. It also holds a small shared kit (the helpers every template reuses) and the tooling that checks and exports everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The storefront:&lt;/strong&gt; &lt;a href="https://no-code.supply" rel="noopener noreferrer"&gt;no-code.supply&lt;/a&gt;, a static Next.js site that shows and sells the templates. Checkout runs on Polar.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The agent:&lt;/strong&gt; Claude Code, on one of the higher-usage plans.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every template ships in two editions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTML:&lt;/strong&gt; plain HTML, CSS and JavaScript. It opens straight from the folder you download. No build step, no accounts, no framework to learn.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React:&lt;/strong&gt; a Next.js + React + Tailwind project, with every word of copy in one file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some also get a Framer edition: &lt;a href="https://no-code.supply/templates/oda/" rel="noopener noreferrer"&gt;Oda&lt;/a&gt; and &lt;a href="https://no-code.supply/templates/signal/" rel="noopener noreferrer"&gt;Signal&lt;/a&gt; so far.&lt;/p&gt;




&lt;h2&gt;
  
  
  How one template gets made
&lt;/h2&gt;

&lt;p&gt;Every template goes through the same phases. The agent does most of the work in each one. I decide when a phase is done.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The concept
&lt;/h3&gt;

&lt;p&gt;This part is mine. Before any code exists, I decide what the template is: the industry, the brand, the mood, the type pairing, the palette and the one interaction people should remember.&lt;/p&gt;

&lt;p&gt;Oda is an architecture studio designed as a drawing set: grid paper, hairline title blocks, sheet numbers, and line drawings that draw themselves as you scroll. Signal is a security SaaS. Meridian is travel. Each one gets its own identity, not a recolour of the last one.&lt;/p&gt;

&lt;p&gt;For every concept I gave the agent 5–10 references: images and websites with the mood I was after, plus things I generally like myself. Alongside them I wrote down the typography (the type scale and its style), the spacing and the colour palette. And one rule above everything else: don't copy anything. Ever. The references set the mood: the feel, how dense the page is, how it moves. The layouts, copy, imagery and code are all made from scratch.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The first build
&lt;/h3&gt;

&lt;p&gt;The agent builds the HTML edition from the concept. And this is the part that still surprises me: &lt;strong&gt;the first version is usually very close to done&lt;/strong&gt;. I don't have a dramatic before/after to show you, because there isn't much of one. The first builds were just amazing. I had to change very little in any of the templates. Here and there I removed a section, but nothing much.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Review, docs and fixes
&lt;/h3&gt;

&lt;p&gt;Close to done isn't done. This is where most of the time goes, and it's where the quality comes from.&lt;/p&gt;

&lt;p&gt;Every template goes through the same definition of done before it ships:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero console errors or warnings.&lt;/li&gt;
&lt;li&gt;No horizontal overflow at 360, 390, 768, 1024, 1440 and 1920 pixels wide.&lt;/li&gt;
&lt;li&gt;0 serious or critical axe issues, a keyboard-only pass, and visible focus styles everywhere.&lt;/li&gt;
&lt;li&gt;WCAG 2.2 AA contrast for text.&lt;/li&gt;
&lt;li&gt;prefers-reduced-motion shows a complete, good-looking static page.&lt;/li&gt;
&lt;li&gt;No third-party requests at all. Fonts are self-hosted. No CDNs, no analytics.&lt;/li&gt;
&lt;li&gt;The HTML edition works from a double-clicked index.html, not just from a web server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lighthouse scores are a goal, not a rule. I aim for Accessibility ≥ 95, Best Practices ≥ 95 and SEO 100, but when a template's design calls for it, I'll accept a lower score.&lt;/p&gt;

&lt;p&gt;That's a lot of checking. Luckily, checking is something the agent is very good at (more on that below).&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The React edition
&lt;/h3&gt;

&lt;p&gt;Same design, same copy, rebuilt as a Next.js project, then put through the same checklist.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Packaging
&lt;/h3&gt;

&lt;p&gt;Zips, previews, a changelog, product copy, and the export to the storefront. More on this below too, because it turned out to be the most surprising part.&lt;/p&gt;

&lt;p&gt;All in, it took about &lt;strong&gt;3–6 hours&lt;/strong&gt; to go from a design to a finished template in both editions.&lt;/p&gt;




&lt;h2&gt;
  
  
  AI-ready templates: what that actually means
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of, and it's the reason I call these AI-ready templates.&lt;/p&gt;

&lt;p&gt;Most people who buy a template in 2026 won't edit it by hand. They'll open it in Cursor, Claude Code or whatever assistant they use, and say "change the hero copy and make it blue." The problem: the assistant doesn't know how the template was built. So it guesses. It hard-codes a colour, breaks the mobile layout, or adds a dependency that breaks the no-build-step promise.&lt;/p&gt;

&lt;p&gt;So every template ships with three files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;README.md&lt;/code&gt;:&lt;/strong&gt; for you. How to install it, edit it, and move a section into another site.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;DESIGN.md&lt;/code&gt;:&lt;/strong&gt; the design rationale. Tokens, type scale, the ideas behind the layout.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;:&lt;/strong&gt; for your AI assistant. Where things live, how the effects work, and the rules that must not break.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a small piece of Oda's &lt;code&gt;AGENTS.md&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Rules that must not break&lt;/span&gt;
&lt;span class="p"&gt;1.&lt;/span&gt; No external requests: no CDNs, Google Fonts, analytics or remote images.
&lt;span class="p"&gt;3.&lt;/span&gt; Respect &lt;span class="sb"&gt;`prefers-reduced-motion`&lt;/span&gt;: new animations need a static equivalent.
&lt;span class="p"&gt;6.&lt;/span&gt; Exactly one &lt;span class="sb"&gt;`&amp;lt;h1&amp;gt;`&lt;/span&gt;; keep headings ordered, landmarks, the skip link and &lt;span class="sb"&gt;`:focus-visible`&lt;/span&gt; styles.
&lt;span class="p"&gt;8.&lt;/span&gt; Use existing tokens. If you need a new one, add it to &lt;span class="sb"&gt;`tokens.css`&lt;/span&gt; with a comment.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These files aren't an afterthought. The agent that built the template also wrote down how it built it, and I reviewed those docs like any other part of the product. So when your assistant opens the template, it follows the same rules the original was built with.&lt;/p&gt;

&lt;p&gt;The Framer edition works the same way: it ships with Framer Skills that teach Framer's own agent how the site is built.&lt;/p&gt;

&lt;p&gt;That's the idea behind AI-ready: the template is the starting point, and your AI assistant can take it the rest of the way without breaking it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where AI was great
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Speed
&lt;/h3&gt;

&lt;p&gt;The obvious one, but the numbers are still silly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;24 September: the templates repo starts.&lt;/li&gt;
&lt;li&gt;26 September: the shop launches with the first six templates.&lt;/li&gt;
&lt;li&gt;29 September: nine templates are out.&lt;/li&gt;
&lt;li&gt;1 October: all 15 are done.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About a week. And not a full-time week, either: I did this around my consulting work, so the hours are hard to count.&lt;/p&gt;

&lt;p&gt;Honestly, without AI I wouldn't have started this project at all. One template would have taken me months, let alone building an entire shop around them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bug hunting
&lt;/h3&gt;

&lt;p&gt;This one surprised me. The agent spotted a lot of bugs by itself and fixed them without me telling it to. A few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tender's form error colours failed contrast.&lt;/strong&gt; You only see an error message when a form fails, so it's easy to never check its colour.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus styles.&lt;/strong&gt; Invisible with a mouse. You only notice them when you go through the page with a keyboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An HTML comment could swallow markup in the step that exports a template to the store.&lt;/strong&gt; A section could quietly disappear from a demo, with no error anywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oda's reveal animations got clipped&lt;/strong&gt;, cutting off the edges of elements as they animated in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The list is much longer. Many times it corrected itself before I'd even noticed anything was wrong.&lt;/p&gt;

&lt;p&gt;The quality checklist above is only realistic because of this. Checking six screen widths, two editions, reduced motion, keyboard navigation and contrast, on every template, after every change, is exactly the kind of boring, careful work people skip. The agent doesn't get bored.&lt;/p&gt;

&lt;h3&gt;
  
  
  Packaging it all as a business
&lt;/h3&gt;

&lt;p&gt;This is the one I didn't see coming. Designing templates is maybe half of running a template shop. The other half is everything around them, and the agent built most of that too:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The storefront itself:&lt;/strong&gt; a static Next.js site with product pages, pricing, an All-Access offer and the legal pages.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The export pipeline:&lt;/strong&gt; one command takes a finished template and writes its product page data, previews and live demo into the store.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Polar sync:&lt;/strong&gt; a script that creates the products in Polar, uploads each edition's zip, and writes the checkout links back to the site. When I ship an update, it swaps the files so every past buyer gets the new version.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Share images:&lt;/strong&gt; every product gets its own Open Graph image, generated at build time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The launch video:&lt;/strong&gt; a script that films the store and the demos frame by frame and renders them to MP4. No screen recording, no editing app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Without AI, the cost of all this would have been enormous for me. It would have been a long year of sleepless nights.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I still had to bring
&lt;/h2&gt;

&lt;p&gt;The agent did the typing. It didn't decide what's good. A few things were still my job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The concept.&lt;/strong&gt; Every template starts with an idea only I can have: what it is, who it's for, what makes it memorable. And the rule that nothing gets copied.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The bar.&lt;/strong&gt; The definition of done above came from me. The agent meets the bar you set. Set it low and it'll happily ship something mediocre.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The final call.&lt;/strong&gt; I reviewed every template visually for bugs and checked that every interaction works. Basic stuff, but someone has to do it.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  "Isn't this just AI slop?"
&lt;/h2&gt;

&lt;p&gt;It's a fair question to ask. Anything built with AI right now gets called AI slop sooner or later, so I'd rather answer it up front.&lt;/p&gt;

&lt;p&gt;Here's the thing: &lt;strong&gt;they look good, and they're templates.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A template isn't the final site. It's where the final site starts. Nobody ships a template untouched. You add your brand, your copy, your photos, your product, your decisions. The template's job is to get you to a good, working, accessible starting point fast, so you can spend your time on the parts only you can do.&lt;/p&gt;

&lt;p&gt;And "AI-generated" isn't what makes something slop. &lt;strong&gt;Slop is what you get when nobody made the decisions.&lt;/strong&gt; Default fonts, default layouts, nobody checking whether it works on a phone or with a keyboard. Every one of these templates has its own concept, its own type pairing and its own signature interaction, and every one goes through the same checklist before it ships.&lt;/p&gt;

&lt;p&gt;The AI wrote a lot of the code. It didn't decide what good looks like. I've seen hundreds, maybe thousands, of templates in my day, and to me these are top-tier by any standard.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd tell a designer starting today
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Just try it.&lt;/strong&gt; This is the biggest lesson. Get familiar with these tools. They're here to stay, and they can make your life a lot easier.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with the concept, not the prompt.&lt;/strong&gt; The clearer your idea, the closer the first build gets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write your definition of done first.&lt;/strong&gt; Think about the big picture you want to achieve. The agent will meet whatever bar you set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the agent write the docs.&lt;/strong&gt; They help you, your buyers, and the next agent that opens the project.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hand it the tedious stuff.&lt;/strong&gt; You don't have to do everything with AI. Give it the boring, careful work and keep the fun parts for yourself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let AI do the business parts too.&lt;/strong&gt; Checkout, exports, share images, even the launch video. That's where one person gets a lot more leverage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Experiment.&lt;/strong&gt; Try things you wouldn't have had time for before.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Can AI design a website on its own?
&lt;/h4&gt;

&lt;p&gt;It can build a good one from a clear concept, and fast. The concept, the quality bar and the final call still come from a person. That's where the difference between a generic site and a good one comes from.&lt;/p&gt;

&lt;h4&gt;
  
  
  Are AI-built website templates any good?
&lt;/h4&gt;

&lt;p&gt;They can be, if someone sets a real bar.&lt;/p&gt;

&lt;h4&gt;
  
  
  What is an AI-ready template?
&lt;/h4&gt;

&lt;p&gt;A template that ships with docs your AI coding assistant can read: a README.md, a DESIGN.md and an AGENTS.md. The assistant then edits the template the way it was built, instead of guessing.&lt;/p&gt;

&lt;h4&gt;
  
  
  How long does it take to build a template with AI?
&lt;/h4&gt;

&lt;p&gt;For me, about 3–6 hours from a design to a finished template, including both editions and the full quality checklist.&lt;/p&gt;

&lt;h4&gt;
  
  
  Do I need to know how to code to use these templates?
&lt;/h4&gt;

&lt;p&gt;No. The HTML edition runs straight from the folder you download, with no build step, and the included docs let your AI assistant make changes for you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;Building this shop with an AI agent changed what I think one designer can do. And I'm just getting started: more templates, and more posts like this one, are on the way.&lt;/p&gt;

&lt;p&gt;If you read this far, thank you! 🙏&lt;/p&gt;

&lt;p&gt;And if you'd rather skip all of this and start from something that has already been through the checklist, &lt;a href="https://no-code.supply" rel="noopener noreferrer"&gt;the templates are here&lt;/a&gt;. &lt;a href="https://no-code.supply/all-access/" rel="noopener noreferrer"&gt;All-Access&lt;/a&gt; gets you every template, including every one I add later. 🔥&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>design</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to create Dark Mode using only CSS</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Thu, 03 Mar 2022 22:32:55 +0000</pubDate>
      <link>https://dev.to/laurilllll/how-to-create-dark-mode-using-only-css-2cb4</link>
      <guid>https://dev.to/laurilllll/how-to-create-dark-mode-using-only-css-2cb4</guid>
      <description>&lt;p&gt;Dark Mode and dark interfaces are not a new thing as they have been a trend for many years. When Apple released a dark mode option with the iOS 13 update back in 2019, the trend took off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using modern CSS, you can create dark mode with a few lines of code.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let's dive in!&lt;/p&gt;

&lt;h4&gt;
  
  
  📚 Content
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Dark mode is more than a trend&lt;/li&gt;
&lt;li&gt;Dark mode is accessibility&lt;/li&gt;
&lt;li&gt;
How to set up dark mode with CSS

&lt;ul&gt;
&lt;li&gt;Create CSS Custom Properties (variables)&lt;/li&gt;
&lt;li&gt;Create conditional styling&lt;/li&gt;
&lt;li&gt;Apply styles&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Demo and final code&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  ✨ Bonus Content
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Color-scheme meta tag and CSS property&lt;/li&gt;
&lt;li&gt;
How to test your code

&lt;ul&gt;
&lt;li&gt;Google Chrome Dev Tools&lt;/li&gt;
&lt;li&gt;Device OS Settings&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;p&gt;You can create dark mode using only &lt;strong&gt;CSS Custom Properties aka CSS variables&lt;/strong&gt; and &lt;strong&gt;CSS media feature &lt;code&gt;prefers-color-scheme&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* 1. Create global variables for text and background color */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 2. Add conditional styling for dark mode preference */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Re-assign previous variables */&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* black =&amp;gt; white */&lt;/span&gt;
    &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* white =&amp;gt; black */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 3. Assign variables to page color and background */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's it 🔥 View my &lt;strong&gt;CSS Only Dark Mode&lt;/strong&gt; &lt;a href="https://codepen.io/laurilllll/pen/yLPKojZ" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dark mode is more than a trend
&lt;/h2&gt;

&lt;p&gt;Dark mode is not a design trend. Dark interfaces can be easier on the eyes and reduce eye strain and fatigue. They can actually help reduce the sensation of discomfort felt when staring at websites with light backgrounds.&lt;/p&gt;

&lt;p&gt;Dark mode also saves your device's battery life. It can reduce battery usage, especially on mobile devices.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dark mode is accessibility
&lt;/h2&gt;

&lt;p&gt;Dark mode is also an accessibility (a11y) feature. &lt;strong&gt;It's about respecting your users and their preferences so they can use your website the way they like.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Besides responsive media queries, modern CSS has many cool media features and &lt;code&gt;prefers-color-scheme&lt;/code&gt; is one of them.  &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" rel="noopener noreferrer"&gt;Quote from MDN Web Docs&lt;/a&gt; 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The prefers-color-scheme CSS media feature is used to detect if the user has requested a light or dark color theme. The user might indicate this preference through an operating system setting (e.g. light or dark mode) or a user agent setting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Users can choose if they prefer light or dark mode from their operating system settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4llkxl3oc2oi1ju3mx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4llkxl3oc2oi1ju3mx4.png" alt="Picture from macOS general settings."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(macOS)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf9qaupb806yxk67fobl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf9qaupb806yxk67fobl.png" alt="Picture from iOS Display &amp;amp; Brightness settings."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(iOS)&lt;/p&gt;

&lt;p&gt;With CSS, you can serve the user the theme they prefer. Media queries are used to conditionally apply styles. Media feature &lt;code&gt;prefers-color-scheme&lt;/code&gt; is a &lt;strong&gt;Media Query&lt;/strong&gt;, so you write it like you'd write your breakpoints:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* Breakpoint */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;800px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Add conditional styles here */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Prefers Color Scheme */&lt;/span&gt;
&lt;span class="c"&gt;/* Dark */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Add conditional styles here */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c"&gt;/* Light */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Add conditional styles here */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  How to set up dark mode with CSS
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Create CSS Custom Properties (variables)
&lt;/h4&gt;

&lt;p&gt;To setup color styles, I recommend using &lt;strong&gt;variables&lt;/strong&gt; to keep your code DRY (don't repeat yourself). If you aren't familiar with CSS variables, you can read about them from &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*" rel="noopener noreferrer"&gt;MDN Web Docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the sake of this tutorial we keep things simple and use black and white as our colors. And we only style our text color and background color.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* 1. Create global variables for text and background color */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Create conditional styling
&lt;/h4&gt;

&lt;p&gt;Next, let's apply &lt;strong&gt;conditional styling for users who prefer dark mode&lt;/strong&gt;. By using a media query, we re-assign previous variables with new inverted values.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* 2. Add conditional styling for dark mode preference */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Re-assign previous variables */&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* black =&amp;gt; white */&lt;/span&gt;
    &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* white =&amp;gt; black */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Apply styles
&lt;/h4&gt;

&lt;p&gt;And finally, we &lt;strong&gt;apply the variables&lt;/strong&gt; to our design:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* 3. Assign variables to page color and background */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Demo and final code
&lt;/h2&gt;

&lt;p&gt;See the final effect in action of user changing between light and dark mode in OS settings: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd6aqe9w1bidmjnu44ui.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzd6aqe9w1bidmjnu44ui.gif" alt="GIF animation of user changing between light and dark mode in OS settings."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👇 The final code in full.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="c"&gt;/* 1. Create global variables for text and background color */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 2. Add conditional styling for dark mode preference */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prefers-color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Re-assign previous variables */&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* black =&amp;gt; white */&lt;/span&gt;
    &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* white =&amp;gt; black */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* 3. Assign variables to page color and background */&lt;/span&gt;
&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can view the code and play with it in my &lt;a href="https://codepen.io/laurilllll/pen/yLPKojZ" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  ✨ Bonus Content
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Color-scheme meta tag and CSS property
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;color-scheme&lt;/code&gt; meta tag and CSS property takes care of two important things for you. This next quote is from &lt;a href="https://web.dev/color-scheme/" rel="noopener noreferrer"&gt;Google Developers web.dev&lt;/a&gt; and I've taken the liberty to highlight some parts of it 👇&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;They both make your life as a developer easier by allowing you to &lt;strong&gt;opt your page in to theme-specific defaults of the user agent stylesheet&lt;/strong&gt;, such as, for example, form controls, scroll bars, as well as CSS system colors. At the same time, this feature &lt;strong&gt;prevents browsers from applying any transformations on their own.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By the order of values, you can determine the default appearance. Here's the syntax for both CSS and the corresponding HTML meta tag:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;

&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;color-scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;dark&lt;/span&gt; &lt;span class="n"&gt;light&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(In the CSS example, the page author prefers &lt;strong&gt;dark&lt;/strong&gt; theme.)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color-scheme"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"light dark"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(In the HTML example, the page author prefers &lt;strong&gt;light&lt;/strong&gt; theme.)&lt;/p&gt;

&lt;p&gt;It is recommended to specify the &lt;code&gt;color-scheme&lt;/code&gt; via the meta tag, so the browser can adopt to the preferred scheme faster.&lt;/p&gt;




&lt;h3&gt;
  
  
  How to test your code
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Google Chrome Dev Tools&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can test your code with Google Chrome Dev Tools.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open up your Dev Tools Inspection panel by pressing &lt;code&gt;Command+Option+C&lt;/code&gt; (Mac) or &lt;code&gt;Control+Shift+C&lt;/code&gt; (Windows, Linux, Chrome OS).&lt;/li&gt;
&lt;li&gt;Click on the &lt;strong&gt;three dots&lt;/strong&gt; in the &lt;strong&gt;upper right corner&lt;/strong&gt; =&amp;gt; select &lt;strong&gt;More tools&lt;/strong&gt; =&amp;gt; click &lt;strong&gt;Rendering&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;From the Rendering tab you can find the emulation for &lt;code&gt;prefers-colors-scheme&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;See the screenshots below 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxp5k9l4zqn2i3ujfqrc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxp5k9l4zqn2i3ujfqrc7.png" alt="Image of Google Chrome Dev Tools' Rendering tab highlighting prefers-color-scheme emulation."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhilrpchexfd3yantizcc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhilrpchexfd3yantizcc.png" alt="Image of Google Chrome Dev Tools' Rendering tab prefers-color-scheme emulation turned to emulate dark mode."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Device OS settings&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As shown before, you can change the appearance from you device settings. Screenshots are from macOS and iOS. You can find the same settings from Android and Windows devices.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4llkxl3oc2oi1ju3mx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs4llkxl3oc2oi1ju3mx4.png" alt="Picture from macOS general settings."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf9qaupb806yxk67fobl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzf9qaupb806yxk67fobl.png" alt="Picture from iOS Display &amp;amp; Brightness settings."&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Resources and further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;CSS Only Dark Mode &lt;a href="https://codepen.io/laurilllll/pen/yLPKojZ" rel="noopener noreferrer"&gt;Codepen&lt;/a&gt; by me&lt;/li&gt;
&lt;li&gt;Color-scheme meta tag and CSS property at &lt;a href="https://web.dev/color-scheme/" rel="noopener noreferrer"&gt;web.dev&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CSS Media Feature &lt;code&gt;prefers-color-scheme&lt;/code&gt; at &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme" rel="noopener noreferrer"&gt;MDN Web Docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;CSS Custom Properties aka CSS Variables at &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/--*" rel="noopener noreferrer"&gt;MDN Web Docs&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Thank you 🙏
&lt;/h2&gt;

&lt;p&gt;I hope you found this article helpful 🔥&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://twitter.com/laurilllll" rel="noopener noreferrer"&gt;follow me on Twitter&lt;/a&gt; for more &lt;strong&gt;CSS&lt;/strong&gt;, &lt;strong&gt;Design System&lt;/strong&gt; and &lt;strong&gt;Figma&lt;/strong&gt; content 💪 &lt;/p&gt;

</description>
      <category>css</category>
      <category>design</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Figma Plugin API: How to Load and Use Fonts</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Sun, 06 Feb 2022 07:45:12 +0000</pubDate>
      <link>https://dev.to/laurilllll/figma-plugin-api-how-to-load-and-use-fonts-bj2</link>
      <guid>https://dev.to/laurilllll/figma-plugin-api-how-to-load-and-use-fonts-bj2</guid>
      <description>&lt;p&gt;Working with Figma text through the Figma Plugin API is a lot trickier than you might think. All the text inside Figma files are &lt;em&gt;nodes&lt;/em&gt; called &lt;strong&gt;TextNodes&lt;/strong&gt;. Essentially, nodes are &lt;strong&gt;layers&lt;/strong&gt; in Figma. With text nodes you have to think about &lt;em&gt;mixed styles&lt;/em&gt;, &lt;em&gt;missing fonts&lt;/em&gt; and &lt;em&gt;loading fonts&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For now, we concentrate on loading fonts.&lt;/p&gt;

&lt;p&gt;If you wish to change the content of a TextNode, &lt;strong&gt;you must load its font&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Here's one way of loading a font and manipulating text:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Load font via async function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFontLoadingFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFontAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Another function where we use the loaded font&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myAnotherFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create text layer&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myTextLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the font&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Set text to uppercase&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPPER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;// Set text content&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is my title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;// Add text layer to current page in Figma&lt;/span&gt;
  &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Use font only after the Promise is resolved&lt;/span&gt;
&lt;span class="nf"&gt;myFontLoadingFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;myAnotherFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;That's basically it. If you want to know more about this subject, just keep on reading.&lt;/p&gt;




&lt;h3&gt;
  
  
  Glossary
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;About loading fonts&lt;/li&gt;
&lt;li&gt;How to load fonts&lt;/li&gt;
&lt;li&gt;What can you do with fonts and text&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can find the official &lt;em&gt;Figma Plugin documentation&lt;/em&gt; &lt;a href="https://www.figma.com/plugin-docs/api/TextNode/" rel="noopener noreferrer"&gt;page about &lt;strong&gt;TextNodes&lt;/strong&gt; here&lt;/a&gt; but I believe the docs could be better and that's why I wrote this blog post.&lt;/p&gt;




&lt;h2&gt;
  
  
  About loading fonts
&lt;/h2&gt;

&lt;p&gt;The docs tells us this important thing about text and fonts:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The important thing with text is that &lt;strong&gt;changing the content of a text node requires its font to be loaded and that fonts are not always available.&lt;/strong&gt; If you attempt to change, say, &lt;code&gt;fontName&lt;/code&gt; without first loading the font for that text node, the plugin will throw an exception.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I found out that the exception will look like this in your console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68j548abd5v9xp9cyvqb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F68j548abd5v9xp9cyvqb.jpg" alt="Image of an error in console."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So, basically every time you make changes to text content or its properties, you have to load its font.&lt;/strong&gt; Only when you're changing properties like fill colour or stroke, you &lt;strong&gt;do not&lt;/strong&gt; need to load the fonts.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to load fonts
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TextNodes&lt;/strong&gt; have a property called &lt;code&gt;fontName&lt;/code&gt; which is a javascript object that contains the font family and font style. The default font is &lt;code&gt;{ family: "Roboto", style: "Regular" }&lt;/code&gt;. In our example we want to use &lt;strong&gt;Work Sans, Bold&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;(As a sidenote: You can load any font thats already accessible in the Figma editor. You cannot load fonts from the internet.)&lt;/p&gt;

&lt;p&gt;The documentation says that &lt;em&gt;"Loading a font is done via &lt;code&gt;figma.loadFontAsync(fontname)&lt;/code&gt;"&lt;/em&gt; and maybe for someone that is enough but, as a designer, I was a bit confused when I tried it and it didn't work.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Like in the docs =&amp;gt; figma.loadFontAsync(fontname)&lt;/span&gt;
&lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFontAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;On it's own, this code isn't enough. This is when the &lt;strong&gt;error&lt;/strong&gt; appears in the console. As we dive deeper into the docs we find this about the &lt;strong&gt;loadFontAsync&lt;/strong&gt; property:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;(loadFontAsync) Makes a font available in the plugin for use when creating and modifying text. Calling this function is necessary to modify any property of a text node that may cause the rendered text to change, including .characters, .fontSize, .fontName, etc.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And from it's signature (found in the docs) &lt;code&gt;loadFontAsync(fontName: FontName): Promise&amp;lt;void&amp;gt;&lt;/code&gt; we can see that it returns a &lt;strong&gt;Promise&lt;/strong&gt;. So, we must enchance our code by creating an "async/await" function:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFontLoadingFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFontAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After the &lt;strong&gt;loadFontAsync&lt;/strong&gt; Promise is resolved, we can use the &lt;code&gt;then()&lt;/code&gt; method that returns a new Promise and when that is a success we can do what we initially wanted.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;myFontLoadingFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Success!&lt;/span&gt;

  &lt;span class="c1"&gt;// Add your code here to do something with the loaded font!&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can read more about &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" rel="noopener noreferrer"&gt;Promises&lt;/a&gt; and the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then" rel="noopener noreferrer"&gt;&lt;code&gt;then()&lt;/code&gt;&lt;/a&gt; from the MDN docs.&lt;/p&gt;

&lt;p&gt;All the code once more:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Load font via async function&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFontLoadingFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loadFontAsync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Another function where we use the loaded font&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myAnotherFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Create text layer&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myTextLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c1"&gt;// Set the font&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fontName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Work Sans&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bold&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Set text to uppercase&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textCase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;UPPER&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;// Set text content&lt;/span&gt;
  &lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is my title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="c1"&gt;// Add text layer to current page in Figma&lt;/span&gt;
  &lt;span class="nx"&gt;figma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentPage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myTextLayer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Use font only after the Promise is resolved&lt;/span&gt;
&lt;span class="nf"&gt;myFontLoadingFunction&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;myAnotherFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;h2&gt;
  
  
  What can you do with fonts and text
&lt;/h2&gt;

&lt;p&gt;After you have your fonts loaded you can use the following properties and functions of a TextNode:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;characters&lt;/strong&gt; = set/write your text content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fontSize&lt;/strong&gt; = set font size&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;fontName&lt;/strong&gt; = set font family and style/weight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;textStyleId&lt;/strong&gt; = set TextStyle using TextStyle id&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;textCase&lt;/strong&gt; = set text casing to uppercase etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;textDecoration&lt;/strong&gt; = set decoration to underline/strikethrough&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;letterSpacing&lt;/strong&gt; = set letter spacing in pixels or percents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;lineHeight&lt;/strong&gt; = set line height in pixels or percents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeFontSize()&lt;/strong&gt; = set font size to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeFontName()&lt;/strong&gt; = set font to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeTextCase()&lt;/strong&gt; = set text casing to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeTextDecoration()&lt;/strong&gt; = set text decoration to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeLetterSpacing()&lt;/strong&gt; = set letter spacing to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeLineHeight()&lt;/strong&gt; = set line height to characters in range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;setRangeTextStyleId()&lt;/strong&gt; = set TextStyle to characters in range&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check out all the &lt;strong&gt;TextNode&lt;/strong&gt; properties and functions &lt;a href="https://www.figma.com/plugin-docs/api/TextNode/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Have fun developing Figma plugins 🔥 I hope you found this article helpful!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/laurilllll" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt; for more &lt;strong&gt;Figma&lt;/strong&gt;, &lt;strong&gt;CSS&lt;/strong&gt; and &lt;strong&gt;Design System&lt;/strong&gt; content 💪 &lt;/p&gt;

</description>
      <category>typescript</category>
      <category>html</category>
      <category>figma</category>
      <category>plugin</category>
    </item>
    <item>
      <title>How to create responsive typography using CSS — Three different methods explained</title>
      <dc:creator>Lauri Lännenmäki</dc:creator>
      <pubDate>Wed, 20 Jan 2021 20:52:14 +0000</pubDate>
      <link>https://dev.to/laurilllll/how-to-create-responsive-typography-using-css-three-different-methods-explained-50f8</link>
      <guid>https://dev.to/laurilllll/how-to-create-responsive-typography-using-css-three-different-methods-explained-50f8</guid>
      <description>&lt;p&gt;Good typography is one of the key elements of a website. Let's take a look at &lt;strong&gt;three different methods&lt;/strong&gt; on &lt;strong&gt;how to create responsive typography using CSS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The three methods are:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Responsive typography using &lt;strong&gt;only media queries&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Responsive typography using &lt;strong&gt;a CSS custom property as a multiplier&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Responsive typography using &lt;strong&gt;the CSS clamp() function&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Check out the final &lt;a href="https://codepen.io/laurilllll/pen/ZEWZvBg"&gt;Codepen with all the methods&lt;/a&gt;. Resize the viewport to see the effect.&lt;/p&gt;




&lt;h3&gt;
  
  
  Why should you use responsive typography?
&lt;/h3&gt;

&lt;p&gt;The web is used on various screen sizes. Your site has to work on &lt;strong&gt;mobile&lt;/strong&gt;, &lt;strong&gt;tablet&lt;/strong&gt;, &lt;strong&gt;laptop&lt;/strong&gt;, &lt;strong&gt;desktop&lt;/strong&gt; and basically everything in between so there's a lot to take into consideration.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All of the method examples below are &lt;strong&gt;simplified&lt;/strong&gt; as they only cover &lt;strong&gt;three selectors&lt;/strong&gt; and &lt;strong&gt;one breakpoint&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can use this simple &lt;strong&gt;HTML&lt;/strong&gt; to try out all the methods in this tutorial:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;How to create responsive typography using CSS&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  Vestibulum molestie sapien eget orci pellentesque, et aliquam lectus convallis. Phasellus neque velit, ultricies ut lacus at, finibus lobortis dui. Proin eget diam elit.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;Three different methods explained&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
  Pellentesque sagittis nisl nec rhoncus porta. Quisque luctus turpis nec turpis consequat fermentum et vitae diam.
&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Let's dig in!&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 1: Responsive typography using only media queries
&lt;/h2&gt;

&lt;p&gt;This is the most basic method in our list.&lt;/p&gt;

&lt;p&gt;Simply, &lt;strong&gt;declare your text styles&lt;/strong&gt; and &lt;strong&gt;increase the font-size on bigger screens&lt;/strong&gt; using a breakpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Declare text styles */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Increase font sizes by 1.5x on bigger screens */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the result from this &lt;a href="https://codepen.io/laurilllll/pen/bGwJbJb"&gt;Codepen&lt;/a&gt;. Resize the viewport to see the effect.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/laurilllll/embed/bGwJbJb?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Using this method is totally fine and it does the job very well.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;downside is the large amount of code&lt;/strong&gt; you have to write. The codebase gets larger with every new selector you need to add. You have to write the styles &lt;strong&gt;separately&lt;/strong&gt; for &lt;strong&gt;every selector in each breakpoint&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In a real world you would probably have text selectors &lt;strong&gt;h1&lt;/strong&gt;, &lt;strong&gt;h2&lt;/strong&gt;, &lt;strong&gt;h3&lt;/strong&gt;, &lt;strong&gt;h4&lt;/strong&gt;, &lt;strong&gt;h5&lt;/strong&gt;, &lt;strong&gt;h6&lt;/strong&gt;, &lt;strong&gt;p&lt;/strong&gt; and at least &lt;strong&gt;two breakpoints&lt;/strong&gt;. At that point, this code is would've already gone &lt;strong&gt;from 20 lines to 67 lines&lt;/strong&gt;. That's &lt;strong&gt;3.35x&lt;/strong&gt; increase in the amount of code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The next method will show how to &lt;strong&gt;decrease the code amount&lt;/strong&gt; and make it &lt;strong&gt;easier to maintain!&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 2: Responsive typography using a CSS custom property as a multiplier
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CSS custom properties&lt;/strong&gt; (variables) are super powerful. In the previous method, we increased the font sizes &lt;em&gt;manually&lt;/em&gt; one selector at a time. Now, we'll &lt;strong&gt;declare a multiplier variable&lt;/strong&gt; for the font-sizes and only &lt;strong&gt;increase the value of the multiplier&lt;/strong&gt; inside a breakpoint.&lt;/p&gt;

&lt;p&gt;Let's look at the code example in full and then break it down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Declare a font size multiplier variable */&lt;/span&gt;
&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Increase the size of the multiplier on bigger screens */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Declare text styles using calc() function and the multiplier */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.5em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the result from this &lt;a href="https://codepen.io/laurilllll/pen/ZEpZzPB"&gt;Codepen&lt;/a&gt;. Resize the viewport to see the effect.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/laurilllll/embed/ZEpZzPB?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The first step&lt;/strong&gt; is to &lt;strong&gt;declare a variable&lt;/strong&gt; that we use to control our font size later on. We set the default value to &lt;strong&gt;1&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The second step&lt;/strong&gt; is to &lt;strong&gt;increase the multiplier value&lt;/strong&gt; inside a breakpoint. Unlike SASS variables, CSS custom properties &lt;strong&gt;can be used inside media queries&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;48rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The last step&lt;/strong&gt; is to declare our font-sizes but this time we use &lt;strong&gt;the calc() function&lt;/strong&gt; so we can utilise our &lt;strong&gt;multiplier&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.5em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1em&lt;/span&gt; &lt;span class="err"&gt;*&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;strong&gt;we only need to declare our font sizes once&lt;/strong&gt;. This is a huge improvement compared to the first method.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Compared to the first method, we only have &lt;strong&gt;17 lines of code compared to 20&lt;/strong&gt;. If we would add four more selectors and one breakpoint, our code would &lt;strong&gt;only increase from 17 lines to 34&lt;/strong&gt;. Remember that using the first method it would require &lt;strong&gt;67 lines&lt;/strong&gt;. Almost twice as much.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The decrease of code is due to our elegant way of using a &lt;strong&gt;CSS custom property as a multiplier&lt;/strong&gt;. Adding another breakpoint takes only &lt;strong&gt;three lines of code&lt;/strong&gt; because we don't have to modify our font sizes at all. The code is also a lot &lt;strong&gt;easier to maintain and modify&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Adding breakpoints is as simple as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Add more breakpoints */&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;64rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.75&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80rem&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--text-multiplier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To the user, this methods &lt;strong&gt;looks exactly the same&lt;/strong&gt; as the first but &lt;strong&gt;the code is much better&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Next up, we'll take a look at a &lt;strong&gt;new CSS clamp() function&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Method 3: Responsive typography using the CSS clamp() function
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;clamp() function&lt;/strong&gt; is pretty powerful! You can set a value using three parameters: &lt;strong&gt;a minimum value&lt;/strong&gt;, &lt;strong&gt;a preferred value&lt;/strong&gt; and &lt;strong&gt;a maximum value&lt;/strong&gt;. Basically you'll have a 3-in-1 value!&lt;/p&gt;

&lt;p&gt;Example declaration for responsive text using the &lt;strong&gt;clamp() function&lt;/strong&gt; looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;font-size: clamp(2rem, 5vw, 3rem);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows us to create responsive typography &lt;strong&gt;without any media queries&lt;/strong&gt;. &lt;strong&gt;With only one line of code&lt;/strong&gt; we set the minimum value (mobile), the maximum value (desktop) and the preferred value.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The font size will become fluid&lt;/strong&gt; as it will always be the &lt;strong&gt;preferred value inside the min-max range&lt;/strong&gt;. Very powerful!&lt;/p&gt;

&lt;p&gt;To set the responsive typography for our demo, it is as simple as this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* Declare text styles */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;/* Font minimum, preferred and maximum value */&lt;/span&gt;
  &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;clamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--min&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--val&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;var&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--max&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Font size variables */&lt;/span&gt;
&lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* minimum value */&lt;/span&gt;
  &lt;span class="py"&gt;--val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* preferred value = 5% viewport width */&lt;/span&gt;
  &lt;span class="py"&gt;--max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* maximum value */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* minimum value */&lt;/span&gt;
  &lt;span class="py"&gt;--val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c"&gt;/* preferred value = 4% viewport width */&lt;/span&gt;
  &lt;span class="py"&gt;--max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.25em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  &lt;span class="c"&gt;/* maximum value */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--min&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c"&gt;/* minimum value */&lt;/span&gt;
  &lt;span class="py"&gt;--val&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.5vw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* preferred value = 2.5% viewport width */&lt;/span&gt;
  &lt;span class="py"&gt;--max&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* maximum value */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check out the result from this &lt;a href="https://codepen.io/laurilllll/pen/ExgJYRm"&gt;Codepen&lt;/a&gt;. Resize the viewport to see the effect.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/laurilllll/embed/ExgJYRm?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you look at the code, you'll see that by using &lt;strong&gt;CSS custom properties together with the clamp() function&lt;/strong&gt; we are able to &lt;strong&gt;declare all the text styles at the same time with only on line of code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;After that, we just set the &lt;strong&gt;--min&lt;/strong&gt;, &lt;strong&gt;--val&lt;/strong&gt; and &lt;strong&gt;--max&lt;/strong&gt; custom properties for each selector and we are done!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CSS custom properties can be &lt;strong&gt;scoped inside selectors&lt;/strong&gt; so you can &lt;strong&gt;use the same custom properties with multiple selectors&lt;/strong&gt; just like we have done here with our &lt;strong&gt;h1&lt;/strong&gt;, &lt;strong&gt;h2&lt;/strong&gt; and &lt;strong&gt;p&lt;/strong&gt;. These custom properties will not clash together even though they have the same name.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This method takes up 18 lines of code and with four more selectors and one breakpoint it would be 38 lines. So, it's slightly larger than on the second method but we get &lt;strong&gt;fluid typography&lt;/strong&gt; in return.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The &lt;strong&gt;clamp() function&lt;/strong&gt; is pretty new, so you should check if it has the browser support you need from &lt;a href="https://caniuse.com/css-math-functions"&gt;caniuse.com&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;CSS is powerful!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In many cases, there's more than one way to achieve the desired result.&lt;/p&gt;

&lt;p&gt;If you read this far, thank you! I hope you learned something new.&lt;/p&gt;

&lt;p&gt;Here's the final &lt;a href="https://codepen.io/laurilllll/pen/ZEWZvBg"&gt;Codepen with all the methods&lt;/a&gt; once more. Resize the viewport to see the effect.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/laurilllll/embed/ZEWZvBg?height=600&amp;amp;default-tab=css,result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Thank you 🙏
&lt;/h2&gt;

&lt;p&gt;I hope you found this article helpful 🔥&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://twitter.com/laurilllll"&gt;follow me on Twitter&lt;/a&gt; for more &lt;strong&gt;CSS&lt;/strong&gt;, &lt;strong&gt;Design System&lt;/strong&gt; and &lt;strong&gt;Figma&lt;/strong&gt; content 💪 &lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
