组合使用Tailwind CSS框架

Tailwind CSS框架是一个功能类优先的CSS框架,可以支持开发人员通过组合其提供的大量样式类来完成样式的定义。Tailwind CSS在与Emotion结合使用的时候,如果采用Emotion的框架无关的使用方式,那么可以直接借助@emotion/css提供的cx函数来组合所需要的Tailwind CSS工具类。

但是如果应用项目采用的是与React固定搭配的形式,那么就需要借助一些其他的工具库来辅助一下了。要达到在应用项目中组合使用Tailwind CSS框架的目的,我们所需要的主要辅助工具库是twin.macro。在应用项目中引入twin.macro以后,还需要在项目中配置babel-plugin-macros来支持twin.macro的样式转换。

在项目中添加所有的相关支持,只需要运行以下命令。

npm install twin.macro tailwindcss -D
yarn add twin.macro tailwindcss -D

Warning

不需要在项目中再添加babel-plugin-macros,因为twin.macro库已经安装了这个依赖,所以在应用项目中可以直接使用。

接下来就是对应用项目进行配置,首先需要配置babel-plugin-macros使用Emotion。这个配置在package.json中,需要添加一个名为babelMacros的键。

{
  "babelMacros": {
    "twin": {
      "preset": "emotion"
    }
  }
}

Warning

只要是在项目中使用twin.macro,不管是使用Create React App还是使用Vite,都需要在package.json中增加这条配置。

在配置好Tailwind CSS的配置文件tailwind.config.js以后,就可以继续配置babel-plugin-macros了。tailwind.config.js文件可以使用以下命令生成。

npx tailwind init --full

以Vite为例,在vite.config.js中需要编写以下内容来配置 babel-plugin-macros

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [
    react({
      babel: {
        plugins: [
          'babel-plugin-macros',
          [
            '@emotion/babel-plugin-jsx-pragmatic',
            {
              export: 'jsx',
              import: '__cssprop',
              module: '@emotion/react'
            }
          ],
          ['@babel/plugin-transform-react-jsx', { pragma: '__cssprop' }, 'twin.macro']
        ]
      }
    })
  ]
});

Tip

如果使用的是Create React App,那么CRA使用的Webpack会自动从 package.json中加载babel-plugin-macros的配置,所以也就不需要在添加其他的配置。

完成twin.macro的配置以后,就可以仿照以下示例编写React组件了。

// 直接使用twin.macro提供的tw属性引入工具样式
import 'twin.macro';

const One = () => <div tw="text-blue-300 w-full">One</div>;
// 使用Style Components风格语法定义组件,注意此时不需要引入@emotion/styled。
import tw, { styled } from 'twin.macro';

const Four = tw.div`border border-solid border-blue-300 hover:border-black`;
const Five = tw(Four)`border-purple-500`;

// 还可以直接使用闭包函数来定义条件样式。
const StyledSix = styled.div(({ hasBorder }) => [
  `color: black;`,
  hasBorder && tw`border-purple-500 border-solid border rounded-sm`
]);
const Six = () => <StyledSix hasBorder>Six</StyledSix>;

// 使用字符串模板的形式也可以。
const StyledSeven = styled.div`
  color: black;
  ${({ hasBorder }) => hasBorder && tw`border border-solid border-purple-500`}
`;
const Seven = () => <StyledSeven hasBorder>Seven</StyledSeven>;

// 或者还可以混用多种样式定义形式。
const StyledEight = styled.div`
  ${tw`text-sm`};
  ${({ hasBorder }) => hasBorder && tw`border-purple-500`};
  ${({ color }) =>
    color &&
    `
        color: ${color};
    `};
  font-weight: 500;
`;
const Eight = () => (
  <StyledEight hasBorder color="blue">
    Eight
  </StyledEight>
);
// 在结合Emotion使用的时候,Emotion的css函数是从twin.macro中引入的。
// twin.macro提供的tw字符串模板函数是用来解析工具样式的,不要与tw属性混淆了。
import tw, { css } from 'twin.macro';

const hoverStyles = css`
  &:hover {
    border-color: black;
    ${tw`text-black border-solid`}
  }
`;
const Three = ({ hasHover, text = 'Three' }) => <div css={[tw`border`, hasHover && hoverStyles]}>{text}</div>;