<?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: Scott Boyle</title>
    <description>The latest articles on DEV Community by Scott Boyle (@monospaced).</description>
    <link>https://dev.to/monospaced</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1149083%2Faf3b7375-cdf0-4353-b06a-007707ebb924.jpg</url>
      <title>DEV Community: Scott Boyle</title>
      <link>https://dev.to/monospaced</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/monospaced"/>
    <language>en</language>
    <item>
      <title>Problems with font distribution, and why versioning matters</title>
      <dc:creator>Scott Boyle</dc:creator>
      <pubDate>Wed, 07 May 2025 12:13:07 +0000</pubDate>
      <link>https://dev.to/measuredco/problems-with-font-distribution-and-why-versioning-matters-1foe</link>
      <guid>https://dev.to/measuredco/problems-with-font-distribution-and-why-versioning-matters-1foe</guid>
      <description>&lt;h1&gt;
  
  
  Problems with Inter, and why font versioning matters
&lt;/h1&gt;

&lt;p&gt;When we &lt;a href="https://measured.co/blog/new-visual-identity" rel="noopener noreferrer"&gt;refreshed the Measured visual identity&lt;/a&gt;, a website rebuild was always part of that scope.&lt;/p&gt;

&lt;p&gt;We expected to make some careful typographic refinements in that process. But what followed was an unexpected deep dive into how fonts are distributed and integrated into modern web infrastructure.&lt;/p&gt;

&lt;p&gt;This is an account of what we encountered, the choices we made, and some thoughts that may be relevant to teams using fonts — and those making and distributing them. We’ve gone quite heavy with hyperlinks by way of explaining terms if needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Though true when we were rebuilding the site around December 2024, some of the detail of what follows has since changed. I’ve done my best to call this out when that’s the case. Hopefully the broader thrust is still useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  The plan
&lt;/h2&gt;

&lt;p&gt;When we embarked on the brand refresh and site rebuild, we landed on &lt;a href="https://rsms.me/inter/" rel="noopener noreferrer"&gt;Inter&lt;/a&gt; for its &lt;a href="https://dev.to/dog_smile_factory/5-reasons-to-give-inter-fonts-a-try-46i2"&gt;many benefits&lt;/a&gt; — readability and ease of implementation among them.&lt;/p&gt;

&lt;p&gt;We wanted to use &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#google-fonts" rel="noopener noreferrer"&gt;&lt;code&gt;next/font/google&lt;/code&gt;&lt;/a&gt; to implement the Inter Google Font for its magical ways of optimising font performance. We wanted a fast site with green &lt;a href="https://developer.chrome.com/docs/lighthouse/overview" rel="noopener noreferrer"&gt;Lighthouse&lt;/a&gt; scores. (Along with images, custom fonts are a major cause of poor site performance.)&lt;/p&gt;

