设计系统:使用 TailwindCSS 覆盖样式

Posted

技术标签:

【中文标题】设计系统:使用 TailwindCSS 覆盖样式【英文标题】:Design system: styles override using TailwindCSS 【发布时间】:2021-06-08 21:09:05 【问题描述】:

我正在尝试使用 ReactJS 和 TailwindCSS 创建一个设计系统。

我创建了一个默认的Button 组件,其基本样式如下:

import React from "react";
import classNames from "classnames";

const Button = React.forwardRef(
  ( children, className = "", onClick , ref) => 
    const buttonClasses = classNames(
      className,
      "w-24 py-3 bg-red-500 text-white font-bold rounded-full"
    );

    const commonProps = 
      className: buttonClasses,
      onClick,
      ref
    ;

    return React.createElement(
      "button",
       ...commonProps, type: "button" ,
      children
    );
  
);

export default Button;

然后我在我的页面中使用Button,例如:

import Button from "../src/components/Button";

export default function IndexPage() 
  return (
    <div>
      <Button onClick=() => console.log("TODO")>Vanilla Button</Button>
      <div className="h-2" />
      <Button
        className="w-6 py-2 bg-blue-500 rounded-sm"
        onClick=() => console.log("TODO")
      >
        Custom Button
      </Button>
    </div>
  );

这是显示的内容:

有些属性像 background-color 一样被覆盖,但有些不是(其余的)。

原因是 TailwindCSS 提供的类是按照 bg-blue-500 放在 bg-red-500 之后的顺序编写的,因此会覆盖它。另一方面,自定义按钮中提供的其他类在基本按钮上的类之前编写,因此不会覆盖样式。

TailwindCSS 会发生这种行为,但只要类顺序可以产生这种情况,其他任何样式方法都可能会发生这种情况。

您是否有任何解决方法/解决方案来启用这种自定义?

如果需要,这里是完整的CodeSanbox。

【问题讨论】:

【参考方案1】:

一种方法是在组件层中使用 Tailwind 的 @apply 从组件中获取 extract component classes。

/* main.css */

@layer components 
    .base-button 
        @apply w-24 py-3 bg-red-500 text-white font-bold rounded-full;
    

// Button.js

const Button = React.forwardRef(( children, className = "", onClick , ref) => 
    const buttonClasses = classNames("base-button", className);

    // ...
);

这会将样式提取到新的base-button 类中,这意味着它们可以很容易地被您传递给Button 组件的实用程序类覆盖。

【讨论】:

谢谢我今天早上在文档中发现了@apply 的用法,但直到现在才有时间尝试。您的回答是确认这应该是处理此问题的正确方法。立即测试。 确认它按预期工作并且似乎是解决此问题的正确方法。 在 Next 应用程序中使用 Styled Components 的任何方式?尝试使用父样式组件中的指令,但它没有做任何事情【参考方案2】:

另一种使用 Tailwind 创建可重用 React 组件的方法如下。

阅读此要点

https://gist.github.com/RobinMalfait/490a0560a7cfde985d435ad93f8094c5

举一个很好的例子。

避免使用 className 作为道具。否则,你很难知道你的组件处于什么状态。如果你想添加一个额外的类,你可以很容易地扩展。

您需要一个助手来有条件地组合类名字符串。本要点的作者 Robert 也与我们分享了辅助函数:

export function classNames(...classes: (false | null | undefined | string)[]) 
  return classes.filter(Boolean).join(" ");

【讨论】:

npm 上的 classNames 包已经做到了这一点,并在原帖中使用。【参考方案3】:

要解决这个问题,我建议做 Bootstrap 所做的事情。为您的默认按钮使用默认类,例如:

.button 
  width: 2rem;
  background-color: red;
  border-radius: 0.25rem;

然后,在自定义按钮时,您应该应用位于 CSS 文件中按钮类之后的类,或者位于在默认 CSS 文件之后调用的不同 CSS 文件中的类,或者使用 !important 声明。

旧答案 使用您的浏览器开发工具来观察您的浏览器如何在元素上加载 CSS 样式。例如,在 Chrome 中,右键单击自定义按钮并选择“检查”。将打开一个 DevTools 窗口,该元素将在 DOM 中突出显示。

在右侧,您应该有一个样式窗格。在那里,您将看到应用于元素的所有 CSS 样式的列表。带有删除线的样式被其他 CSS 类或内联样式调用的样式所覆盖。

在您的情况下,自定义按钮同时具有“CommonProps”类和您在 IndexPage 中添加的类。例如w-6 类和w-24 类。

w-24 是覆盖类 w-6 因为 CSS 优先级。 Read more about CSS precedence here. 在接受的答案中查看规则#3。我想这就是发生在你身上的事情。

要解决这个问题,您可能需要从 commonProps 中删除一些类。或者在某些类上使用!important 声明。这是您需要考虑的设计系统的一部分。看看 Bootstrap 等其他系统是如何做到的。

【讨论】:

感谢您的快速回答。事实上,我知道问题与 CSS 优先级有关,这也是我在问题本身中所解释的。无论如何,谢谢你的努力。 @Florian_L 抱歉,我没有阅读您的整个问题,并认为我知道这一切。更新了我的答案。 是的,我知道如何使用常规 css 方法解决此排序问题。但是,当使用 tailwindcss.com 作为实用程序优先的框架时,您不是编写 CSS 的人,而是更多地使用定义的类来编写样式。我想知道的是,是否有任何选项可以让我使用 TailwindCSS 以 100% 完成使用。 @Florian_L 我认为您不能仅使用 Tailwind 就拥有基本样式。查看有关该主题的文档:tailwindcss.com/docs/adding-base-styles 他们建议为此使用他们的 Preflight 样式表。 是的,我同意。要走的路是使用tailwindcss.com/docs/extracting-components

以上是关于设计系统:使用 TailwindCSS 覆盖样式的主要内容,如果未能解决你的问题,请参考以下文章

如何使表格占据所有水平空间 TailwindCSS (React)

NuxtJS + BootstrapVue + TailwindCSS:我可以有效地使用 Bootstrap Vue 组件,但使用 Tailwind CSS 样式?

无法扩展:TailwindCSS 变体:

tailwindcss使用总结

覆盖 <div> 内联宽度样式以使元素拉伸到内​​容?

使用@nuxtjs/tailwindcss 清除了 SCSS 样式