Tailwind CSS 插件怎么用?如何开发自定义插件?

文章导读
上一个 测验 下一个 Tailwind CSS 插件允许使用可重用的第三方插件扩展 Tailwind。插件让你使用 JavaScript 而不是常规 CSS 代码向 Tailwind 添加新样式。
📋 目录
  1. A 官方插件
  2. B 添加 Utilities
  3. C 添加组件
  4. D 添加基础样式
  5. E 添加变体
  6. F 扩展配置
  7. G 暴露选项
  8. H CSS-in-JS 语法
A A

Tailwind CSS - 插件



上一个
测验
下一个

Tailwind CSS 插件允许使用可重用的第三方插件扩展 Tailwind。插件让你使用 JavaScript 而不是常规 CSS 代码向 Tailwind 添加新样式。

要创建你的第一个插件,你需要做两件事:

  • 导入 plugin 函数:通过在 Tailwind CSS 配置文件中添加 import { plugin } from 'tailwindcss/plugin' 来完成。
  • 将你的插件添加到 plugins 数组中:通过在 plugins 数组中调用 plugin 函数来完成。在 plugin 函数内部,你将编写插件的代码。
const plugin = require('tailwindcss/plugin')

module.exports = {
    plugins: [
    plugin(function({ addUtilities, addComponents, e, config }) {
        // 在这里添加你的自定义样式
    }),
    ]
}

插件函数设计得非常灵活。它们接受一个对象作为输入,可以分解为多个 helper 函数以便于处理。

  • addUtilities() 用于注册新的静态 utility 样式。
  • matchUtilities() 用于注册新的动态 utility 样式。
  • addComponents() 用于注册新的静态 component 样式。
  • matchComponents() 用于注册新的动态 component 样式。
  • addBase() 用于注册新的 base 样式。
  • addVariant() 用于注册自定义静态 variants。
  • matchVariant() 用于注册自定义动态 variants。
  • theme() 用于查找用户 theme 配置中的值。
  • config() 用于查找用户 Tailwind 配置中的值。
  • corePlugins() 用于检查核心插件是否启用。
  • e() 用于手动转义用于 class names 的字符串。

官方插件

Tailwind CSS 提供了一些官方插件,用于尚未包含在核心库中的功能。这些插件可以使用 npm 安装,然后添加到你的 tailwind.config.js 文件中。

/** @type {import('tailwindcss').Config} */
module.exports = {
  // ...
  plugins: [
    require('@tailwindcss/typography'),
    require('@tailwindcss/forms'),
    require('@tailwindcss/aspect-ratio'),
    require('@tailwindcss/container-queries'),
  ]
}

Typography

Tailwind CSS Typography 插件让为内容中的文本添加样式变得简单。它提供了预构建的 class,可以为来自 Markdown 或 CMS 数据库的内容添加时尚的排版效果,让你的文本无需太多努力即可看起来很棒。

<article class="prose lg:prose-xl">
  <h1>
    Garlic bread with cheese: 
    What the science tells us
  </h1>
  <p>
    For years parents have espoused the health
    benefits of eating garlic bread with cheese to their
    children, with the food earning such an iconic status
    in our culture that kids will often dress
    up as warm, cheesy loaf for Halloween.
  </p>
  <p>
    But a recent study shows that the celebrated appetizer
    may be linked to a series of rabies cases
    springing up around the country.
  </p>
  <!-- ... -->
</article>

Forms

@tailwindcss/forms 插件通过提供一组默认样式,使样式化表单变得更容易。这让创建外观一致的表单变得更简单。

Aspect Ratio

@tailwindcss/aspect-ratio 插件为不支持此功能的旧浏览器提供了设置元素宽高比的方法。它添加了像 aspect-w-* 和 aspect-h-* 这样的新 utility class 来控制元素的宽高比。

Container queries

"@tailwindcss/container-queries" 插件允许你使用 "@container" 指令,根据父容器的尺寸为元素添加样式。

<div class="@container">
  <div class="@lg:text-sky-400">
     <!-- ... -->
  </div>
</div>

添加 Utilities