&lt;p&gt;But when we came to implementation, we ran into some blockers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Inter on Google Fonts didn’t have some OpenType features and glyphs that we wanted (rounded “quotes” and commas, for example)&lt;/li&gt;
&lt;li&gt;Google Fonts not having Inter Italic at all (true at the time, but no longer&lt;sup id="fnref1"&gt;1&lt;/sup&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Inter-vention needed
&lt;/h2&gt;

&lt;p&gt;So - how best to optimally integrate Inter (Italic) with Next.js if it's not available as a Google Font? &lt;/p&gt;

&lt;p&gt;Our answer was to use &lt;a href="https://nextjs.org/docs/pages/building-your-application/optimizing/fonts#local-fonts" rel="noopener noreferrer"&gt;&lt;code&gt;next/font/local&lt;/code&gt;&lt;/a&gt;, a feature that provides similar font optimisations to next/font/google, but for self-hosted font files.&lt;/p&gt;

&lt;p&gt;But though this method worked, performance was significantly downgraded compared to using Google Fonts, and Lighthouse scores were distinctly non-green.&lt;/p&gt;

&lt;p&gt;There were a couple of reasons for this: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Downloading Inter from Rasmus’ site offers no way to subset, meaning that our self-hosted Inter files were very large (weighing in at 740kb combined)&lt;/li&gt;
&lt;li&gt;It turns out &lt;code&gt;next/font/local&lt;/code&gt; doesn’t optimise quite as well as next/font/google, which leverages Google's CDN caching &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Like the good stoics we are, we dialled into problem 1 as being within our power to affect, so we looked to subset the fonts as aggressively as possible to reduce the file size and get us back into the green.&lt;/p&gt;

&lt;p&gt;After much trial and error, we eventually managed to subset the two Inter files so that they had all the glyphs we needed while remaining as small as possible. To do this, we used &lt;a href="https://github.com/fonttools/fonttools" rel="noopener noreferrer"&gt;fontTools&lt;/a&gt; to try various subsetting and optimising techniques, and &lt;a href="https://fontdrop.info/" rel="noopener noreferrer"&gt;FontDrop&lt;/a&gt; to test the output. &lt;/p&gt;

&lt;p&gt;In the end we arrived at this command line magic spell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pyftsubset InterVariable.ttf &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--unicodes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;U+0000,U+0020-007E,U+00A0-00AC,U+00AE-00FF,U+0131, &lt;span class="se"&gt;\&lt;/span&gt;
            U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC, &lt;span class="se"&gt;\&lt;/span&gt;
            U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+2002, &lt;span class="se"&gt;\&lt;/span&gt;
            U+2009,U+200B,U+2013-2014,U+2018-201A,U+201C-201E, &lt;span class="se"&gt;\&lt;/span&gt;
            U+2022,U+2026,U+2032-2033,U+2039-203A,U+2044,U+2074, &lt;span class="se"&gt;\&lt;/span&gt;
            U+20AC,U+2122,U+2191,U+2193,U+2212,U+FEFF &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--layout-features&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;calt,ccmp,dnom,frac,kern,locl,mark,mkmk,numr &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--flavor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;woff2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result was that our self-hosted files had a combined size of 144kb and Lighthouse performance scores were back in the green — not quite as good as they would have been with Google Fonts, but green nonetheless. &lt;/p&gt;

&lt;p&gt;Most importantly: our site speed was fast again, and with the custom-designed true Italics and all the other typographical nuances we were after.&lt;/p&gt;

&lt;h2&gt;
  
  
  The need for font versioning
&lt;/h2&gt;

&lt;p&gt;So how does this lead us to font versioning? &lt;/p&gt;

&lt;p&gt;A good example is that Inter 3 didn’t have a separate file for Italics as they were handled with a variable font slant axis. When Inter 4 removed this variable axis and replaced it with a completely separate and custom designed Italic file, it took — and is still taking — tools a long time to catch up. &lt;/p&gt;

&lt;p&gt;And because font versioning isn't really considered, someone using Inter from Google Fonts would have their italics switched from the variable font slant axis in Inter 3, to faux italics with Inter 4 overnight. &lt;/p&gt;

&lt;p&gt;And all this without really any visibility. Google Fonts doesn't announce version changes, or even show the font version (at least not clearly that we can find — answers on a postcard). &lt;/p&gt;

&lt;p&gt;To double check what version they were serving, we had to use FontDrop. So you really need to be tuned in to the font’s release history, and to typographical nuances in general, to have any idea about this. &lt;/p&gt;

&lt;p&gt;Though it was a mission, digging into the details paid off for us. We were able to achieve the typographic clarity we wanted without significantly compromising performance. &lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Google Fonts now has all the Inter OpenType features and glyphs, plus Inter Italic, so the original problem is nearly solved. However, at time of writing, &lt;code&gt;next/font/google&lt;/code&gt; still does not include Inter Italic. Hopefully it will be added in future — we should probably open a pull request! ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>frontend</category>
      <category>nextjs</category>
      <category>performance</category>
    </item>
    <item>
      <title>Understanding the trade-offs of using Tailwind CSS</title>
      <dc:creator>Scott Boyle</dc:creator>
      <pubDate>Tue, 11 Feb 2025 10:55:05 +0000</pubDate>
      <link>https://dev.to/measuredco/understanding-the-trade-offs-of-using-tailwind-css-39dj</link>
      <guid>https://dev.to/measuredco/understanding-the-trade-offs-of-using-tailwind-css-39dj</guid>
      <description>&lt;p&gt;If you work in web development, there’s a good chance you’ve come across &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;Tailwind CSS&lt;/a&gt;. If not, it’s a good tool to have on your radar.&lt;/p&gt;

&lt;p&gt;Tailwind is a CSS framework that uses a &lt;a href="(https://www.ituonline.com/tech-definitions/what-is-utility-first-css/)"&gt;utility-first&lt;/a&gt; approach. Elements are styled directly, without needing to leave your HTML.&lt;/p&gt;

&lt;p&gt;Its promise is that you can build modern web pages quickly and simply. Choosing a utility-first framework could have a significant impact on your project — particularly in maintenance and scaling. It undoubtedly has benefits, but they come with trade-offs.  &lt;/p&gt;

&lt;p&gt;In this post we want to explore some counterpoints to those benefits. Hopefully this will help you decide whether it’s the right tool for your project. &lt;/p&gt;

&lt;p&gt;In no way is this intended as a take-down. In the quest to make life better for the people that build the web, Tailwind is a positive force. We write this from the point of view of practitioners evaluating a tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Tailwind
&lt;/h2&gt;

&lt;p&gt;Much has been written on the benefits of Tailwind, so we’ll cover those we see in brief:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No custom CSS:&lt;/strong&gt; It provides ready-to-use utility classes that let you style elements directly in your markup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Less need for naming conventions:&lt;/strong&gt; It largely does away with creating and naming custom classes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good performance:&lt;/strong&gt; It’s a small library with production builds that automatically strip out unused CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS knowledge is less important:&lt;/strong&gt; There’s less need for CSS skills on your team — lots of developers know Tailwind.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Good design defaults:&lt;/strong&gt; You can mostly trust Tailwind’s defaults to quickly help you build something decent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to customise:&lt;/strong&gt; If you do want to edit its defaults, it makes this easy through changes to a single configuration file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Design consistency:&lt;/strong&gt; Developers can apply consistent styles without having to choose exact values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive design:&lt;/strong&gt; You can apply classes conditionally at various breakpoints without writing additional CSS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fast iteration:&lt;/strong&gt; You can test and adjust things quickly, making changes directly in the markup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Well supported&lt;/strong&gt; Tailwind is backed by many plugins, extensive documentation and well-known paradigms.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more on the benefits of utility-first, see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;John Polacek’s &lt;a href="https://johnpolacek.github.io/the-case-for-atomic-css/" rel="noopener noreferrer"&gt;The Case for Atomic / Utility-First CSS&lt;/a&gt; (&lt;a href="https://tailwindcss.com/docs/utility-first" rel="noopener noreferrer"&gt;via Tailwind&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Ryan Flynn’s &lt;a href="https://medium.com/@f4lc0n.d00d/mastering-tailwind-css-an-in-depth-look-at-the-utility-first-framework-b8c939b02213" rel="noopener noreferrer"&gt;Mastering Tailwind CSS: An In-Depth Look at the Utility-First Framework&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;This &lt;a href="https://www.reddit.com/r/webdev/comments/13rai6v/i_dont_understand_the_advantages_of_tailwind/" rel="noopener noreferrer"&gt;Reddit thread&lt;/a&gt;, where the community shares benefits from a boots-on-the-ground perspective&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Counterpoints to Tailwind’s documentation
&lt;/h2&gt;

&lt;p&gt;Many of Tailwind’s benefits are clear-cut. But we’ve also seen cases made that we think require caveats, including those in Tailwind’s own &lt;a href="https://tailwindcss.com/docs/styling-with-utility-classes" rel="noopener noreferrer"&gt;Utility-First Fundamentals&lt;/a&gt;. Let’s look at these in turn.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Effort saved with class names and selectors
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;You don't spend any time coming up with class names [and] making decisions about selectors […] so your designs come together very fast.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://martinfowler.com/bliki/TwoHardThings.html" rel="noopener noreferrer"&gt;Naming things is hard&lt;/a&gt;. But a well-named styling or theming architecture is a worthwhile investment on large projects.&lt;/p&gt;

&lt;p&gt;Thoughtfully-named styles help teams develop a shared language for components and layouts, making it easier to collaborate across disciplines. This reinforces consistency and helps make sure that intentional design choices are carried forward as the project evolves. Consequently, experienced CSS people generally don’t spend time agonising over class names and selectors.&lt;/p&gt;

&lt;p&gt;In contrast, relying too heavily on utility-first classes can result in context being lost. For example, developers have to interpret design intent from raw style rules rather than clear names.&lt;/p&gt;

&lt;p&gt;Going further, advanced CSS selectors can make it easy to do things that are much harder, or cumbersome, using only utilities. For example, &lt;a href="https://nerdy.dev/hover-not-hover-sorry-not-sorry" rel="noopener noreferrer"&gt;focus by demotion&lt;/a&gt; can be achieved in a few lines of CSS, but is an absolute casserole to do in Tailwind — less than ideal if the object is to keep your codebase simple.&lt;/p&gt;

&lt;p&gt;Naming CSS classes isn’t that hard in any case. Well-considered &lt;a href="https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md" rel="noopener noreferrer"&gt;naming conventions&lt;/a&gt; provide a straightforward way to choose intuitive class names.&lt;/p&gt;

&lt;p&gt;There are also technical solutions that make naming CSS classes easier. For example, &lt;a href="https://github.com/css-modules/css-modules/blob/master/docs/local-scope.md" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt; lets you &lt;a href="https://github.com/css-modules/css-modules/blob/master/docs/local-scope.md" rel="noopener noreferrer"&gt;scope class names locally&lt;/a&gt;. This means you can use simple, logical names without worrying about conflicts in the global namespace.&lt;/p&gt;

&lt;p&gt;Overall, taking the trouble to develop a well-named styling architecture may mean more up-front effort, but it can pay dividends longer term.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. CSS stops growing
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Since utility classes are so reusable, your CSS doesn't continue to grow linearly with every new feature you add to a project.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is true, but by using Tailwind your markup gets bigger every time you add a utility class. Consequently, it becomes harder to read and maintain.&lt;/p&gt;

&lt;p&gt;Front-end abstractions are about more than CSS. Tailwind encourages utility-first development to avoid thinking about encapsulation and accelerate development, but this can have diminishing returns.&lt;/p&gt;

&lt;p&gt;In our experience, it can mean time-pressed developers choose to keep adding Tailwind classes rather than breaking up their components into smaller, systematic pieces. Over time, this can make your front-end cumbersome and difficult to scale. &lt;/p&gt;

&lt;p&gt;When you have a system of composable components, you rarely need to write new CSS. You can simply reuse the components.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Safer changes
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Adding or removing a utility class to an element only ever affects that element, so you never have to worry about accidentally breaking something [on] another page that's using the same CSS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a problem that has been solved by hard encapsulation in general. This means a component’s styles are confined to only that component — they can’t leak to other parts of the project. &lt;/p&gt;

&lt;p&gt;Of course, Tailwind’s approach is a form of hard encapsulation, but it’s by no means the only game in town.&lt;/p&gt;

&lt;p&gt;With CSS’s natural inheritance, styles can cascade across elements and contexts, sometimes unpredictably. Tailwind defines styles locally in the markup, sidestepping CSS inheritance by making sure that each element’s styles are explicitly declared. &lt;/p&gt;

&lt;p&gt;This can reduce unintended side effects, but it also bypasses one of CSS’s strengths: the ability to create flexible systems that adapt globally with minimal duplication.&lt;/p&gt;

&lt;p&gt;There are others tools available to do hard encapsulation, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/css-modules/css-modules" rel="noopener noreferrer"&gt;CSS Modules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM" rel="noopener noreferrer"&gt;shadowDOM&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nextjs.org/docs/app/building-your-application/styling/css-in-js" rel="noopener noreferrer"&gt;CSS-in-JS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, if your project is relatively simple, soft encapsulation through naming conventions like &lt;a href="https://github.com/suitcss/suit/blob/master/doc/naming-conventions.md" rel="noopener noreferrer"&gt;SUIT CSS&lt;/a&gt; may be all you need.&lt;/p&gt;

&lt;p&gt;In sum, there are many ways to architect your styles so you never have to think about unintended side effects. Weigh up the options and choose an approach that works for you.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Designing with constraints
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;Using inline styles, every value is a magic number. With utilities, you’re choosing styles from a predefined design system, which makes it much easier to build visually consistent UIs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We don’t advocate for inline styles, but this does raise a question about the problems Tailwind solves.&lt;/p&gt;

&lt;p&gt;Magic numbers are arbitrary values in CSS that lack clear purpose. They tend to persist for fear of breaking something. Or they break things when they’re removed because their purpose wasn’t clear.&lt;/p&gt;

&lt;p&gt;Avoiding magic numbers is good practice. But Tailwind utilities can be magic numbers too. In fact, Tailwind provides advice on &lt;a href="https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values" rel="noopener noreferrer"&gt;how to use arbitrary values&lt;/a&gt;.&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Designing to constraints can be done in several ways. CSS Custom Properties enforced by linting is a technique we’ve used at Measured.&lt;/p&gt;

&lt;p&gt;Tailwind’s out-of-the-box utilities define a system, but it’s broad, with little guidance on usage. They can be an aid to consistency but they’re not a panacea.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Responsive design, hover, focus, and other states
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;You can’t use media queries in inline styles, but you can use Tailwind’s responsive variants to build fully responsive interfaces easily.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inline styles can’t target states like hover or focus, but Tailwind’s state variants make it easy to style those states with utility classes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These points highlight Tailwind’s advantages over raw inline styles, but they’re less about why Tailwind is uniquely good and more about why inline styles are problematic. &lt;/p&gt;

&lt;p&gt;While it’s true that Tailwind’s utilities can simplify responsive design and state-based styling, these problems can also be solved in other ways.&lt;/p&gt;

&lt;p&gt;Libraries like &lt;a href="https://css-hooks.com/docs/introduction/" rel="noopener noreferrer"&gt;CSS Hooks&lt;/a&gt; let you manage responsive designs and state styles directly in JavaScript. Similarly, approaches like &lt;a href="https://styled-components.com/" rel="noopener noreferrer"&gt;styled-components&lt;/a&gt; or other CSS-in-JS libraries let you define styles with responsive and state-based capabilities in a flexible, programmatic way.&lt;/p&gt;

&lt;p&gt;Tailwind makes these tasks easier in its own context, but is that a reason to choose Tailwind?&lt;/p&gt;

&lt;h2&gt;
  
  
  Other considerations
&lt;/h2&gt;

&lt;p&gt;Here are two more considerations, though these aren’t in reference to Tailwind’s documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential brand conflicts
&lt;/h3&gt;

&lt;p&gt;Tailwind makes design choices so designers and developers don't have to. This can result in a recognisable look. Those familiar with Tailwind can often spot Tailwind-built sites.&lt;/p&gt;

&lt;p&gt;However, every brand has its own architecture and identity (sometimes complex), which needs to be represented in UI design decisions. Though Tailwind supports theming, this is done within the constraints of Tailwind’s naming conventions, which might not make sense for your brand.&lt;/p&gt;

&lt;p&gt;This is more complex with multi-brand systems, where one of two outcomes is likely. Either the resulting solution will make all the brands look like Tailwind, or it requires so many escape hatches that you'd be better off not using Tailwind in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  You need to know some CSS anyway
&lt;/h3&gt;

&lt;p&gt;To be most effective with Tailwind, you still need to have some understanding of the underlying CSS. For example, to understand Tailwind's &lt;a href="https://tailwindcss.com/docs/flex" rel="noopener noreferrer"&gt;flex&lt;/a&gt; class, you probably need to understand how &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_flexible_box_layout/Basic_concepts_of_flexbox" rel="noopener noreferrer"&gt;flexbox&lt;/a&gt; works.&lt;/p&gt;

&lt;p&gt;If you only learn through Tailwind, you will only have a truncated understanding of CSS. This means you will likely struggle to debug more complicated issues, or transfer your skills to other CSS architectures in the future.&lt;/p&gt;

&lt;p&gt;To some extent, it’s an example of ecosystem lock-in, and one that creates barriers for experienced CSS people. Sometimes the class names are intuitive, and sometimes they’re not. Modern CSS is pretty concise in any case. &lt;/p&gt;

&lt;h2&gt;
  
  
  All things considered…
&lt;/h2&gt;

&lt;p&gt;There are no silver bullets when making web UI. Weighing up CSS against Tailwind means weighing up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time spent naming CSS classes against time spent reading and parsing utility names&lt;/li&gt;
&lt;li&gt;CSS size against markup size&lt;/li&gt;
&lt;li&gt;Inheritance against encapsulation&lt;/li&gt;
&lt;li&gt;Opinionated systems against flexible systems&lt;/li&gt;
&lt;li&gt;CSS expertise against Tailwind expertise &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tailwind’s utility-first approach can work well for small-to-medium projects where speed and cost-efficiency are top priorities. This is especially true if you already have Tailwind skills — or a lack of CSS skills — on deck. &lt;/p&gt;

&lt;p&gt;But for larger projects or teams with established CSS practices, it introduces challenges around readability, maintainability, and scalability. The larger and more complex your project, the less sense Tailwind might make.&lt;/p&gt;

&lt;p&gt;Thank you to &lt;a href="https://bsky.app/profile/mattlynch.dev" rel="noopener noreferrer"&gt;Matthew Lynch&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/chrisvilla/" rel="noopener noreferrer"&gt;Chris Villa&lt;/a&gt; for contributing insights and feedback to this article.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;We recommend linting to prevent magic numbers in Tailwind, using &lt;a href="https://github.com/francoismassart/eslint-plugin-tailwindcss/blob/master/docs/rules/no-arbitrary-value.md" rel="noopener noreferrer"&gt;ESLint-plugin-tailwindcss&lt;/a&gt;, for example. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>webdev</category>
      <category>web</category>
      <category>css</category>
      <category>tailwindcss</category>
    </item>
  </channel>
</rss>
