Tailwind CSS를 사용하여 구성요소 변형을 작성하는 다른 접근 방식

Patricia Arquette
풀어 주다: 2024-11-21 05:35:11
원래의
603명이 탐색했습니다.

A different approach to writing component variants with Tailwind CSS

문제

전통적으로 Tailwind CSS로 구성 요소 변형을 작성할 때 prop 값을 구성 요소 슬롯에 매핑하는 간단한 클래스 맵을 찾았습니다.

type TTheme = "DEFAULT" | "SECONDARY";
interface IComponentSlot {
  root: string;
  accent: string;
}

const THEME_MAP: Record<TTheme, IComponentSlot> = {
  DEFAULT: {
    root: "bg-red hover:background-pink",
    accent: "text-blue hover:text-green",
  },
  SECONDARY: {
    root: "bg-green hover:background-black",
    accent: "text-pink hover:text-white",
  }
}

<div :class="THEME_MAP['DEFAULT'].root">
  <div :class="THEME_MAP['DEFAULT'].accent">/**/</div>
</div>
로그인 후 복사

이 접근 방식의 문제점은 필수 클래스를 서로 일치시켜 각 변형이 특히 더 복잡한 구성 요소에서 필요한 모든 클래스를 갖도록 보장한다는 것입니다. 텍스트 색상과 같은 스타일을 여러 구성 요소 슬롯에 걸쳐 공유하려는 구성 요소에서는 각 슬롯을 개별적으로 업데이트해야 합니다.

Tailwind의 제한사항

Tailwind는 코드베이스와 일치하는 문자열을 스캔하여 유틸리티 클래스를 생성합니다. 즉, Tailwind는 임의의 값으로 클래스를 생성할 수 있지만 허용 목록을 생성하지 않으면 동적으로 시작할 수 없습니다. 따라서 이것은 작동하지 않습니다:

// .ts
type TTheme = "DEFAULT" | "SECONDARY";

const colors: Record<TTheme, string> = {
  DEFAULT: "red",
  SECONDARY: "blue",
}

// .html
<div :class="`text-[${colors[DEFAULT]}]`">
로그인 후 복사

그러나 Tailwind가 내부적으로 많은 클래스에 사용하는 CSS 변수를 활용하여 원하는 동작을 모방할 수 있습니다. 다음 구문을 사용하여 Tailwind의 클래스를 통해 변수를 설정할 수 있습니다. [--my-variable-key:--my-variable-value]
그렇다면 동적 값을 사용하도록 위의 코드 예제를 어떻게 업데이트할 수 있을까요?

// .ts
type TTheme = "DEFAULT" | "SECONDARY";

const colors: Record<TTheme, string> = {
  DEFAULT: "[--text-color:red]",
  SECONDARY: "[--text-color:blue]",
}

// .html
<div
  :class="[
    colors[DEFAULT],
    'text-[--text-color]'
  ]">
로그인 후 복사

초기 문제 해결

이제 Tailwind의 한계를 이해했으므로 클래스 맵 접근 방식으로 인해 발생한 초기 문제를 해결하는 방법을 조사해야 합니다. 수업 맵을 단순화하는 것부터 시작해 보겠습니다.

type TTheme = "DEFAULT" | "SECONDARY";
interface IComponentSlot {
  root: string;
  accent: string;
}

const THEME_MAP: Record<TTheme, string> = {
  DEFAULT: "[--backgound:red] [--hover__background:pink] [--text:blue] [--hover__text:green]",
  SECONDARY: "[--backgound:green] [--hover__background:black] [--text:pink] [--hover__text:white]",
}

<div>



<p>Unfortunately, this alone doesn't solve our problem, we still can't ensure we've set all of the classes we need to display each variant correctly. So how can we take this a step further? Well, we could begin writing an interface to force us to set specified values:<br>
</p>

<pre class="brush:php;toolbar:false">interface IComponentThemeVariables {
  backgound: string;
  hover__backgound: string;
  text: string;
  hover__text: string;
}

const THEME_MAP: Record<TTheme, IComponentThemeVariables> = {
  DEFAULT: {
    backgound: "[--backgound:red]",
    text: "[--hover__background:pink]",
    hover__background: "[--text:blue]",
    hover__text:"[--hover__text:green]",
  },
  SECONDARY: {
    backgound: "[--backgound:green]",
    text: "[--hover__background:black]",
    hover__background: "[--text:pink]",
    hover__text:"[--hover__text:white]",
  },
}
로그인 후 복사

이렇게 하면 작동하지만 여전히 문제가 있습니다. 문자열 값을 혼동하는 것을 막을 수 있는 것은 없습니다. 예를 들어 실수로 키 배경을 [--text:blue]로 설정할 수 있습니다.