addUtilitiesmatchUtilities 函数允许你向 Tailwind CSS 添加自定义样式,就像默认样式一样。不过,这些自定义样式只有在你的项目中实际使用时,才会被包含在最终的 CSS 中。

静态 Utilities

addUtilities 函数用于添加简单、不变的样式(utilities),这些样式不支持用户提供的参数值。

const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addUtilities }) {
      addUtilities({
        '.content-auto': {
          'content-visibility': 'auto',
        },
        '.content-hidden': {
          'content-visibility': 'hidden',
        },
        '.content-visible': {
          'content-visibility': 'visible',
        },
      })
    })
  ]
}

动态 Utilities

matchUtilities 函数允许你创建使用 theme 配置值的 CSS utility 类。

const plugin = require('tailwindcss/plugin')

module.exports = {
    theme: {
    tabSize: {
        1: '1',
        2: '2',
        4: '4',
        8: '8',
    }
    },
    plugins: [
    plugin(function({ matchUtilities, theme }) {
        matchUtilities(
        {
            tab: (value) => ({
            tabSize: value
            }),
        },
        { values: theme('tabSize') }
        )
    })
    ]
}

你可以在 utilities 中使用自定义值,即使它们没有在 theme 中定义,也可以使用方括号。

<div class="tab-[13]">
   <!-- ... -->
</div>

前缀和 important

插件的工具会自动使用用户设置的诸如 prefixesimportant 等选项。

这意味着给定以下 Tailwind 配置:

/** @type {import('tailwindcss').Config} */
module.exports = {
    prefix: 'tw-',
    important: true,
    // ...
}

上面的示例插件会生成以下 CSS:

.tw-content-auto {
    content-visibility: auto !important;
    }
    .tw-content-hidden {
    content-visibility: hidden !important;
    }
    .tw-content-visible {
    content-visibility: visible !important;
    }

与修饰符一起使用

使用 addUtilities 添加的任何自定义 utilities 都可以与其他 utility 类(如 hover、focus 等)组合使用。

<div class="content-auto lg:content-visible">
  <!-- ... -->
</div>

提供默认值

Utility 插件可以通过向插件函数提供配置对象作为第二个参数来设置默认值。这些默认值行为类似于原始默认设置,用户可以修改或添加它们。

const plugin = require('tailwindcss/plugin')

module.exports = plugin(function({ matchUtilities, theme }) {
    matchUtilities(
    {
        tab: (value) => ({
        tabSize: value
        }),
    },
    { values: theme('tabSize') }
    )
}, {
    theme: {
    tabSize: {
        1: '1',
        2: '2',
        4: '4',
        8: '8',
    }
    }
})

添加组件

Tailwind CSS 中的 addComponents 函数让你可以创建自定义的预设计组件,如按钮、表单、警告等。这些组件就像构建模块一样,可以用于你的设计中,如果需要,你可以使用其他 Tailwind class 来修改它们的外观。

要从插件中添加新的组件样式,请调用 addComponents,使用 CSS-in-JS 语法传入你的样式:

const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addComponents }) {
      addComponents({
        '.btn': {
          padding: '.5rem 1rem',
          borderRadius: '.25rem',
          fontWeight: '600',
        },
        '.btn-blue': {
          backgroundColor: '#3490dc',
          color: '#fff',
          '&:hover': {
            backgroundColor: '#2779bd'
          },
        },
        '.btn-red': {
          backgroundColor: '#e3342f',
          color: '#fff',
          '&:hover': {
            backgroundColor: '#cc1f1a'
          },
        },
      })
    })
  ]
}

前缀和 important

默认情况下,组件 class 会遵循用户的 prefix 偏好,但会忽略他们的 "important" 偏好。

这意味着,给定这个 Tailwind 配置:

/** @type {import('tailwindcss').Config} */
module.exports = {
  prefix: 'tw-',
  important: true,
  // ...
}

上面的示例插件会生成以下 CSS:

