」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 將 Tailwind 配置為設計系統

將 Tailwind 配置為設計系統

發佈於2024-11-06
瀏覽:679

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

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

使用我的 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]刪除
最新教學 更多>
  • 如何使用“ JSON”軟件包解析JSON陣列?
    如何使用“ JSON”軟件包解析JSON陣列?
    parsing JSON與JSON軟件包 QUALDALS:考慮以下go代碼:字符串 } func main(){ datajson:=`[“ 1”,“ 2”,“ 3”]`` arr:= jsontype {} 摘要:= = json.unmarshal([] byte(...
    程式設計 發佈於2025-04-05
  • 如何有效地選擇熊貓數據框中的列?
    如何有效地選擇熊貓數據框中的列?
    在處理數據操作任務時,在Pandas DataFrames 中選擇列時,選擇特定列的必要條件是必要的。在Pandas中,選擇列的各種選項。 選項1:使用列名 如果已知列索引,請使用ILOC函數選擇它們。請注意,python索引基於零。 df1 = df.iloc [:,0:2]#使用索引0和1 ...
    程式設計 發佈於2025-04-05
  • 如何使用Python理解有效地創建字典?
    如何使用Python理解有效地創建字典?
    在python中,詞典綜合提供了一種生成新詞典的簡潔方法。儘管它們與列表綜合相似,但存在一些顯著差異。 與問題所暗示的不同,您無法為鑰匙創建字典理解。您必須明確指定鍵和值。 For example:d = {n: n**2 for n in range(5)}This creates a dict...
    程式設計 發佈於2025-04-05
  • \“(1)vs.(;;):編譯器優化是否消除了性能差異?\”
    \“(1)vs.(;;):編譯器優化是否消除了性能差異?\”
    答案: 在大多數現代編譯器中,while(1)和(1)和(;;)之間沒有性能差異。編譯器: perl: 1 輸入 - > 2 2 NextState(Main 2 -E:1)V-> 3 9 Leaveloop VK/2-> A 3 toterloop(next-> 8 last-> 9 ...
    程式設計 發佈於2025-04-05
  • 如何簡化PHP中的JSON解析以獲取多維陣列?
    如何簡化PHP中的JSON解析以獲取多維陣列?
    php 試圖在PHP中解析JSON數據的JSON可能具有挑戰性,尤其是在處理多維數組時。 To simplify the process, it's recommended to parse the JSON as an array rather than an object.To do...
    程式設計 發佈於2025-04-05
  • 如何使用組在MySQL中旋轉數據?
    如何使用組在MySQL中旋轉數據?
    在關係數據庫中使用mySQL組使用mySQL組進行查詢結果,在關係數據庫中使用MySQL組,轉移數據的數據是指重新排列的行和列的重排以增強數據可視化。在這裡,我們面對一個共同的挑戰:使用組的組將數據從基於行的基於列的轉換為基於列。 Let's consider the following ...
    程式設計 發佈於2025-04-05
  • 對象擬合:IE和Edge中的封面失敗,如何修復?
    對象擬合:IE和Edge中的封面失敗,如何修復?
    To resolve this issue, we employ a clever CSS solution that solves the problem:position: absolute;top: 50%;left: 50%;transform: translate(-50%, -50%)...
    程式設計 發佈於2025-04-05
  • 如何從PHP中的數組中提取隨機元素?
    如何從PHP中的數組中提取隨機元素?
    從陣列中的隨機選擇,可以輕鬆從數組中獲取隨機項目。考慮以下數組:; 從此數組中檢索一個隨機項目,利用array_rand( array_rand()函數從數組返回一個隨機鍵。通過將$項目數組索引使用此鍵,我們可以從數組中訪問一個隨機元素。這種方法為選擇隨機項目提供了一種直接且可靠的方法。
    程式設計 發佈於2025-04-05
  • 如何將PANDAS DataFrame列轉換為DateTime格式並按日期過濾?
    如何將PANDAS DataFrame列轉換為DateTime格式並按日期過濾?
    將pandas dataframe列轉換為dateTime格式示例:使用column(mycol)包含以下格式的以下dataframe,以自定義格式:})指定的格式參數匹配給定的字符串格式。轉換後,MyCol列現在將包含DateTime對象。 date date filtering > = ...
    程式設計 發佈於2025-04-05
  • 大批
    大批
    [2 數組是對象,因此它們在JS中也具有方法。 切片(開始):在新數組中提取部分數組,而無需突變原始數組。 令ARR = ['a','b','c','d','e']; // USECASE:提取直到索引作...
    程式設計 發佈於2025-04-05
  • 如何使用Java.net.urlConnection和Multipart/form-data編碼使用其他參數上傳文件?
    如何使用Java.net.urlConnection和Multipart/form-data編碼使用其他參數上傳文件?
    使用http request 上傳文件上傳到http server,同時也提交其他參數,java.net.net.urlconnection and Multipart/form-data Encoding是普遍的。 Here's a breakdown of the process:Mu...
    程式設計 發佈於2025-04-05
  • 找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    找到最大計數時,如何解決mySQL中的“組函數\”錯誤的“無效使用”?
    如何在mySQL中使用mySql 檢索最大計數,您可能會遇到一個問題,您可能會在嘗試使用以下命令:理解錯誤正確找到由名稱列分組的值的最大計數,請使用以下修改後的查詢: 計數(*)為c 來自EMP1 按名稱組 c desc訂購 限制1 查詢說明 select語句提取名稱列和每個名稱...
    程式設計 發佈於2025-04-05
  • 如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求和假用戶代理繞過網站塊?
    如何使用Python的請求模擬瀏覽器行為,以及偽造的用戶代理提供了一個用戶 - 代理標頭一個有效方法是提供有效的用戶式header,以提供有效的用戶 - 設置,該標題可以通過browser和Acterner Systems the equestersystermery和操作系統。通過模仿像Chro...
    程式設計 發佈於2025-04-05
  • 如何使用PHP從XML文件中有效地檢索屬性值?
    如何使用PHP從XML文件中有效地檢索屬性值?
    從php $xml = simplexml_load_file($file); foreach ($xml->Var[0]->attributes() as $attributeName => $attributeValue) { echo $attributeName,...
    程式設計 發佈於2025-04-05
  • 如何使用Depimal.parse()中的指數表示法中的數字?
    如何使用Depimal.parse()中的指數表示法中的數字?
    在嘗試使用Decimal.parse(“ 1.2345e-02”中的指數符號表示法表示的字符串時,您可能會遇到錯誤。這是因為默認解析方法無法識別指數符號。 成功解析這樣的字符串,您需要明確指定它代表浮點數。您可以使用numbersTyles.Float樣式進行此操作,如下所示:[&& && && ...
    程式設計 發佈於2025-04-05

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3