对于设计系统来说,一致性和理解性就是一切。一个好的设计系统通过实现它的代码的配置来确保实现的一致性。它需要是:
使用我的 React 和 Tailwind 的默认堆栈,我将向您展示如何设置自己的版式、颜色和间距默认值,而不仅仅是区分应用程序外观和感觉的起点。更重要的是,它大大减少了我们必须编写和维护的代码,从而减少了以系统、一致和无错误的方式实现样式的精神负担。
我将从我经常看到的一个主要批评开始,然后分解我用来解决它的一系列配置步骤。
Tailwind 使开发人员可以轻松编写样式,这对于快速原型设计非常有用。但这种易用性并不能保证良好的设计或可扩展、可维护的设计系统。
像 Tailwind 这样的默认和零配置工具是基础设施速度层,可以为构建创造更多时间。但是,如果您要扩展一个使用设计系统来区分自己的应用程序,则不能仅仅依赖“像午餐一样免费”的开箱即用配置。
如果您使用默认的 Tailwind 配置运行并将样式管理推送到组件上的类应用程序,结果通常是一堆难以推理的类分布在组件中,伪装成设计系统。
上面是一个很好的例子。它几乎难以辨认,需要大量时间才能理解,更不用说操纵了。尝试这样做很可能会导致重复和错误,从而逐渐偏离整个应用程序的设计一致性。
很容易将您的设计类合并到单个类名中。但这样做并不容易。
易用性需要权衡。使用别人的标准意味着依赖他们的专业知识。这可能是有益的,但也可能是一个陷阱。让我们退后一步,思考一下设计系统的基础知识包括哪些内容:
在 React with Tailwind 的上下文中,这些和许多其他设计系统元素都在 Tailwind 配置中设置,我们可以对其进行自定义。
{/* 更漂亮-忽略 */}
const config = { theme: { fontSize: { /* ... */ }, colors: { /* ... */ }, spacing: { /* ... */ }, }, };
您是否曾经努力记住小文本的正确字母间距?如果您可以设置一次然后忘记它怎么办?
我们可以直接在 tailwind.config 中将前导(行高)和跟踪(字母间距)设置为每个字体大小元组的参数。这意味着当我们使用字体大小类时,我们不需要设置行距或跟踪。无需记住(或无法查找)小文本的字母间距是多少。
fontSize: { small: [ "13px", { lineHeight: 1.5, letterSpacing: "0.015em" }, ], base: [ "16px", { lineHeight: 1.5, letterSpacing: 0 }, ], }
现在使用 text-small 设置字体大小、行高和字母间距。将核心排版元组封装在一个类中,将这些值的实现集中到配置中,而不是跨代码库。可维护性的巨大胜利。
/* 13px/1.5 with 0.015em letter-spacing */
我们可以使用 CSS 变量在 :root 和 html.dark 范围下设置响应颜色。这意味着我们编写和管理一个类,例如 bg-canvas,而不是两个类,例如 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); }
因为我在这里使用 Radix Colors,所以我不需要设置 .dark 范围,因为这已经为我完成了。如果您不喜欢基数颜色,您可以自定义它们、使用其他库或编写自己的库。
然后在Tailwind配置中设置CSS变量。
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)", }
现在使用 bg-canvas 在浅色或深色模式下设置适当的颜色。在代码库中删除这种重复可以将颜色管理集中到我们的配置中,而不是将其分散到组件上的类的实现中。认知和可维护性的巨大胜利。
/* sets --gray-1 as #fcfcfc on :root or #111111 on html.dark */
我提倡颜色和字体大小的语义名称,因为语义命名是一种将含义与使用联系起来的强制功能。这样做可以消除实现猜测工作并减少错误。
我见过无数的项目,其中不一致的gray-50、gray-100或gray-200都用于背景。通过定义一种名为背景的颜色可以轻松解决这个问题。
同样,当深色和浅色文本颜色称为填充和纯色时,更容易记住它们的名称。当它们被称为gray-900和gray-600时,它会更难,也更容易出错,因为你必须特别记住它不是gray-950和gray-500,或者gray-800和gray-700。
但是命名事物并就命名达成一致是很困难的。本着零配置的精神,我建议采用 Radix Color 的背景、边框、实体和填充范例。或者这个调色板语义。
一旦你在 tailwind.config 中设置了此项,Typescript 就会通过自动完成功能唤起你的记忆。
如果您要扩展 Tailwind 主题而不是编写自己的主题,请不要使用已经使用过的音阶键。您可能会无意中覆盖您需要使用的类。
您会注意到在前面的颜色配置示例中,我将 --color-gray-base var 设置为 canvas,而不是 base。如果我使用基础,那么使用此色阶作为文本颜色(文本基础)将与默认字体大小基础值发生冲突,该值也是文本基础。
这并不是自定义 Tailwind 配置的缺点,而是其主题命名的遗留问题:在 Tailwind 中设置字体大小或颜色类都使用 text-*.1
我们还可以使用CSS变量来设置间距。
: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)", }
有人可能会说这是过度设计。除了计算复杂的交互式布局(如粘性标题、滚动边距等)之外,这种预先配置工作使其在像素方面变得直接且无错误。
/* ... */
再次注意语义命名的使用使其易于记忆和使用。
我们现在已经在一个集中的地方以易于理解和维护的方式配置了版式、颜色和间距标记。而且我们不需要编写那么多的类来实现系统。获胜。我们可以采取进一步的措施来减少这种实现开销。
如果我告诉你有一种方法可以完全避免到处写 text-lg lg:text-xl xl:text-2xl p-2 md:p-4 lg:p-8 呢?
我们可以通过在tailwind.config中使用clamp作为字体大小值来避免设置响应式字体大小类。这是我使用的简单钳位函数。
fontSize: { title: [ /* clamp(17px, 14.1429px 0.5714vw, 21px) */ generateClampSize(500, 1200, 17, 21), { lineHeight: 1.5, letterSpacing: "-0.015em" }, ]; }
因此,我们可以只写 text-title,而不是写 text-lg lg:text-xl xl:text-2xl。再一次,通过将字体大小响应提升到钳位值,我们再次避免了“实现类”陷阱,节省了脑力劳动、错误和调试时间。
请记住,这意味着通过正确配置 Tailwind,我们已从 text-lg lg:text-xl xl:text-2xlleading-none Tracking-wide 转移到 text-title。赢了!
/* 17px at 500px, 21px at 1200, fluidly calculated inbetween */ /* …with default line-height and letter-spacing also specified */Heading copy
我们也可以对间距执行此操作。扩展主题时,我在这些键前加上 d 作为“动态”前缀,以将其与默认间距比例区分开来。
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), }
这允许我们编写 py-d24 而不是 py-16 md:py-20 lg:py-24。这减轻了我们在脑海中为每个媒体查询保留一系列网站版本的负担。相反,它鼓励我们想象流畅响应的布局,其中测量并不像一致的关系那么重要。
/* ... */ /* ... */
精心设计的 UI 是您抵御即将到来的粗心人工智能应用程序浪潮的最后一道防线。以下是自定义 Tailwind 如何节省您的时间和麻烦,以便您可以专注于构建眨眼间即可运行的 UI 所需的不合理的关注:
是的,有前期时间成本。但它确实得到了回报:更少的代码、更少的错误、更高的设计一致性以及真正理解系统的团队。
接下来:我们将探索如何使用 Class Variance Authority 来创建一个防弹样式 API,其中包含从 Tailwind 中提取的语义属性。敬请关注。
这也是我不喜欢使用 tailwind-merge 删除 JSX 中重复的 Tailwind 类的原因。通常,我发现当两者都需要时,它会删除文本颜色以支持文本字体大小。我很惊讶更多的开发人员没有提出这个问题。 ↩
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3