.tw-btn {
    padding: .5rem 1rem;
    border-radius: .25rem;
    font-weight: 600;
    }
    .tw-btn-blue {
    background-color: #3490dc;
    color: #fff;
    }
    .tw-btn-blue:hover {
    background-color: #2779bd;
    }
    .tw-btn-red {
    background-color: #e3342f;
    color: #fff;
    }
    .tw-btn-red:hover {
    background-color: #cc1f1a;
    }

通常不建议将组件声明设置为 important。但是,如果你绝对需要这样做,你可以手动添加 !important 关键字。

const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addComponents }) {
      addComponents({
        '.btn': {
          padding: '.5rem 1rem !important',
          borderRadius: '.25rem !important',
          fontWeight: '600 !important',
        },
        // ...
      })
    })
  ]
}

选择器中的所有 class 默认都会添加前缀,所以如果你添加更复杂的样式如:

const plugin = require('tailwindcss/plugin')

module.exports = {
    prefix: 'tw-',
    plugins: [
    plugin(function({ addComponents }) {
        const components = {
        // ...
        '.navbar-inverse a.nav-link': {
            color: '#fff',
        }
        }

        addComponents(components)
    })
    ]
}

会生成以下 CSS:

.tw-navbar-inverse a.tw-nav-link {
    color: #fff;
}

与修饰符一起使用

使用 addUtilities 添加的任何自定义 utility 都可以与其他 utility class(如 hover、focus 等)组合使用。

<div class="btn md:btn-lg">
  <!-- ... -->
</div>

添加基础样式

Tailwind CSS 中的 addBase 函数让你可以添加全局应用于整个项目的根本样式。这非常适合设置默认字体样式、重置浏览器默认值,或定义自定义字体。

要从插件中添加新的基础样式,请调用 addBase,使用 CSS-in-JS 语法传入你的样式:

const plugin = require('tailwindcss/plugin')

module.exports = {
    plugins: [
    plugin(function({ addBase, theme }) {
        addBase({
        'h1': { fontSize: theme('fontSize.2xl') },
        'h2': { fontSize: theme('fontSize.xl') },
        'h3': { fontSize: theme('fontSize.lg') },
        })
    })
    ]
}

添加变体

addVariantmatchVariant 函数允许你创建自己的自定义修饰符,这些修饰符可以像内置变体(如 hoverfocussupports)一样使用。

静态变体

使用 addVariant 函数来创建简单的自定义变体。提供自定义变体的名称和一个描述选择器应该如何修改的格式字符串。

const plugin = require('tailwindcss/plugin')

module.exports = {
    // ...
    plugins: [
    plugin(function({ addVariant }) {
        addVariant('optional', '&:optional')
        addVariant('hocus', ['&:hover', '&:focus'])
        addVariant('inverted-colors', '@media (inverted-colors: inverted)')
    })
    ]
}

第一个参数是用户将在 HTML 中使用的修饰符名称,因此上面的示例将使编写如下类名成为可能:

<form class="flex inverted-colors:outline ...">
    <input class="optional:border-gray-300 ..." />
    <button class="bg-blue-500 hocus:bg-blue-600">...</button>
</form>

动态变体

matchVariant 函数允许你创建自定义参数化变体,类似于内置变体如 supports-*data-*aria-*

const plugin = require('tailwindcss/plugin')

module.exports = {
    plugins: [
    plugin(function({ matchVariant }) {
        matchVariant(
        'nth',
        (value) => {
            return `&:nth-child(${value})`;
        },
        {
            values: {
            1: '1',
            2: '2',
            3: '3',
            }
        }
        );
    })
    ]
}

使用 matchVariant 定义的变体也支持使用方括号表示法传入任意值:

<div class="nth-[3n+1]:bg-blue-500 ...">
  <!-- ... -->
</div>

如果需要控制生成 CSS 的源顺序以避免与其他来自同一变体的值产生优先级问题,可以使用 sort 选项:

matchVariant("min", (value) => `@media (min-width: ${value})`, {
    sort(a, z) {
        return parseInt(a.value) - parseInt(z.value);
    },
    });

父元素和兄弟元素状态

