3 дня назад
История
README.md
EffCSS
EffCSS is a self-confident CSS-in-TS library based only on the browser APIs. Use the full power of JS and TS to create styles.
Some features
- zero-dependency,
- framework agnostic,
- small bundle size,
- lazy mode support,
- selectors isolation and minification out of the box,
- TypeScript contract-based autocompletion,
- compatible with any rendering (CSR, SSR, SSG).
Links
- Docs
- SourceCraft
- GitHub
- NPM
- vite-plugin-effcss - CSR tool injecting generated CSS into HTML. It allows to eliminate FOUC and speed up the first rendering due to style hydration just like for SSR/SSG.
Examples
Installation
Type in your terminal:
# npm
npm i effcss
# pnpm
pnpm add effcss
# yarn
yarn add effcss
CSS types & TS autocompletion
By default EffCSS is permissive: styles accept any object. To enable strict CSS-typing (autocompletion + validation of invalid values), define EffCSS.Properties once in your project via global namespace augmentation.
For example, you can install csstype
npm i -D csstype
Then combine with EffCSS
// env.d.ts
import type { Properties as CSSProperties } from 'csstype';
declare global {
namespace EffCSS {
interface Properties extends CSSProperties {}
}
}
export {};
Now every style rule gets full TS autocompletion for CSS properties.
Usage
Just declare stylesheet contract, implement it and apply ready selectors:
App.tsx
import { className, classNames, attribute, attributes, variable, variables, animation, animations } from 'effcss';
// you can create independent rules
// returns classname string
const bgCls = className({
background: 'white',
'&:hover': {
borderRadius: '1em'
}
});
// returns object with data-attribute
const fontAttr = attribute({
fontWeight: 'bold'
});
// single global variable
// shadowColor() => var(--unique-variable-name)
const shadowColor = variable('#58666d');
// multiple global variables
// widthVars.s() => var(--unique-variable-name)
const widthVars = variables({
s: '12px',
m: '16px',
l: '20px'
});
// single global animation
// spinAnimation = unique-animation-name
const spinAnimation = animation({
from: {
transform: 'rotate(0deg)'
},
to: {
transform: 'rotate(360deg)'
}
});
// also you can create isolated stylesheets
// 1. declare
/** 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;
};
// 2. implement
// creates a stylesheet with attribute selectors
// styleComponents({rounded: true}) => {[data-unique-key]: 'some values'}
const styleComponents = attributes<Components>((selectors) => {
const { rounded, card, spinner } = selectors;
// multiple local variables
const colors = variables({
primary: {
inherits: false,
initialValue: '#2192a7'
},
secondary: {
inherits: false,
initialValue: '#425158'
}
});
return {
[rounded.true]: {
borderRadius: '50%'
},
[spinner]: {
animation: `${spinAnimation} infinite 6s linear`
},
[card]: {
display: 'flex',
justifyContent: 'center',
'&:hover': {
filter: `drop-shadow(0 0 2em ${shadowColor()})`
}
},
[card.bg.primary]: {
background: colors.primary()
},
[card.bg.secondary]: {
// with fallback value
background: colors.secondary('cyan')
},
'@media(prefers-color-scheme: dark)': {
[card + ':hover']: {
filter: `drop-shadow(0 0 2em #ffffff)`
}
}
// ... and so on
};
});
// creates a stylesheet with class selectors
// styleUtils({w: 's'}) => 'string with classnames'
const styleUtils = classNames<Utils>((selectors) => {
const { w, spacing, blink } = selectors;
// local animations
const blinkAnimations = animations({
simple: {
'50%': {
visibility: 'hidden'
}
},
smooth: {
'0%': {
opacity: 1
},
'50%': {
opacity: 0
},
'100%': {
opacity: 1
}
}
});
return {
[blink.true]: {
animation: `${blinkAnimations.smooth} 2s infinite`
},
[w.s]: {
width: widthVars.s()
},
[w.m]: {
width: widthVars.m()
}
// ... and so on
};
});
// 3. apply
// returns an object as it is created using `attributes`
const cardAttrs = styleComponents({
card: {
bg: 'primary',
disabled: true
}
});
// returns a string as it is created using `classNames`
const utilsCls = styleUtils({
w: 'm'
});
export const App = () => {
return (
<div {...cardAttrs} className={utilsCls}>
<p {...fontAttr} className={bgCls}>
...
</p>
</div>
);
};
That’s all. Enjoy simplicity.
Описание
Self-confident CSS-in-JS
Конвейеры
0
успешных
0
с ошибкой