”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 将 Tailwind 配置为设计系统

将 Tailwind 配置为设计系统

发布于2024-11-06
浏览:318

对于设计系统来说,一致性和理解性就是一切。一个好的设计系统通过实现它的代码的配置来确保实现的一致性。它需要是:

  • 易于理解,无需放弃良好设计所需的细微差别;
  • 可扩展和可维护,且不影响一致性。

使用我的 React 和 Tailwind 的默认堆栈,我将向您展示如何设置自己的版式、颜色和间距默认值,而不仅仅是区分应用程序外观和感觉的起点。更重要的是,它大大减少了我们必须编写和维护的代码,从而减少了以系统、一致和无错误的方式实现样式的精神负担。

我将从我经常看到的一个主要批评开始,然后分解我用来解决它的一系列配置步骤。

易于使用并不等于易于掌握知识

Tailwind 使开发人员可以轻松编写样式,这对于快速原型设计非常有用。但这种易用性并不能保证良好的设计或可扩展、可维护的设计系统。

像 Tailwind 这样的默认和零配置工具是基础设施速度层,可以为构建创造更多时间。但是,如果您要扩展一个使用设计系统来区分自己的应用程序,则不能仅仅依赖“像午餐一样免费”的开箱即用配置。

如果您使用默认的 Tailwind 配置运行并将样式管理推送到组件上的类应用程序,结果通常是一堆难以推理的类分布在组件中,伪装成设计系统。

Configuring Tailwind as a Design System

上面是一个很好的例子。它几乎难以辨认,需要大量时间才能理解,更不用说操纵了。尝试这样做很可能会导致重复和错误,从而逐渐偏离整个应用程序的设计一致性。

很容易将您的设计类合并到单个类名中。但这样做并不容易。

配置您的系统以方便了解

易用性需要权衡。使用别人的标准意味着依赖他们的专业知识。这可能是有益的,但也可能是一个陷阱。让我们退后一步,思考一下设计系统的基础知识包括哪些内容:

  • 排版
  • 颜色
  • 间距
  • 响应能力(包括颜色模式)

在 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)",
}

有人可能会说这是过度设计。除了计算复杂的交互式布局(如粘性标题、滚动边距等)之外,这种预先配置工作使其在像素方面变得直接且无错误。

/* ... */

再次注意语义命名的使用使其易于记忆和使用。

增强您的 Tailwind 配置

我们现在已经在一个集中的地方以易于理解和维护的方式配置了版式、颜色和间距标记。而且我们不需要编写那么多的类来实现系统。获胜。我们可以采取进一步的措施来减少这种实现开销。

Clamp() 你的类

如果我告诉你有一种方法可以完全避免到处写 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 所需的不合理的关注:

  • 充分利用 tailwind.config 的潜力。集中和分组您的设计令牌,避免“到处实现类”陷阱。
  • 使用clamp()进行流畅的排版和间距。
  • 在 :root 和 .dark 上设置颜色变量以轻松实现深色模式。
  • 从语义上命名颜色和间距:背景每天都会比灰色 100。
  • 使用 size-em 将图标与文本大小相关联。

是的,有前期时间成本。但它确实得到了回报:更少的代码、更少的错误、更高的设计一致性以及真正理解系统的团队。

接下来:我们将探索如何使用 Class Variance Authority 来创建一个防弹样式 API,其中包含从 Tailwind 中提取的语义属性。敬请关注。


  1. 这也是我不喜欢使用 tailwind-merge 删除 JSX 中重复的 Tailwind 类的原因。通常,我发现当两者都需要时,它会删除文本颜色以支持文本字体大小。我很惊讶更多的开发人员没有提出这个问题。 ↩