Tailwind 的特殊功能如 group-*peer-* 不会自动与自定义修饰符一起工作。要让它们正常工作,你需要使用 :merge 将自定义修饰符注册为单独的变体。这确保 grouppeer 类在最终样式表中只出现一次,从而正确应用。

const plugin = require('tailwindcss/plugin')

module.exports = {
    // ...
    plugins: [
    plugin(function({ addVariant }) {
        addVariant('optional', '&:optional')addComponents([
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
])
        addVariant('group-optional', ':merge(.group):optional &')
        addVariant('peer-optional', ':merge(.peer):optional ~ &')
    })
    ]
}

扩展配置

插件可以通过将对象作为插件函数的第二个参数来向用户的 tailwind.config.js 文件添加自己的设置。

const plugin = require('tailwindcss/plugin')

module.exports = plugin(function({ matchUtilities, theme }) {
  matchUtilities(
    {
      tab: (value) => ({
        tabSize: value
      }),
    },
    { values: theme('tabSize') }
  )
}, {
  theme: {
    tabSize: {
      1: '1',
      2: '2',
      4: '4',
      8: '8',
    }
  }
})

暴露选项

plugin.withOptions API 允许你使用自定义配置对象来配置插件。这让用户能够调整插件的行为,而这些行为与 theme 设置没有直接关系。例如,你可以使用此 API 让用户指定插件使用的 class names。此 API 的工作方式类似于常规的 plugin API,但不是直接传递值,而是定义函数来接收用户的配置选项并返回插件对应的值。

const plugin = require('tailwindcss/plugin')

module.exports = plugin.withOptions(function (options = {}) {
  return function({ addComponents }) {
    const className = options.className ?? 'markdown'

    addComponents({
      [`.${className}`]: {
        // ...
      }
    })
  }
}, function (options) {
  return {
    theme: {
      markdown: {
        // ...
      }
    },
  }
})

用户在 plugins 配置中注册插件时,会调用你的插件并传递他们的选项:

/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require('./plugins/markdown.js')({
      className: 'wysiwyg'
    })
  ],
}

如果用户不需要传递任何自定义选项,也可以正常注册这种方式创建的插件,而无需调用它们:

/** @type {import('tailwindcss').Config} */
module.exports = {
  theme: {
    // ...
  },
  plugins: [
    require('./plugins/markdown.js')
  ],
}

CSS-in-JS 语法

Tailwind 的插件系统使用 JavaScript 对象来编写 CSS 规则,类似于 Emotion 等 CSS-in-JS 库的方式。这在底层使用了 postcss-js。

考虑这个简单的 CSS 规则:

.card {
    background-color: #fff;
    border-radius: .25rem;
    box-shadow: 0 2px 4px rgba(0,0,0,0.2);
    }

将其转换为 CSS-in-JS 对象如下所示:

addComponents({
    '.card': {
        'background-color': '#fff',
        'border-radius': '.25rem',
        'box-shadow': '0 2px 4px rgba(0,0,0,0.2)',
    }
    })

也支持嵌套(由 postcss-nested 提供支持),使用你可能熟悉的 Sass 或 Less 的相同语法:

addComponents({
    '.card': {
        backgroundColor: '#fff',
        borderRadius: '.25rem',
        boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
        '&:hover': {
        boxShadow: '0 10px 15px rgba(0,0,0,0.2)',
        },
        '@media (min-width: 500px)': {
        borderRadius: '.5rem',
        }
    }
    })

可以在同一个对象中定义多个规则:

addComponents({
    '.btn': {
        padding: '.5rem 1rem',
        borderRadius: '.25rem',
        fontWeight: '600',
    },
    '.btn-blue': {
        backgroundColor: '#3490dc',
        color: '#fff',
        '&:hover': {
        backgroundColor: '#2779bd'
        },
    },
    '.btn-red': {
        backgroundColor: '#e3342f',
        color: '#fff',
        '&:hover': {
        backgroundColor: '#cc1f1a'
        },
    },
    })

或者在需要重复相同 key 的情况下,使用对象数组:

addComponents([
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
  {
    '@media (min-width: 500px)': {
      // ...
    }
  },
])