使用可复用的第三方插件扩展 Tailwind。
插件让您注册新的样式,让 Tailwind 使用 JavaScript 代替 CSS 注入用户的样式表。
要开始您的第一个插件,先从 tailwindcss/plugin 导入 Tailwind 的 plugin 函数。然后在您的 plugins 数组中,调用这个函数,用一个匿名函数作为其第一个参数。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities, addComponents, e, prefix, config }) {
// Add your custom styles here
}),
]
}插件函数接收一个单一的对象参数,可以 destructured 成几个帮助函数。
addUtilities(), for registering new utility stylesaddComponents(), for registering new component stylesaddBase(), for registering new base stylesaddVariant(), for registering custom variantse(), for escaping strings meant to be used in class namesprefix(), for manually applying the user's configured prefix to parts of a selectortheme(), for looking up values in the user's theme configurationvariants(), for looking up values in the user's variants configurationconfig(), for looking up values in the user's Tailwind configurationpostcss, for doing low-level manipulation with PostCSS directlyaddUtilities 函数允许您在 Tailwind 的 utilities 层注册新的样式。
插件功能类的输出顺序是按照其注册的顺序,在内置的功能类之后,所以如果一个插件的作用目标是任何一个与内置功能类相同的属性,插件功能类将优先。
要从插件中添加新的功能类,调用 addUtilities,使用 CSS-in-JS 语法 传递您的样式。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
const newUtilities = {
'.skew-10deg': {
transform: 'skewY(-10deg)',
},
'.skew-15deg': {
transform: 'skewY(-15deg)',
},
}
addUtilities(newUtilities)
})
]
}默认情况下,插件功能类会自动遵守用户的 prefix 和 important 偏好。
也就是说,如果给出这样的 Tailwind 配置:
// tailwind.config.js
module.exports = {
prefix: 'tw-',
important: true,
// ...
}...上面的示例插件会生成以下CSS:
.tw-skew-10deg {
transform: skewY(-10deg) !important;
}
.tw-skew-15deg {
transform: skewY(-15deg) !important;
}如果有必要,您可以通过向 addUtilities 传递一个选项对象作为第二个参数来选择不使用这种行为。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
const newUtilities = {
// ...
}
addUtilities(newUtilities, {
respectPrefix: false,
respectImportant: false,
})
})
]
}要生成 responsive、hover、focus、active 或样式的其它变体,请使用 variants 选项指定您想生成的变体。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
const newUtilities = {
// ...
}
addUtilities(newUtilities, {
variants: ['responsive', 'hover'],
})
})
]
}如果您只需要指定变体,而不需要选择不使用默认的前缀或 important 选项,您也可以直接将变体数组作为第二个参数传递。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
const newUtilities = {
// ...
}
addUtilities(newUtilities, ['responsive', 'hover'])
})
]
}如果您希望用户在他们的 tailwind.config.js 文件中的 variants 部分提供自己的变体,您可以使用 variants() 函数来获取他们配置的变体。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
variants: {
customPlugin: ['responsive', 'hover'],
},
plugins: [
plugin(function({ addUtilities, variants }) {
const newUtilities = {
// ...
}
addUtilities(newUtilities, variants('customPlugin'))
})
]
}addComponents 函数允许您在 Tailwind 的 components 层注册新的样式。
用它来添加更个性化、更复杂的类,比如按钮、表单控件、警告等;就是您在其他框架中经常看到的您可能需要使用功能类覆盖的那种预建组件。
要从插件中添加新的组件样式,调用 addComponents ,使用 CSS-in-JS 语法 传递您的样式。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
const buttons = {
'.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'
},
},
}
addComponents(buttons)
})
]
}默认情况下,组件类自动遵守用户的 prefix 偏好,但不受用户的 important 偏好的影响。
这意味着如果有以下 Tailwind 配置:
// tailwind.config.js
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-blue {
background-color: #e3342f;
color: #fff;
}
.tw-btn-blue:hover {
background-color: #cc1f1a;
}虽然很少有一个很好的理由让组件声明 important,但如果您真的需要这样做,您可以手动添加 !important 。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
const buttons = {
'.btn': {
padding: '.5rem 1rem !important',
borderRadius: '.25rem !important',
fontWeight: '600 !important',
},
// ...
}
addComponents(buttons)
})
]
}选择器中的所有类都会默认添加前缀,所以如果您添加一个更复杂的样式,比如:
// tailwind.config.js
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;
}要选择不使用前缀,可以传递一个 options 对象作为第二个参数给 addComponents:
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
prefix: 'tw-',
plugins: [
plugin(function({ addComponents }) {
const components = {
// ...
}
addComponents(components, {
respectPrefix: false
})
})
]
}要生成组件的 responsive、hover、focus、active或其他变体,请使用 variants 选项指定您想生成的变体。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
const newComponents = {
// ...
}
addComponents(newComponents, {
variants: ['responsive', 'hover'],
})
})
]
}如果您只需要指定变体,而不需要选择不使用默认的前缀或 important 选项,您也可以直接将变体数组作为第二个参数传递。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents }) {
const newComponents = {
// ...
}
addComponents(newComponents, ['responsive', 'hover'])
})
]
}如果您希望用户在他们的 tailwind.config.js 文件中的 variants 部分提供自己的变体,您可以使用 variants() 函数来获取他们配置的变体。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
variants: {
customPlugin: ['responsive', 'hover'],
},
plugins: [
plugin(function({ addComponents, variants }) {
const newComponents = {
// ...
}
addComponents(newComponents, variants('customPlugin'))
})
]
}addBase 函数允许您在 Tailwind 的 base 层注册新的样式。
使用它来添加诸如基本的排版样式、个性化的全局重置或 @font-face 规则。
要从插件中添加新的基础样式,调用 addBase,使用 CSS-in-JS 语法 传递您的样式。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addBase, config }) {
addBase({
'h1': { fontSize: config('theme.fontSize.2xl') },
'h2': { fontSize: config('theme.fontSize.xl') },
'h3': { fontSize: config('theme.fontSize.lg') },
})
})
]
}由于基本样式是针对 div、h1 等裸选择器的,所以它们不遵从用户的 prefix 或 important 配置。
如果您的插件生成的类中包含用户提供的字符串,您可以使用 e 函数来转义这些类名,以确保非标准字符被正确地自动处理。
例如,这个插件生成了一组 .rotate-{angle} 功能类,其中 {angle} 是用户提供的字符串。e 函数用于转义连接的类名,以确保像 .rotate-1/4 这样的类能按预期工作。
// tailwind.config.js
const _ = require('lodash')
const plugin = require('tailwindcss/plugin')
module.exports = {
theme: {
rotate: {
'1/4': '90deg',
'1/2': '180deg',
'3/4': '270deg',
}
},
plugins: [
plugin(function({ addUtilities, config, e }) {
const rotateUtilities = _.map(config('theme.rotate'), (value, key) => {
return {
[`.${e(`rotate-${key}`)}`]: {
transform: `rotate(${value})`
}
}
})
addUtilities(rotateUtilities)
})
]
}这个插件会生成以下CSS:
.rotate-1\/4 {
transform: rotate(90deg);
}
.rotate-1\/2 {
transform: rotate(180deg);
}
.rotate-3\/4 {
transform: rotate(270deg);
}注意只转义您真正想转义的内容;不要在类名中传递前导的 . 或在 :hover 或 :focus 等伪类的开头传递 :,否则这些字符将被转义。
此外,因为 CSS 有关于类名的规则(类名不能以数字开头,但可以包含数字),所以最好是转义完整的类名(不只是用户提供的部分),否则您可能会得到不必要的转义序列。
// Will unnecessarily escape `1`
`.rotate-${e('1/4')}`
// => '.rotate-\31 \/4'
// Won't escape `1` because it's not the first character
`.${e('rotate-1/4')}`
// => '.rotate-1\/4'如果您正在写一些复杂的东西,您只想给某些类加前缀,您可以使用 prefix 函数来精细控制何时应用用户配置的前缀。
例如,如果您正在创建一个插件,以便在一组内部项目中重复使用,在其选择器中包含现有的类,您可能只想给新的类加上前缀。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
prefix: 'tw-',
plugins: [
plugin(function({ addComponents, prefix }) {
addComponents({
[`.existing-class > ${prefix('.new-class')}`]: {
backgroundColor: '#fff',
}
})
})
]
}这将生成以下CSS:
.existing-class > .tw-new-class {
background-color: #fff;
}prefix 函数会给选择器中的所有类加前缀,而忽略不是类的选择器,所以传递像这样复杂的选择器是完全安全的。
prefix('.btn-blue .w-1\/4 > h1.text-xl + a .bar')
// => '.tw-btn-blue .tw-w-1\/4 > h1.tw-text-xl + a .tw-bar'config、theme 和 variants 函数允许您使用点符号从用户的 Tailwind 配置中获取一个值,如果该路径不存在,则提供一个默认值。
例如,这个简化版的内置 容器 插件使用 theme 函数来获取用户配置的断点。
// tailwind.config.js
const _ = require('lodash')
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addComponents, theme }) {
const screens = theme('screens', {})
const mediaQueries = _.map(screens, width => {
return {
[`@media (min-width: ${width})`]: {
'.container': {
'max-width': width,
},
},
}
})
addComponents([
{ '.container': { width: '100%' } },
...mediaQueries,
])
})
]
}请注意,theme 函数实际上只是使用 config 函数访问用户配置的主题部分的一个快捷方式。
// These are equivalent
config('theme.screens')
theme('screens')如果您想引用用户的 variants 配置,建议您使用 variants() 函数而不是 config 函数。
不要使用 config 函数来查找变体
addUtilities(newUtilities, config('variants.customPlugin'))使用 variants 函数代替
addUtilities(newUtilities, variants('customPlugin'))由于 variants 可以简单地成为一个全局的变体列表,为整个项目中的每一个插件进行配置,所以使用 variants() 函数可以让您很容易地遵从用户的配置,而不是自己重新实现这个逻辑。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
variants: ['responsive', 'hover', 'focus'],
plugins: [
plugin(function ({ config, variants }) {
config('variants.customPlugin')
// => undefined
variants('customPlugin')
// => ['reponsive', 'hover', 'focus']
})
]
}通常情况下,一个插件暴露自己的选项是有意义的,用户可以配置这些选项来定制插件的行为。
最好的方法是在用户的 theme 和 variants 配置中定义自己的键,并要求他们在那里提供任何选项,这样您就可以通过 theme 和 variants 函数访问它们。
例如,这里有一个插件(提取到自己的模块),用于创建简单的渐变功能类,接受要生成的渐变值和变体做为选项。
// ./plugins/gradients.js
const _ = require('lodash')
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ addUtilities, e, theme, variants }) {
const gradients = theme('gradients', {})
const gradientVariants = variants('gradients', [])
const utilities = _.map(gradients, ([start, end], name) => ({
[`.${e(`bg-gradient-${name}`)}`]: {
backgroundImage: `linear-gradient(to right, ${start}, ${end})`
}
}))
addUtilities(utilities, gradientVariants)
})要使用它,您需要在您的插件列表中 require 它,在 theme 和 variants 中的 gradients 键下指定您的配置。
// tailwind.config.js
module.exports = {
theme: {
gradients: theme => ({
'blue-green': [theme('colors.blue.500'), theme('colors.green.500')],
'purple-blue': [theme('colors.purple.500'), theme('colors.blue.500')],
// ...
})
},
variants: {
gradients: ['responsive', 'hover'],
},
plugins: [
require('./plugins/gradients')
],
}要为您的插件提供默认的 theme 和 variants 选项,请向 Tailwind 的 plugin 函数传递包含默认值的第二个参数,。
// ./plugins/gradients.js
const _ = require('lodash')
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ addUtilities, e, theme, variants }) {
// ...
}, {
theme: {
gradients: theme => ({
'blue-green': [theme('colors.blue.500'), theme('colors.green.500')],
'purple-blue': [theme('colors.purple.500'), theme('colors.blue.500')],
// ...
})
},
variants: {
gradients: ['responsive', 'hover'],
}
})这个对象只是另一个 Tailwind 配置对象,并具有与 tailwind.config.js 中使用的配置对象相同的所有属性和功能。
通过以这种方式提供您的默认值,最终用户将能够 覆盖 和 扩展 您的默认值,就像他们可以覆盖和扩展 Tailwind 的内置样式一样。
每一个 addUtilities、addComponents 和 addBase 都期望 CSS 规则写成 JavaScript 对象。Tailwind 使用的语法,您可能会从 CSS-in-JS 库中识别出来,如 Emotion,并由 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)',
}
})为方便起见,属性名也可以用 camelCase 书写,并会自动翻译成 dash-case:
addComponents({
'.card': {
backgroundColor: '#fff',
borderRadius: '.25rem',
boxShadow: '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'
},
},
})...或者作为一个对象数组,以备您需要重复使用同一个键:
addComponents([
{
'@media (min-width: 500px)': {
// ...
}
},
{
'@media (min-width: 500px)': {
// ...
}
},
{
'@media (min-width: 500px)': {
// ...
}
},
])addVariant 函数允许您注册自己的自定义 变体,这些变体可以像内置的 hover、hover、hover 等变体一样使用。
要添加一个新的变量,调用 addVariant 函数,传入您的自定义变量的名称,以及一个回调,根据需要修改受影响的 CSS 规则。
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant, e }) {
addVariant('disabled', ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {
return `.${e(`disabled${separator}${className}`)}:disabled`
})
})
})
]
}回调收到的对象可以被反构为以下部分:
modifySelectors, a helper function to simplify adding basic variantsseparator, the user's configured separator stringcontainer, a PostCSS Container containing all of the rules the variant is being applied to, for creating complex variants如果您想添加一个简单的变量,只需要改变选择器,使用 modifySelectors 助手。
modifySelectors 助手接受一个函数,该函数接收一个对象,该对象可以被重构为以下部分:
selector, the complete unmodified selector for the current ruleclassName, the class name of the current rule with the leading dot removed您传递给 modifySelectors 的函数应该简单地返回修改后的选择器。
例如,一个 first-child 的变体插件可以这样写:
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant, e }) {
addVariant('first-child', ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {
return `.${e(`first-child${separator}${className}`)}:first-child`
})
})
})
]
}如果您需要做的事情不仅仅是简单地修改选择器(比如改变实际的规则声明,或者将规则包装在另一个 at-rule 中),您将需要使用 container 实例。
使用 container 实例,您可以在给定的模块或 @variants 块中遍历所有的规则,并使用标准的 PostCSS API 随意操作它们。
例如,该插件通过在类前加上感叹号,并将每个声明修改为 important,为每个受影响的功能创建一个 important 版本。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant }) {
addVariant('important', ({ container }) => {
container.walkRules(rule => {
rule.selector = `.\\!${rule.selector.slice(1)}`
rule.walkDecls(decl => {
decl.important = true
})
})
})
})
]
}这个插件将容器内的所有规则,用 @supports (display: grid) at-rule 包装起来,并在每个规则前加上 supports-grid 。
// tailwind.config.js
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addVariant, e, postcss }) {
addVariant('supports-grid', ({ container, separator }) => {
const supportsRule = postcss.atRule({ name: 'supports', params: '(display: grid)' })
supportsRule.append(container.nodes)
container.append(supportsRule)
supportsRule.walkRules(rule => {
rule.selector = `.${e(`supports-grid${separator}${rule.selector.slice(1)}`)}`
})
})
})
]
}要了解更多关于直接使用 PostCSS 的信息,请查看 PostCSS API 文档。
使用自定义变体与使用 Tailwind 的内置变体没有什么不同。
要使定制的变体与 Tailwind 的核心插件一起使用,将它们添加到您的配置文件的 variants 部分。
// tailwind.config.js
modules.exports = {
variants: {
borderWidths: ['responsive', 'hover', 'focus', 'first-child', 'disabled'],
}
}要在您自己的CSS中使自定义变体和自定义功能类一起使用,请使用 variants at-rule。
@variants hover, first-child {
.bg-cover-image {
background-image: url('/path/to/image.jpg');
}
}