ガイド
このセクションでは、EffCSS のインストール方法と使い方を説明します。
インストール
ターミナルで以下を入力してください。
# npm
npm i effcss
# pnpm
pnpm add effcss
# yarn
yarn add effcss使用方法
EffCSSでスタイルを作成するには、ユーティリティを呼び出すだけです。幸いなことに、ユーティリティの種類は非常に少なく、名前を見ればその機能が理解できます。
数あるユーティリティの中でも、classNamesとattributesは特に重要です。これらを使用するには、セレクタを実装するためのTypeScript型のコントラクトを指定する必要があります。これにより、スタイルの作成と使用の両方を制御できます。コントラクト型は、任意のレベルのネストを持つプロパティを持つオブジェクトです。
/**
* 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
classNameは、指定されたコンテンツを持つ単一のCSSルールを作成し、クラスセレクタを文字列として返します。
import { className } from 'effcss';
// create
const cls = className({
margin: 'auto',
'&:hover': {
outline: '2px solid black',
'.child': {
background: 'grey'
}
}
});
// apply
export const Component = () => {
return <div className={cls}>
Card
</div>
};classNamesはスタイルシートを作成し、クラス名を導出するための関数を返します。
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'
}
}
});
const cls = card({
card: {
rounded: true
},
w: 's'
});
// apply
export const Component = () => {
return <div className={cls}>
Card
</div>
};lazyClassNamesは、セレクタが最初に導出された後に渡された関数を実行し、スタイルシートを作成するという点でclassNamesとは異なります。
import { lazyClassNames } from 'effcss';
// declare
type Card = {/* the same */};
// implement
const card = lazyClassNames<Card>(/* the same */);
// the stylesheet has not been created yet
const cls = card({
card: {
rounded: true
},
w: 's'
});
// the stylesheet has been created
// apply
export const Component = () => {
return <div className={cls}>
Card
</div>
};attributes
attributeは、指定されたコンテンツを持つ単一のCSSルールを作成し、属性セレクタをオブジェクトとして返します。
import { attribute } from 'effcss';
// create
const attr = attribute({
margin: 'auto',
'&:hover': {
outline: '2px solid black',
'.child': {
background: 'grey'
}
}
});
// apply
export const Component = () => {
return <div {...attr}>
Card
</div>
};attributesはスタイルシートを作成し、属性を導出するための関数を返します。
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'
}
}
});
const attrs = card({
card: {
rounded: true
},
w: 's'
});
// apply
export const Component = () => {
return <div {...attrs}>
Card
</div>
};lazyAttributesは、セレクタが最初に導出された後に渡された関数を実行し、スタイルシートを作成するという点でattributesとは異なります。
import { lazyAttributes } from 'effcss';
// declare
type Card = {/* the same */};
// implement
const card = lazyAttributes<Card>(/* the same */);
// the stylesheet has not been created yet
const attrs = card({
card: {
rounded: true
},
w: 's'
});
// the stylesheet has been created
// apply
export const Component = () => {
return <div {...attrs}>
Card
</div>
};customStyles
customStylesは派生セレクタなしでスタイルシートを作成します。
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>
};lazyCustomStyles は、渡された関数を実行し、最初の結果呼び出し後にスタイルシートを作成するという点で customStyles と異なります。
import { lazyCustomStyles } from 'effcss';
// implement
const applyStyles = lazyCustomStyles(/* the same */);
// the stylesheet has not been created yet
applyStyles();
// the stylesheet has been created
// apply
export const Component = () => {
return <div className='custom'>
Card
</div>
};variables
variable は単一の CSS @property ルールを作成し、variables は複数の @property ルールを一度に作成します。
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'
}
};
});グローバル変数の初期値を取得および設定するには、対応するメソッドを使用します。
const offset = variable('10px');
const colors = variable({
primary: {
syntax: 'color',
inherits: false,
initialValue: '#2192a7'
},
secondary: '#425158'
});
offset.set('14px');
colors.primary.set('grey');
colors.secondary.set('green');
const actualOffsetValue = offset.get();
const actualPrimaryColorValue = colors.primary.get();animations
animation は単一の CSS @keyframes ルールを作成し、animations は複数の @keyframes ルールを一度に作成します。
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 は複数の @layer ルールを一度に作成します。
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 は複数の @container ルールを一度に作成します。
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%'
}
},
};
});fonts
font は単一の CSS @font-face ルールを作成し、fonts は複数のルールを一度に作成します。
import { customStyles, font, fonts } from 'effcss';
// global
const single = font({
src: `url("https://mdn.github.io/shared-assets/fonts/FiraSans-Regular.woff2")`,
genericName: 'sans-serif'
});
const multiple = fonts({
primary: {
src: `url("/fonts/roboto-regular.woff2") format("woff2"), url("/fonts/roboto-regular.woff") format("woff")`,
weight: 400,
style: 'normal',
display: 'swap'
},
secondary: {
src: `url("https://mdn.github.io/shared-assets/fonts/FiraSans-Regular.woff2")`
}
});
customStyles(() => {
// local
const localSingle = font(/* the same */);
const localMultiple = fonts(/* the same */);
return {
'.global-font': {
fontFamily: single()
},
'.global-primary-font': {
// `single` as fallback
fontFamily: multiple.primary(single)
},
'.local': {
fontFamily: localSingle()
},
'.local-primary-font': {
// `localSingle` as fallback
fontFamily: localMultiple.primary(localSingle)
}
};
});update
updateはグローバル変数の初期値を更新します。
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'
});可能な限り変数のsetメソッドを使用してください。その方がより明確です。
stylesheet
stylesheetは作成されたスタイルシートを返します。
const custom = customStyles(() => {
return {
'.custom': {
padding: '1rem'
},
};
});
// specified stylesheet
const customStylesheet = stylesheet(custom);特殊なスタイルシートを返すユーティリティもあります。
layersStylesheetはグローバルレイヤーのスタイルシートを返します。variablesStylesheetはグローバル変数のスタイルシートを返します。animationsStylesheetはグローバルアニメーションのスタイルシートを返します。fontsStylesheetはグローバルフォントのスタイルシートを返します。sharedStylesheetはグローバルルールのスタイルシートを返します(classNameとattributeを使用して作成されます)。
configure
configureは、最初のスタイルシートが作成される前に呼び出された場合、スタイル生成に影響を与えます。
configure({
// custom prefix for ids
prefix: 'custom',
// disable minification
minify: false,
// emulate server-side mode
emulate: true
});serialize
serializeは、引数または作成されたすべてのスタイルシートをHTML文字列に変換します。
const custom = customStyles(() => {
return {
'.custom': {
padding: '1rem'
},
};
});
// specified stylesheet
const customHTML = serialize(custom);
// all created stylesheets
const fullHTML = serialize();serializeMeta は、引数のメタデータ、または作成されたすべてのスタイルシートのメタデータを HTML 文字列にシリアル化します。
import { classNames } from 'effcss';
type Card = {/* the same */};
const card = classNames<Card>(/* the same */);
// specified stylesheet metadata
const cardMetaHTML = serializeMeta(card);
// all created stylesheets metadata
const fullMetaHTML = serialize();この方法により、スタイルとメタデータをサーバー側で計算し、クライアント側で再利用することが可能になります。これは特にSSG/SSRにおいて有効です。
subscribe
subscribeを使用すると、EffCSSのスタイル作成イベントをリッスンできます。
import { subscribe, classNames } from 'effcss';
const events = [];
// start listen to events
const unsubscribe = subscribe((event) => events.push(event));
type Card = {/* the same */};
const card = classNames<Card>(/* the same */);
// stop listen to events
unsubscribe();これはきめ細かな制御とデバッグのためのツールなので、本番環境のビルド内では使用しないでください。