그러므로 값도 입력해야 할 것 같습니다. 전체 클래스를 입력할 수는 없습니다. 그러면 유지 관리가 악몽이 될 것입니다. 따라서 색상을 입력하고 CSS 변수를 생성하는 도우미 메서드를 작성하면 어떻게 될까요?

type TColor = "red" | "pink" | "blue" | "green" | "black" | "white";

interface IComponentThemeVariables {
  backgound: TColor;
  hover__backgound: TColor;
  text: TColor;
  hover__text: TColor;
}

// Example variableMap method at the end of the article

const THEME_MAP: Record<TTheme, string> = {
  DEFAULT: variableMap({
    backgound: "red",
    text: "pink",
    hover__background: "blue",
    hover__text:"green",
  }),
  SECONDARY: variableMap({
    backgound: "green",
    text: "black",
    hover__background: "pink",
    hover__text:"white",
  }),
}
로그인 후 복사

좋아요. 구성 요소의 모든 변형에 대해 항상 올바른 변수를 설정하고 있는지 확인할 수 있어서 좋습니다. 하지만 잠깐만요. Tailwind에서 발견한 초기 문제에 직면했습니다. 클래스를 생성할 수는 없고 Tailwind에서는 해당 클래스를 선택하지 않습니다. 그렇다면 이 문제를 어떻게 해결해야 할까요?

JS의 CSS는 어떻습니까?

여기서는 JS의 CSS가 확실한 답인 것 같았습니다. 올바른 변수를 사용하여 사용자 정의 클래스를 생성하는 클래스를 생성하기만 하면 됩니다. 하지만 문제가 있습니다. Javascript가 클라이언트에서 실행되고 이로 인해 구성 요소가 올바르게 표시되도록 업데이트하기 전에 변수 세트 없이 처음에 로드되는 "플래시"가 발생합니다.

JS 라이브러리의 CSS는 이를 어떻게 처리하나요?

Emotion과 같은 라이브러리는 구성 요소에 대한 인라인 스타일 태그를 삽입하여 이를 처리합니다.

<body>
  <div>
    <style data-emotion-css="21cs4">.css-21cs4 { font-size: 12 }</style>
    <div>



<p>This didn't feel like the right approach to me.</p>

<h3>
  
  
  So how do we solve this?
</h3>

<p>I was working with Vue, this led me down the path of v-bind in CSS, a feature in Vue to bind Javascript as CSS values. I'd only used this feature sparingly in the past and never taken a deep dive into what it's doing. v-bind in CSS simply sets an inline style on the relevant element.</p>

<p>This jogged my memory about a Tweet I saw from the creator of Tailwind CSS, Adam Wathan a couple of months previously:</p>

<p>So how does this help us? Well, while we can't dynamically generate Tailwind classes, we can dynamically generate inline styles and consume those inline styles from our Tailwind classes. So what would that look like?<br>
</p>

<pre class="brush:php;toolbar:false">type TColor = "red" | "pink" | "blue" | "green" | "black" | "white";

interface IComponentThemeVariables {
  backgound: TColor;
  hover__backgound: TColor;
  text: TColor;
  hover__text: TColor;
}

// Example variableMap method at the end of the article

const THEME_MAP: Record<TTheme, string> = {
  DEFAULT: variableMap({
    backgound: "red",
    text: "pink",
    hover__background: "blue",
    hover__text: "green",
  }),
  SECONDARY: variableMap({
    backgound: "green",
    text: "black",
    hover__background: "pink",
    hover__text: "white",
  }),
}

<div
 >



<h2>
  
  
  Conclusion
</h2>

<p>By combining the powers of Typescript, CSS variables, and inline styles we were able to ensure that while using Tailwind CSS, each variant of our component would have every option set and with the correct type.</p>

<p>This is an experimental approach on which I'm sure there will be some strong opinions. Am I convinced this is the best approach? At this stage, I'm not sure, but I think it has legs.</p>

<p>If you've found this article interesting or useful, please follow me on Bluesky (I'm most active here), Medium, Dev and/ or Twitter.</p>

<h3>
  
  
  Example: variableMap
</h3>



<pre class="brush:php;toolbar:false">// variableMap example
export const variableMap = <T extends Record<string, string>>(
  map: T
): string => {
  const styles: string[] = [];
  Object.entries(map).forEach(([key, value]) => {
    const wrappedValue = value.startsWith("--") ? `var(${value})` : value;
    const variableClass = `--${key}: ${wrappedValue};`;
    styles.push(variableClass);
  });
  return styles.join(" ");
};
로그인 후 복사

위 내용은 Tailwind CSS를 사용하여 구성요소 변형을 작성하는 다른 접근 방식의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