For design systems, consistency and comprehension are everything. A good design system ensures consistency of implementation through the configuration of code that implements it. It needs to be:
- easy to comprehend without foregoing the nuance that good design requires;
- scalable and maintainable without compromising consistency.
Using my default stack of React with Tailwind, I'll show you how setting your own defaults for typography, colour and spacing is not just the starting point for differentiating your app's look and feel. More importantly, it drastically cuts down the code we have to write and maintain, which reduces the mental load of implementing styles in a systematic, consistent and error-free way.
I'll start with a major criticism that I see all the time, and then breakdown a series of configuration steps that I use to solve it.
Ease of use does not equate to ease of knowledge
Tailwind makes it easy for developers to write styles, which is great for rapid prototyping. But that ease doesn't guarantee good design or a scalable, maintainable design system.
Defaults and zero-config tools like Tailwind are the infrastructure pace layer that create more time for building. But if you're scaling an app that uses a design system to differentiate itself, you can't rely solely on "free as in lunch" out-of-the-box configs.
If you run with the default Tailwind config and push style management to the application of classes on components, the result is often a mess of hard-to-reason-about classes spread across components, masquerading as a design system.
Above is a prime example. It is almost illegible and takes signficant time to understand, let alone manipulate. Attempts to do so are highly likely to lead to duplication and error, spiralling away from design consistency throughout the app.
It is easy to smush your design classes into a single className. But there is no ease of knowledge in doing so.
Configure your system for ease of knowledge
Ease of use comes with trade-offs. Using someone else's standard means relying on their knowhow. This can be beneficial, but it can also be a trap. Let's take a step back and think about what the basics of a design system consist of:
- typography
- colour
- spacing
- responsiveness (which includes color mode)
In the context of React with Tailwind, these and many other design system elements are set in the Tailwind config, which we can customise.
{/* prettier-ignore */}
const config = { theme: { fontSize: { /* ... */ }, colors: { /* ... */ }, spacing: { /* ... */ }, }, };
Typographic defaults
Have you ever struggled to remember the correct letter-spacing for your small text? What if you could set it once and forget about it?
We can set leading (line-height) and tracking (letter-spacing) as parameters for each font size tuple directly in tailwind.config. This means we don't need to set leading or tracking when we use a font-size class. No need to remember (or fail to look up) what the letter-spacing of small text is.
fontSize: { small: [ "13px", { lineHeight: 1.5, letterSpacing: "0.015em" }, ], base: [ "16px", { lineHeight: 1.5, letterSpacing: 0 }, ], }
Using text-small now sets font-size, line-height and letter-spacing. Enclosing the core typographic tuple together in one class centralises the implementation of these values into the config instead of across a codebase. A huge win for maintainability.
/* 13px/1.5 with 0.015em letter-spacing */ <div className="text-small" />
Color defaults
We can use CSS variables to set responsive colours under :root and html.dark scopes. This means we write and manage one class, such as bg-canvas, instead of two, such as bg-gray-100 dark:bg-gray-800.
@import "@radix-ui/colors/gray.css"; @import "@radix-ui/colors/gray-dark.css"; :root { --color-gray-base: var(--gray-1); --color-gray-bg: var(--gray-3); --color-gray-line: var(--gray-4); --color-gray-border: var(--gray-5); --color-gray-solid: var(--gray-10); --color-gray-fill: var(--gray-12); }
Because I'm using Radix Colors here, I don't need to set the .dark scope as that's already done for me. If you don't like the Radix colors, you can customise them, use another library or write your own.
Then set the CSS variables in the Tailwind config.
colors: { canvas: "var(--color-gray-base)", background: "var(--color-gray-bg)", line: "var(--color-gray-line)", border: "var(--color-gray-border)", solid: "var(--color-gray-solid)", fill: "var(--color-gray-fill-contrast)", }
Using bg-canvas now sets the appropriate color in light or dark mode. Removing this duplication across a codebase centralises color management to our config instead of spreading it across the implementation of classes on components. A huge win for cognitiion and maintainability.
/* sets --gray-1 as #fcfcfc on :root or #111111 on html.dark */ <div className="bg-canvas" />
Semantic naming
I advocate semantic names for colours and font-sizes because semantic naming is a forcing function that ties meaning to use. Doing so removes implementation guess work and reduces error.
I've seen countless projects where inconsistent gray-50, gray-100 or gray-200 are all used for backgrounds. This is easily solved by defining a color called background.
In the same way, it is easier to remember the names for dark and light text colors when they are called fill and solid. It's harder and more error-prone when they're called gray-900 and gray-600 because then you have to remember specifically that it wasn't gray-950 and gray-500, or gray-800 and gray-700.
But naming things—and agreeing on naming—is hard. In the spirit of zero-config, I suggest taking Radix Color's backgrounds, borders, solids & fills paradigm. Or this palette semantics.
And once you've set this in tailwind.config, Typescript will jog your memory at your fingertips with autocomplete.
Avoid namespace clashes
If you're extending a Tailwind theme and not writing your own, don't use a scale key that's already been used. You may inadvertently overwrite a class that you need to use.
You'll note in the previous colour config example that I set the --color-gray-base var to canvas, not base. If I used base then using this color scale as a text colour (text-base) would clash with the default font-size base value, which is also text-base.
This isn't a downfall of customising the Tailwind config, it's a legacy of its theme naming: setting font-size or color classes in Tailwind both use text-*.1
Spacing defaults
We can also use CSS variables to set spacings.
:root { --height-nav: 80px; --height-tab: 54px; --space-inset: 20px; --container-text-px: 660px; --container-hero-px: 1000px; }
spacing: { em: "1em", /* relate icon size to parent font-size */ nav: "var(--height-nav)", inset: "var(--space-inset)", text: "var(--container-text)", hero: "var(--container-hero)", }
One could argue this is over-engineering. Except that when it comes time to compute complex interactive layouts like sticky headers, scroll margins and so on, this upfront configuration work makes it straight forward and error-free, to the pixel.
<div className="top-[calc(theme(spacing.nav)+theme(spacing.tab))]"> <div className="scroll-mt-[calc(theme(spacing.nav)+theme(spacing.tab))]"> /* ... */ </div> </div>
Note again the use of semantic naming makes it easy to remember and use.
Augmenting your Tailwind config
We have now configured typography, colour and spacing tokens in a manner that is easy to understand and maintain in a single, centralised place. And we don't need to wrire as many classes to implement the system. Winning. And there's further steps we can take to reduce this implementation overhead.
Clamp() your classes
What if I told you there's a way to completely avoid writing text-lg lg:text-xl xl:text-2xl p-2 md:p-4 lg:p-8 everywhere?
We can avoid setting responsive font-size classes by using clamp as a a font-size value in tailwind.config. Here's the simple clamp function I use.
fontSize: { title: [ /* clamp(17px, 14.1429px + 0.5714vw, 21px) */ generateClampSize(500, 1200, 17, 21), { lineHeight: 1.5, letterSpacing: "-0.015em" }, ]; }
So instead of writing text-lg lg:text-xl xl:text-2xl we can just write text-title. Once again, by hoisting font-size responsiveness into a clamp value, we avoid the "implement classes" pitfall again, saving mental effort, errors and debugging time.
Keep in mind, this means we've moved from text-lg lg:text-xl xl:text-2xl leading-none tracking-wide to text-title by properly configuring Tailwind. Winning!
/* 17px at 500px, 21px at 1200, fluidly calculated inbetween */ /* …with default line-height and letter-spacing also specified */ <h2 className="text-title"> Heading copy </h2>
We can also do this for spacing. When extending a theme, I prefix these keys with d for "dynamic" to differentiate it from the default spacing scale.
spacing: { /* lower value is 2/3 of upper value */ d4: generateClampSize(500, 1200, 10.5, 16), d8: generateClampSize(500, 1200, 21, 32), d16: generateClampSize(500, 1200, 43, 64), d24: generateClampSize(500, 1200, 64, 96), d64: generateClampSize(500, 1200, 171, 256), }
This allows us to write py-d24 instead of py-16 md:py-20 lg:py-24. This alleviates the weight of holding a range of website versions for each media-query in our minds. Instead it encourages us to picture fluidly responsive layouts where measurements don't matter as much as consistent relationships.
<main className="pt-d24 pb-d64 space-y-w8"> <header className="container max-w-hero space-y-1"> /* ... */ </header> <article className="container space-y-2"> /* ... */ </article> </main>
Summary
Well-crafted UI is your last defense against the coming slopwave of careless AI apps. Here's how customizing Tailwind can save you time and headaches so you can focus on the irrational amount of care it takes to build UI that works in the blink of an eye:
- Use tailwind.config to its full potential. Centralize and group your design tokens and avoid the "implement classes everywhere" trap.
- Use clamp() for fluid typography and spacing.
- Set color variables on :root and .dark for effortless dark mode.
- Name colors and spacing semantically: background beats gray-100 any day.
- Relate icons to text size with size-em.
Yes, there's an upfront time cost. But it pays off in spades: less code, fewer errors, greater design consistency, and a team that actually understands the system.
Next up: We'll explore how to use Class Variance Authority to create a bulletproof styling API with semantic props drawn from Tailwind. Stay tuned.
-
This is also why I dislike using tailwind-merge to remove duplicate Tailwind classes in JSX. More often than not, I find it removing a text-color in favour of a text-fontSize when both are needed. I'm surprised more developers don't raise this issue. ↩
以上是Configuring Tailwind as a Design System的详细内容。更多信息请关注PHP中文网其他相关文章!

这是我们在形式可访问性上进行的小型系列中的第三篇文章。如果您错过了第二篇文章,请查看“以:focus-visible的管理用户焦点”。在

本教程演示了使用智能表单框架创建外观专业的JavaScript表单(注意:不再可用)。 尽管框架本身不可用,但原理和技术仍然与其他形式的建筑商相关。

CSS盒子阴影和轮廓属性获得了主题。让我们查看一些在真实主题中起作用的示例,以及我们必须将这些样式应用于WordPress块和元素的选项。

Svelte Transition API提供了一种使组件输入或离开文档(包括自定义Svelte Transitions)时动画组件的方法。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

Dreamweaver CS6
视觉化网页开发工具

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

PhpStorm Mac 版本
最新(2018.2.1 )专业的PHP集成开发工具

Dreamweaver Mac版
视觉化网页开发工具