指导
在本节中,我们将安装 EffCSS 并了解如何使用它。
安装
在终端中输入:
sh
# npm
npm i effcss
# pnpm
pnpm add effcss
# yarn
yarn add effcss使用
要使用 EffCSS 创建样式,只需调用相应的工具即可。幸运的是,工具数量很少,而且从名称上就能看出它们的功能。
EffCSS 使用 classNames、attributes 和 customStyles 这三个工具创建独立的样式表。前两个工具需要指定一个 TypeScript 类型契约,用于实现选择器。这样,您就可以控制样式的创建和使用。该契约类型是一个包含任意层级嵌套属性的对象:
ts
/**
* Components stylesheet
*/
type Components = {
/**
* Is rounded
*/
rounded: true;
/**
* Height
*/
h: 'full' | 'half';
/**
* Card
*/
card: {
/**
* Card background
*/
bg: 'primary' | 'secondary';
/**
* Is card disabled
*/
disabled: boolean;
};
/**
* Spinner component
*/
spinner: {};
};
/**
* Utils stylesheet
*/
type Utils = {
/**
* Width
*/
w: 's' | 'm' | 'l';
/**
* Spacing
*/
spacing: 0 | 1 | 2;
/**
* Blink animation
*/
blink: true;
};让我们仔细看看每项工具的用途。
classNames
classNames 创建一个样式表并返回一个用于派生类名的函数:
tsx
import { classNames } from 'effcss';
// declare
type Card = {
w: 's' | 'm' | 'l';
blur: true;
card: {
variant: 1 | 2;
rounded: true;
};
}
// implement
const card = classNames<Card>((selectors) => {
const {w, card, blur} = selectors;
return {
[w.s]: {
width: '12px'
},
[w.m]: {
width: '24px'
},
[w.l]: {
width: '26px'
},
[blur.true]: {
filter: 'blur(5px)'
},
[card]: {
background: 'white',
border: 'none'
},
[card.variant[1]]: {
width: 'auto',
display: 'block',
padding: '12px',
':hover': {
cursor: 'pointer'
}
},
[card.variant[2]]: {
width: 'auto',
display: 'flex',
flexDirection: 'column',
padding: '16px',
':hover': {
outline: '2px solid black'
}
},
[card.rounded.true]: {
borderRadius: '1rem'
}
}
});
// apply
export const Component = () => {
const cls = card({
card: {
rounded: true
},
w: 's'
});
return <div className={cls}>
Card
</div>
};attributes
attributes 创建一个样式表并返回一个用于派生属性的函数:
tsx
import { attributes } from 'effcss';
// declare
type Card = {
w: 's' | 'm' | 'l';
blur: true;
card: {
variant: 1 | 2;
rounded: true;
};
}
// implement
const card = attributes<Card>((selectors) => {
const {w, card, blur} = selectors;
return {
[w.s]: {
width: '12px'
},
[w.m]: {
width: '24px'
},
[w.l]: {
width: '26px'
},
[blur.true]: {
filter: 'blur(5px)'
},
[card]: {
background: 'white',
border: 'none'
},
[card.variant[1]]: {
width: 'auto',
display: 'block',
padding: '12px',
':hover': {
cursor: 'pointer'
}
},
[card.variant[2]]: {
width: 'auto',
display: 'flex',
flexDirection: 'column',
padding: '16px',
':hover': {
outline: '2px solid black'
}
},
[card.rounded.true]: {
borderRadius: '1rem'
}
}
});
// apply
export const Component = () => {
const attrs = card({
card: {
rounded: true
},
w: 's'
});
return <div {...attrs}>
Card
</div>
};customStyles
customStyles 创建的样式表不包含派生选择器:
tsx
import { customStyles } from 'effcss';
// implement
customStyles(() => ({
'.custom': {
background: 'transparent',
width: '100%',
'&:hover': {
outline: '2px solid black'
}
},
'@media screen and (max-width: 768px)': {
'.custom': {
width: '50%'
}
}
}));
// apply
export const Component = () => {
return <div className='custom'>
Card
</div>
};variables
variable 创建一个 CSS @property 规则,variables 一次创建多个规则:
ts
import { customStyles, variable, variables } from 'effcss';
// global
const offset = variable('10px');
const colors = variable({
primary: {
syntax: 'color',
inherits: false,
initialValue: '#2192a7'
},
secondary: '#425158'
});
customStyles(() => {
// local
const localOffset = variable({
inherits: true,
initialValue: '12px'
});
const localColors = variables({
primary: '#2192a7',
secondary: '#425158'
});
return {
'.global': {
background: colors.primary(),
// with fallback value
padding: offset('8px'),
},
'.local': {
// with fallback value
background: localColors.primary('grey'),
padding: localOffset()
},
'.override': {
[localColors.primary]: 'grey'
}
};
});animations
animation 创建一个 CSS @keyframes 规则,animations 一次创建多个规则:
ts
import { customStyles, animation, animations } from 'effcss';
// global
const spin = animation({
from: {
transform: 'rotate(0deg)',
},
to: {
transform: 'rotate(360deg)',
},
});
const blink = animations({
simple: {
'50%': {
visibility: 'hidden'
}
},
smooth: {
'0%': {
opacity: 1
},
'50%': {
opacity: 0
},
'100%': {
opacity: 1
}
}
});
customStyles(() => {
// local
const localSpin = animation(/* the same */);
const localBlink = animations(/* the same */);
return {
'.global-spin': {
animation: `${spin} 6s infinite`
},
'.global-blink': {
animation: `${blink.smooth} 2s infinite`
},
'.local-spin': {
animation: `${localSpin} 6s infinite`
},
'.local-blink': {
animation: `${localBlink.smooth} 2s infinite`
},
};
});layers
layer 创建一个 CSS @layer 规则,layers 一次创建多个规则:
ts
import { customStyles, layer, layers } from 'effcss';
// global
const single = layer();
const list = layers(['theme', 'layout', 'utilities']);
customStyles(() => {
// local
const localSingle = layer();
const localList = layers(['theme', 'layout', 'utilities']);
return {
[single]: {
'.global-layer': {
background: 'transparent'
}
},
[list.theme]: {
'.global-layer': {
background: '#425158'
}
},
[localSingle]: {
'.local-layer': {
background: 'white'
}
},
[localList.theme]: {
'.local-layer': {
background: 'grey'
}
}
};
});containers
container 创建一个 CSS @container 规则,containers 一次创建多个规则:
ts
import { customStyles, container, containers } from 'effcss';
// global
const single = container();
const multiple = containers({
normal: '',
inline: 'inline-size',
scrollState: 'size scroll-state'
});
customStyles(() => {
// local
const localSingle = container();
const localMultiple = containers({
normal: '',
inline: 'inline-size',
scrollState: 'size scroll-state'
});
return {
'.global-container': {
container: single()
},
[single + ' not scroll-state(scrollable: none)']: {
'.inside-global-container': {
width: '100%'
}
},
'.local-container': {
container: localMultiple.inline()
},
[localMultiple.inline + ' (max-width: 768px)']: {
'.inside-local-container': {
width: '100%'
}
},
};
});update
update 会刷新全局变量的初始值:
ts
const offset = variable('10px');
const colors = variable({
primary: {
syntax: 'color',
inherits: false,
initialValue: '#2192a7'
},
secondary: '#425158'
});
update(offset, '14px');
update(colors, {
primary: 'grey',
secondary: 'green'
});stylesheet
stylesheet 返回创建的样式表:
ts
const custom = customStyles(() => {
return {
'.custom': {
padding: '1rem'
},
};
});
// specified stylesheet
const customStylesheet = stylesheet(custom);configure
在创建第一个样式表之前调用 configure 会影响样式生成:
ts
configure({
// custom prefix for ids
prefix: 'custom',
// disable minification
minify: false,
// emulate server-side mode
emulate: true
});serialize
serialize 函数将其参数或所有已创建的样式表转换为 HTML 字符串:
ts
const custom = customStyles(() => {
return {
'.custom': {
padding: '1rem'
},
};
});
// specified stylesheet
const customHTML = serialize(custom);
// all created stylesheets
const fullHTML = serialize();生成的字符串可用于 SSG/SSR。