Tailwind を設計システムとして構成する

Barbara Streisand
リリース: 2024-09-19 14:15:03
オリジナル
542 人が閲覧しました

デザインシステムでは、一貫性と理解がすべてです。優れた設計システムは、それを実装するコードの構成を通じて実装の一貫性を保証します。次のようにする必要があります:

  • 優れたデザインに必要なニュアンスを無視することなく理解しやすい;
  • 一貫性を損なうことなく、スケーラブルで保守可能です。

Tailwind で React のデフォルトのスタックを使用して、タイポグラフィ、色、間隔の独自のデフォルトを設定することが、アプリの外観と操作性を差別化するための単なる出発点ではないことを説明します。さらに重要なことは、記述して保守しなければならないコードが大幅に削減され、体系的で一貫性があり、エラーのない方法でスタイルを実装する際の精神的負担が軽減されることです。

私が常に目にする主な批判から始めて、それを解決するために私が使用する一連の構成手順を詳しく説明します。

使いやすさは知識の容易さとは一致しません

Tailwind を使用すると、開発者はスタイルを簡単に作成できるため、ラピッド プロトタイピングに最適です。しかし、その容易さは、優れた設計やスケーラブルで保守可能な設計システムを保証するものではありません。

Tailwind のようなデフォルトおよびゼロ構成ツールは、構築により多くの時間を生み出すインフラストラクチャペースレイヤーです。しかし、差別化を図るためにデザイン システムを使用するアプリを拡張する場合、「ランチのように無料」のすぐに使える構成だけに頼ることはできません。

デフォルトの Tailwind 構成で実行し、コンポーネント上のクラスのアプリケーションにスタイル管理をプッシュすると、その結果、多くの場合、デザイン システムを装った、推論が困難なクラスがコンポーネント全体に分散した混乱が生じます。

Configuring Tailwind as a Design System

上記はその代表的な例です。ほとんど判読できず、操作することはおろか、理解するのにもかなりの時間がかかります。そうしようとすると、重複やエラーが発生する可能性が高く、アプリ全体のデザインの一貫性が損なわれます。

設計クラスを単一の className に押し込むのは簡単です。しかし、そうすることで知識を得るのは容易ではありません。

理解しやすいようにシステムを構成する

使いやすさにはトレードオフが伴います。他人の標準を使用するということは、その人のノウハウに依存することを意味します。これは有益なこともありますが、罠になることもあります。一歩下がって、デザイン システムの基本が何で構成されているかを考えてみましょう。

  • タイポグラフィ
  • 間隔
  • 応答性 (カラーモードを含む)

Tailwind を使用した React のコンテキストでは、これらおよび他の多くのデザイン システム要素が 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 を使用すると、font-size、line-height、letter-spacing が設定されるようになりました。コアのタイポグラフィック タプルを 1 つのクラスにまとめることで、これらの値の実装がコードベース全体ではなく構成に集中化されます。保守性の面で大きなメリットがあります。

/* 13px/1.5 with 0.015em letter-spacing */
<div className="text-small" />
ログイン後にコピー

色のデフォルト

CSS 変数を使用して、:root および html.dark スコープでレスポンシブ カラーを設定できます。これは、bg-gray-100 dark:bg-gray-800 などの 2 つのクラスではなく、bg-canvas などの 1 つのクラスを作成して管理することを意味します。

@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);
}
ログイン後にコピー

ここでは基数カラーを使用しているため、.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 */
<div className="bg-canvas" />
ログイン後にコピー

セマンティックな命名

私は、色とフォントサイズにセマンティックな名前を付けることを提唱しています。なぜなら、セマンティックな名前付けは、意味と使用を結びつける強制的な機能だからです。そうすることで実装の推測作業がなくなり、エラーが減ります。

一貫性のないグレー 50、グレー 100、またはグレー 200 がすべて背景に使用されているプロジェクトを数え切れないほど見てきました。これは、背景と呼ばれる色を定義することで簡単に解決できます。

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.


  1. 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. ↩

以上がTailwind を設計システムとして構成するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!