版本声明 本文转载于:https://dev.to/callumflack/configuring-tailwind-as-a-design-system-2f5h?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 为什么Go的main函数有死循环?
    为什么Go的main函数有死循环?
    Go 运行时:主函数中无限循环之谜Go 运行时的核心位于 src/runtime/proc.go,其中有一个令人费解的功能:主函数末尾有一个无限的 for 循环。人们可能想知道为什么运行时中存在这样一个看似毫无意义的构造。目的:检测致命错误深入研究代码,很明显循环服务于错误处理的关键目的。当发生致命...
    编程 发布于2024-11-07
  • iostream 与 iostream.h:在现代 C++ 中应该使用哪个?
    iostream 与 iostream.h:在现代 C++ 中应该使用哪个?
    iostream 和 iostream.h 之间的区别在 C 中,程序员可能会遇到两个具有类似目的的术语:iostream 和 iostream.h 。本指南旨在阐明两者之间的根本区别。iostream.h:已弃用的旧版本iostream.h 是 C 库中的一个头文件,它提供一组输入/输出函数。对于...
    编程 发布于2024-11-07
  • VLONE Clothing:重新定义都市时尚的街头服饰品牌
    VLONE Clothing:重新定义都市时尚的街头服饰品牌
    VLONE 是少数几个在快速变化的市场中取得超越街头服饰行业所能想象的成就的品牌之一。 VLONE 由 A$AP Mob 集体的电影制片人之一 A$AP Bari 创立,现已发展成为一个小众项目,有时甚至成为都市时尚界的国际知名品牌。 VLONE 凭借大胆的图案、深厚的文化联系和限量版发售,在时尚界...
    编程 发布于2024-11-07
  • 如何使用PDO查询单行中的单列?
    如何使用PDO查询单行中的单列?
    使用 PDO 查询单行中的单列处理针对单行中特定列的 SQL 查询时,通常需要检索直接取值,无需循环。要使用 PDO 完成此操作,fetchColumn() 方法就派上用场了。fetchColumn() 的语法为:$col_value = $stmt->fetchColumn([column_...
    编程 发布于2024-11-07
  • 我是如何构建 PeerSplit:一款免费的点对点费用分摊应用程序 — 从构思到发布仅需数周时间
    我是如何构建 PeerSplit:一款免费的点对点费用分摊应用程序 — 从构思到发布仅需数周时间
    我构建了 PeerSplit——一个免费的、点对点的 Splitwise 替代品——从想法到发布仅用了两周时间! PeerSplit 是一款本地优先的应用程序,用于分配团体费用。它可以离线工作,100% 免费且私密,不需要注册或任何个人数据。 以下是我如何构建它以及我在此过程中学到的一切。 ...
    编程 发布于2024-11-07
  • 如何在 PHP 中解析子域名的根域名?
    如何在 PHP 中解析子域名的根域名?
    在 PHP 中从子域解析域名在 PHP 中,从子域中提取根域名是一项常见任务。当您需要识别与子域关联的主网站时,这非常有用。为了实现这一目标,让我们探索一个解决方案。提供的代码片段利用 parse_url 函数将 URL 分解为其组件,包括域名。随后,它使用正则表达式来隔离根域,而忽略子域。以下示例...
    编程 发布于2024-11-07
  • 使用 Socket.io 构建实时应用程序
    使用 Socket.io 构建实时应用程序
    介绍 Socket.io 是一个 JavaScript 库,允许 Web 客户端和服务器之间进行实时通信。它支持创建交互式动态应用程序,例如聊天室、多人游戏和直播。凭借其易于使用的 API 和跨平台兼容性,Socket.io 已成为构建实时应用程序的流行选择。在本文中,我们将探讨 ...
    编程 发布于2024-11-07
  • 重写 `hashCode()` 和 `equals()` 如何影响 HashMap 性能?
    重写 `hashCode()` 和 `equals()` 如何影响 HashMap 性能?
    了解 equals 和 hashCode 在 HashMap 中的工作原理Java 中的 HashMap 使用 hashCode() 和 equals() 方法的组合来有效地存储和检索键值对。当添加新的键值对时,首先计算键的hashCode()方法,以确定该条目将被放置在哪个哈希桶中。然后使用 eq...
    编程 发布于2024-11-07
  • 使用 Google Apps 脚本和 Leaflet.js 构建交互式 XY 图像图
    使用 Google Apps 脚本和 Leaflet.js 构建交互式 XY 图像图
    Google Maps has a ton of features for plotting points on a map, but what if you want to plot points on an image? These XY Image Plot maps are commonly...
    编程 发布于2024-11-07
  • 理解 React 中的状态变量:原因和方法
    理解 React 中的状态变量:原因和方法
    在深入研究状态变量之前,让我们先来分析一下 React 组件的工作原理! 什么是 React 组件? 在 React 中,组件是一段可重用的代码,代表用户界面 (UI) 的一部分。它可以像 HTML 按钮一样简单,也可以像完整的页面一样复杂。 React 中的状态...
    编程 发布于2024-11-07
  • Miva 的日子:第 4 天
    Miva 的日子:第 4 天
    这是 100 天 Miva 编码挑战的第四天。我跳过了第三天的报告,因为我被困在我的网页设计项目中,需要改变节奏。这就是为什么我今天决定深入研究 JavaScript。 JavaScript JavaScript 就像系统和网站的行为组件。它为网站增加了交互性和响应能力,使其成为网页设计和开发的关...
    编程 发布于2024-11-07
  • TailGrids React:+ Tailwind CSS React UI 组件
    TailGrids React:+ Tailwind CSS React UI 组件
    我们很高兴推出 TailGrids React,这是您的新首选工具包,可用于轻松构建令人惊叹的响应式 Web 界面。 TailGrids React 提供了超过 600 免费和高级 React UI 组件、块、部分和模板的大量集合 - 所有这些都是用 Tailwind CSS 精心制作的。 无论您...
    编程 发布于2024-11-07
  • 如何用列表值反转字典?
    如何用列表值反转字典?
    使用列表值反转字典:解决方案在本文中,我们探讨了使用列表值反转字典的挑战。给定一个索引字典,其中键是文件名,值是这些文件中出现的单词列表,我们的目标是创建一个倒排字典,其中单词是键,值是文件名列表。提供的反转函数 invert_dict,不适用于以列表值作为键的字典,因为它会失败并显示“TypeEr...
    编程 发布于2024-11-07
  • 现代 Web 开发框架:比较流行的框架及其用例
    现代 Web 开发框架:比较流行的框架及其用例
    在快速发展的 Web 开发领域,选择正确的框架可以显着影响项目的成功。本文深入研究了一些最流行的 Web 开发框架,比较了它们的优势和理想用例,以帮助开发人员做出明智的决策。 反应 概述 React 由 Facebook 开发和维护,是一个用于构建用户界面的 Java...
    编程 发布于2024-11-07
  • 如何在 Go 1.18 中安全地使用泛型类型解组 JSON?
    如何在 Go 1.18 中安全地使用泛型类型解组 JSON?
    Unmarshal 中的泛型使用 (Go 1.18)在 Go 1.18 中使用泛型时,例如创建一个容器来保存各种报告类型,可能会出现类型限制。考虑以下设置:由结构表示的多种报告类型具有通用类型参数的 ReportContainer 包装器可报告,约束为实现可报告接口鉴别器ReportType 在解组...
    编程 发布于2024-11-07

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3