https://github.com/luncheon/isaaccss
Inline-Style-as-a-Class CSS engine
https://github.com/luncheon/isaaccss
atomic-css css css-framework css-generator css-in-js css-utilities inline-css inline-styles open-props postcss tailwindcss utility-classes windicss
Last synced: about 1 month ago
JSON representation
Inline-Style-as-a-Class CSS engine
- Host: GitHub
- URL: https://github.com/luncheon/isaaccss
- Owner: luncheon
- License: wtfpl
- Created: 2022-08-23T04:13:20.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2022-09-20T06:16:00.000Z (over 2 years ago)
- Last Synced: 2025-03-13T03:36:40.080Z (2 months ago)
- Topics: atomic-css, css, css-framework, css-generator, css-in-js, css-utilities, inline-css, inline-styles, open-props, postcss, tailwindcss, utility-classes, windicss
- Language: JavaScript
- Homepage: https://luncheon.github.io/isaaccss/playground/
- Size: 6.17 MB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# isaaccss: Inline-Style-as-a-Class CSS engine
An atomic CSS DSL like inline style.
```jsx
import { is } from "isaaccss";const SubmitButton = ({ variant }: { variant: 'primary' | 'secondary' }) => (
=768px/padding:8px_16px @hover:hover/:hover/scale:1.1
`}>
Submit
);
```Or using some short aliases:
```jsx
import { is } from "isaaccss";const SubmitButton = ({ variant }: { variant: 'primary' | 'secondary' }) => (
=768px/p:8px_16px @hover:hover/:hover/scale:1.1
`}>
Submit
);
```[Playground](https://luncheon.github.io/isaaccss/playground/)
## Installation
```
npm i -D isaaccss
```## Usage
Import `is` from `"isaaccss"` and write styles in `is`-tagged template.
```js
import { is } from "isaaccss";document.body.className = is`m:0 @screen&w>=640px/m:1rem`;
```The above code with default config generates the following JS and CSS:
```js
document.body.className = `#a #b`;
``````css
.\#a:not(#\ ) {
margin: 0;
}@media screen and (width>=640px) {
.\#b:not(#\ ) {
margin: 1rem;
}
}
```- `#` of `#a`, `#b`: prefix to avoid conflicts with other libraries and your CSS. Customizable.
- `:not(#\ )`: selector to increase ID-specificity. Ensures greater specificity than other libraries or your CSS.## Syntax
```
[@media/][@^container/][selectors/]property:value[!][;property:value[!]...][?][*[*...]]
~~~~~~~ ~~~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~ ~~~~~ ~ ~~~~~~~~~~~~~~~~~~~~~ ~ ~~~~~~~
(1) (2) (3) (4) (5) (6) (7) (8) (9)
```1. Optional `@media/` indicates [media queries](https://developer.mozilla.org/docs/Web/CSS/Media_Queries/Using_media_queries)
- `@foo/d:none` generates `@media foo { .\#a { display: none } }`
(`.\@foo\/d\:none` is compressed into `.\#a`)
- Tokens are parenthesized where necessary
e.g. `@screen&w>=640px/m:0` -> `@media screen and (width >= 640px) { .\#a { margin: 0 } }`
2. Optional `@^container/` indicates [container queries](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Container_Queries)
- `@^w>=200/m:1rem` generates `@container (w>=200) { .\#a { margin:1rem } }`
- `@^card(w>=200)/m-l:1rem` generates `@container card (w>=200) { .\#a { margin-left: 1rem } }`
3. Optional `selectors/` indicates additional selectors
- [Pseudo-classes](https://developer.mozilla.org/docs/Web/CSS/Pseudo-classes)
e.g. `:hover/`, `:has(>:checked)/`
- [Pseudo-elements](https://developer.mozilla.org/docs/Web/CSS/Pseudo-elements)
e.g. `::before/`, `::part(foo)/`
- [Child combinator](https://developer.mozilla.org/docs/Web/CSS/Child_combinator)
e.g. `>div/`
- [Adjacent sibling combinator](https://developer.mozilla.org/docs/Web/CSS/Adjacent_sibling_combinator)
e.g. `+div/`
- [General sibling combinator](https://developer.mozilla.org/docs/Web/CSS/General_sibling_combinator)
e.g. `~div/`
- Combination of the above
e.g. `:hover>input+label::before/`
- If there are ampersands `&`, they becomes that class
e.g. `&+&/m-l:1rem` -> `.\&\+\& + .\&\+\& { margin-left: 1rem }`
4. Required `property` indicates the property name
- Must be one of the [known properties](https://github.com/known-css/known-css-properties/blob/master/data/all.json) or a [custom property](https://developer.mozilla.org/docs/Web/CSS/--*)
5. Required `value` indicates the property value
- `$bar` will be replaced with `var(--bar)`
- Custom property set libraries, such as [Open Props](https://open-props.style/), can help with design themes
6. Optional `!` indicates [`!important`](https://developer.mozilla.org/en-US/docs/Web/CSS/important)
7. Multiple `property:value[!]` can be specified, delimited by semicolons `;`
8. Optional trailing `?` generates unnamed [`@layer{}`](https://developer.mozilla.org/docs/Web/CSS/@layer)
- For example, add `?` to the components in a component library, so that applications using it can override the properties
9. Optional trailing `*` increases ID-[specificity](https://developer.mozilla.org/docs/Web/CSS/Specificity), more than one can be specified
- For example, add `*` to the preferred style between `:hover` and `:active`- An underscore `_` will be replaced with a whitespace ` ` and can be escaped with a backslash (`\_` will be replaced with `_`)
## Setup
### [esbuild](https://esbuild.github.io/)
```js
import esbuild from "esbuild";
import isaaccss from "isaaccss/esbuild";esbuild.build({
entryPoints: ["src/index.ts"],
outdir: "dist",
bundle: true,
// Inject `isaaccss.inject`.
inject: [isaaccss.inject],
plugins: [
isaaccss.plugin({
// Optional filename filter. Default is following.
filter: /\.[cm][jt]x?$/,// Optional isaaccss config. See `Configuration Example` section below.
pretty: true,
compress: { prefix: "~" },
aliases: [],
postcss: { plugins: [] },
}),
],
});
```### [Rollup](https://rollupjs.org/)
```js
// rollup.config.js
import isaaccss from "isaaccss/rollup";/** @type {import("rollup").RollupOptions} */
export default {
input: "src/index.js",
output: { file: "dist/index.js" },
plugins: [
isaaccss({
// Optional include filter. By default, all bundled scripts are included.
include: ["**/*.js"],// Optional exclude filter. By default, `**/node_modules/**` are excluded.
exclude: ["**/node_modules/**"],// Optional output filename.
// Default is the output script filename with extension ".css".
output: "dist/index.css",// Optional isaaccss config. See `Configuration Example` section below.
pretty: true,
compress: { prefix: "~" },
aliases: [],
postcss: { plugins: [] },
}),
],
};
```When you want to merge other CSS files with isaaccss CSS, use [`rollup-plugin-import-css`](https://github.com/jleeson/rollup-plugin-import-css) instead of [`rollup-plugin-css-only`](https://github.com/thgh/rollup-plugin-css-only).
```js
// rollup.config.js
import css from "rollup-plugin-import-css";
import isaaccss from "isaaccss/rollup";/** @type {import("rollup").RollupOptions} */
export default {
input: "src/index.js",
output: { file: "dist/index.js" },
plugins: [css(), isaaccss()],
};
```### [Vite](https://vitejs.dev/)
Class names are not compressed in Vite dev server, but in Vite build.
```js
// vite.config.js
import isaaccssPlugin from "isaaccss/vite";/** @type {import("vite").UserConfig} */
export default {
plugins: [
isaaccssPlugin({
// Options are same as for Rollup isaaccss plugin above.
}),
],
};
```## Configuration Example
```js
import { defaultAliases } from "isaaccss/aliases";
import OpenProps from "open-props";
import postcssJitProps from "postcss-jit-props";export default {
// Whether to pretty-print. Default is `false`.
pretty: true,// Class name compression setting in boolean or `{ prefix: string }`. Pass `false` to turn off.
// Default is `{ prefix: "#" }`; class names are "#a", "#b", ..., "#aa", "#ab", ...
compress: { prefix: "~" },// Aliases. If specified, the default aliases are removed.
aliases: [
// If you want to extend the default, pass the `defaultAliases` imported from "isaaccss".
defaultAliases,// Custom aliases. For example:
{
// Alias format of `media`, `container` and `selector` is one of the following:
// - { "search": replacementString }
// - [/pattern/g, replacementStringOrFunction]
// - Array of the above
media: {
dark: "prefers-color-scheme:dark",
light: "prefers-color-scheme:light",
sm: "640px", // use breakpoints like `@w{margin:.0625rem} `m-l:[16]`->{margin-left:1rem}
/^margin|^padding|^font-size$/,
[/\[(-?\d*\.?\d+)\]/g, (_, $1) => `${+$1 / 16}rem`.replace(/^0\./, ".")],
],
],
},
],// Optional PostCSS config. The only field is `plugins`.
// Following configuration is an example of using Open Props (e.g. `color:$blue-1`):
postcss: {
plugins: [postcssJitProps(OpenProps)],
},
};
```See [src/aliases/default.ts](https://github.com/luncheon/isaaccss/blob/main/src/aliases/default.ts) for the default aliases.
## Intention
- Like inline styles and other atomic CSS frameworks:
- Predictable changes
- No pondering class names
- Correct separation of concerns: markup and its style are strongly coupled and should be maintained together. Putting them into separate files is a bad idea.
- Unlike inline styles:
- Media queries, container queries and selectors (combinators, pseudo-class, pseudo-elements) can be described
- Specificity can be adjusted
- Short aliases can be used
- [`Content-Security-Policy`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy): no need `'unsafe-inline'` or `'nonce-a682b15c'` for [`style-src`](https://developer.mozilla.org/docs/Web/HTTP/Headers/Content-Security-Policy/style-src)
- Unlike [Tailwind CSS](https://tailwindcss.com/) and [Windi CSS](https://windicss.org/):
- This is a class name description rule, not a predefined property set, therefore:
- Less to remember
- Simple and flexible: any media, any container, any selector, any property and any value can be described as is
- High specificity (ID-specificity = 1) by default to override styles from other CSS libraries
- Specificity can be adjusted
- Class names can be compressed into prefixed short names such as `#a`, `#b`, ..., `#aa`, ...
- Invalid class names can be detected
- Unlike [Linaria](https://linaria.dev/):
- Short aliases can be used
- Atomic styles are reused, preventing CSS file size bloating## License
[WTFPL](http://www.wtfpl.net/)