Compound Variants
compound variants 只在你列出的 variant 值全部匹配时才应用样式。它解决的是“我只想在 variant: 'outlined' 且 color: 'danger' 时应用这个样式”这类需求。也可以只列出一个维度,此时它就像一个在其他样式之后才应用的 variant 样式。
compoundVariants
compound variant 只在多个维度同时匹配特定值时应用样式,适合“X 同时是 Y 时外观不同”的模式。
const button = ev({
base: {
border: '1px solid transparent',
borderRadius: 8,
cursor: 'pointer',
fontWeight: 600,
transition: 'all 0.2s ease',
},
variants: {
variant: {
filled: {
background: 'var(--button-color)',
color: 'white',
},
outlined: {
background: 'transparent',
borderColor: 'var(--button-color)',
color: 'var(--button-color)',
},
text: {
background: 'transparent',
color: 'var(--button-color)',
},
},
size: {
small: {
padding: '8px 16px',
fontSize: 12,
},
medium: {
padding: '10px 20px',
fontSize: 14,
},
large: {
padding: '12px 24px',
fontSize: 16,
},
},
color: {
primary: {
'--button-color': '#d36ac2',
},
secondary: {
'--button-color': '#475569',
},
},
},
compoundVariants: [
{
variants: {
variant: 'filled',
size: 'large',
color: 'primary',
},
style: {
boxShadow: '0 4px 12px rgba(211, 106, 194, 0.4)',
},
},
],
defaultVariants: {
variant: 'filled',
size: 'medium',
color: 'primary',
},
});
<button
css={button({
size: 'large',
color: 'primary',
})}
>
Large primary
</button>
<button
css={button({
size: 'large',
color: 'secondary',
})}
>
Large secondary
</button>compound variants 按数组顺序求值,并叠加在匹配的普通 variants 之后,因此可以放心地覆盖样式。
何时使用
以下情况适合使用 compound variant:
- 某个样式同时依赖两个或更多维度。
- 如果用单一维度的 variant 来表达,就得新增维度或重复定义值。
- 组件内部开始出现条件 CSS(
size === 'lg' && color === 'primary' && ...)。
如果样式只依赖一个维度,直接写进 variants 即可。compound variants 用于维度之间的交叉组合。
模式:filled / outlined / text × color
一种常见的设计系统模式:同一组颜色,用三种方式呈现。
import { ev } from 'emotion-variants';
const button = ev({
base: {
padding: '8px 16px',
borderRadius: 8,
cursor: 'pointer',
border: 'none',
},
variants: {
variant: {
filled: {},
outlined: {
background: 'transparent',
border: '2px solid currentColor',
},
text: {
background: 'transparent',
},
},
color: {
primary: {},
danger: {},
},
},
compoundVariants: [
// Filled
{
variants: {
variant: 'filled',
color: 'primary',
},
style: {
background: '#d36ac2',
color: 'white',
},
},
{
variants: {
variant: 'filled',
color: 'danger',
},
style: {
background: '#dc2626',
color: 'white',
},
},
// Outlined
{
variants: {
variant: 'outlined',
color: 'primary',
},
style: {
color: '#d36ac2',
},
},
{
variants: {
variant: 'outlined',
color: 'danger',
},
style: {
color: '#dc2626',
},
},
// Text
{
variants: {
variant: 'text',
color: 'primary',
},
style: {
color: '#d36ac2',
},
},
{
variants: {
variant: 'text',
color: 'danger',
},
style: {
color: '#dc2626',
},
},
],
defaultVariants: {
variant: 'filled',
color: 'primary',
},
});color variant 在 variants 中是空对象,因为它的样式只有在与 variant 组合时才有意义。实际的值由 compound variants 承载。
模式:size × density 覆盖
有时 compound variant 只在某个特定交叉点上微调基础属性。
const card = ev({
base: {
padding: 16,
borderRadius: 12,
},
variants: {
size: {
sm: {
padding: 12,
},
md: {
padding: 16,
},
lg: {
padding: 24,
},
},
density: {
comfortable: {},
compact: {},
},
},
compoundVariants: [
{
variants: {
size: 'lg',
density: 'compact',
},
style: {
padding: 16,
},
},
],
});只有 lg + compact 这个组合会覆盖该尺寸原本的 padding。
匹配多个值
条件可以是数组。只要 variant 的值是列出值中的任意一个就算匹配,因此一个条目就能覆盖原本要逐个复制的情况。
const button = ev({
variants: {
variant: {
filled: {},
outlined: {},
text: {},
},
color: {
primary: {},
danger: {},
},
},
compoundVariants: [
{
variants: {
variant: ['outlined', 'text'],
color: 'danger',
},
style: {
color: 'crimson',
},
},
],
});
button({ variant: 'outlined', color: 'danger' }); // 包含 compound 样式
button({ variant: 'text', color: 'danger' }); // 同样包含
button({ variant: 'filled', color: 'danger' }); // 不包含维度之间仍然是 AND 关系。列出的每个维度都必须匹配;数组只是放宽了它所在维度的匹配范围。空数组永远不会匹配。
顺序很重要
每次调用时,compound variants 会按在数组中出现的顺序追加在普通 variants 之后。如果两个 compound variant 都匹配并设置了同一属性,后者生效。
compoundVariants: [
{
variants: {
size: 'lg',
},
style: {
fontWeight: 600,
},
},
{
variants: {
size: 'lg',
color: 'primary',
},
style: {
fontWeight: 700, // 覆盖上面的条目
},
},
],compound variant 也可以只匹配单个维度。它的行为与普通 variant 相同,但当你想把所有“条件”规则集中在一处时很有用。
另请参阅
最后更新于