@cssints/css-grammar

中文文档
0.35.1发布于 2026/11/07MITTypeScriptES Module构建来源已验证近 30 天下载 1.5万

Type-level and runtime recognizer of CSS values over mdn-data grammars (the engine of cssints)

原始使用文档
文档目录12 节
  1. Install
  2. Frameworks
  3. In a terminal
  4. Debugging
  5. For agents
  6. Layout
  7. Development
  8. Credits
  9. Data and code that ships
  10. Ideas and designs
  11. Built on
  12. License

CSS-in-TS

cssints is compile-time CSS-in-TypeScript. You write calls such as css.flex().alignItems("center"). A Vite plugin runs them at build time and replaces each one with atomic, content-hashed class names in @layers. Nothing of the styling code ships to the browser except a few lines that join class names: for a cn() with runtime arguments and for cv/scv.

  • Values are checked against the spec grammars (mdn-data) in the types and again at build time. A typo is an error in the editor and in the build.
  • Conditions (media, container, supports, hover), variants (cv, scv), design tokens and themes (createTokens, createGlobalTheme, check.contrast) are all build-time, and all typed.
  • LightningCSS optimizes the output. Browser support (@mdn/browser-compat-data against your browserslist) is reported as warnings, except for what LightningCSS lowers for those targets.

Alpha. cssints is on npm at 0.x. The API can still change between minor versions, the plugin packages may move, and some browsers and frameworks are checked less than others (docs/API.md, "Browser support and what 0.1 does not have"). Pin the version, and report what breaks.

Decisions and findings are in docs/wayfinder.md; the API reference is docs/API.md. Both are also a site with search and type hovers: apps/docs (cd apps/docs && bun run dev); deployed to Cloudflare with Alchemy: https://cssints.dev.

Install

npm install --save-dev cssints vite@8   # or: bun add -d cssints vite@8, pnpm add -D cssints vite@8

cssints needs Vite 8 (Vite+ works too) and Node 22.18 or later (the plugin runs your modules with type stripping). It is a dev dependency: nothing of it ships except the few lines behind cn with runtime arguments and cv. The plugin packages are installed the same way, each beside cssints (npm install --save-dev @cssints/fluid); the list is on the plugin packages page. In this repository cssints is a workspace package ("cssints": "workspace:*").

// vite.config.ts
import cssints, { cssTarget, targets } from "cssints/vite";

export default {
  plugins: [cssints()],
  css: { transformer: "lightningcss", lightningcss: { targets } },
  build: { cssMinify: "lightningcss", cssTarget },
};
// the entry, once
import "virtual:cssints.css";
import { reset } from "@cssints/reset" with { type: "cssints" };

reset();

reset() is the recommended start: @cssints/reset is a small modern reset in a layer below every style, so any style of yours beats it. A project without the call has none, as in any app.

targets and cssTarget come from the browserslist query of the support warnings: the BROWSERSLIST variable, else the standard config ("browserslist" in package.json or .browserslistrc, with the BROWSERSLIST_ENV, NODE_ENV or production section), else defaults. The exports are computed when vite.config.ts is imported, before Vite's root is known, so they look the config up from process.cwd() and upward; the support warnings look it up from Vite's root (2026-10-09, cssints-p3d2). They are the same when Vite runs from the app's directory; with vite <dir> from elsewhere, give targets and cssTarget the app's config yourself. Vite's CSS minify reads cssTarget, not targets: without it the minifier merges the declarations of a firstThatWorks into the last one. Add "types": ["vite/client"] to tsconfig.json for the virtual: import.

Frameworks

Any framework that builds JSX through a Vite plugin works; the engine evaluates your modules itself, so it does not care what the plugin makes of JSX, nor in which order the plugins are listed. apps/csssky is the Solid 2 app (solid-js and @solidjs/web 2.0.0-rc.13, @solidjs/vite-plugin 3.0.0-next.47):

// vite.config.ts
import solid from "@solidjs/vite-plugin";
import cssints, { cssTarget, targets } from "cssints/vite";

export default {
  plugins: [cssints(), solid()],
  css: { transformer: "lightningcss", lightningcss: { targets } },
  build: { cssMinify: "lightningcss", cssTarget },
};

tsconfig.json is Solid's: "jsx": "preserve", "jsxImportSource": "@solidjs/web", "types": ["vite/client"]. Solid's class takes a string, an object or an array, so cn is not needed for the join: class={[card, on() && p(4)]} and class={badge({ tone: tone() })} work as in React. A site's arguments are still build-time values, so a signal goes in the condition or in a cv variant, not in p(n()). Under vite dev an edit of a component replaces it and resets its state below it (Solid's refresh); an edit of a style changes the class strings and the sheet with no reload.

import { reset } from "@cssints/reset" with { type: "cssints" };
import {
  bg,
  color,
  cn,
  cv,
  flex,
  hover,
  media,
  p,
  style,
  token,
} from "cssints" with { type: "cssints" };

reset();

const md = media("(width >= 40rem)");
const accent = token.color("#2563eb", "accent");

const button = cv({
  base: cn(p(2), color("white"), bg(accent), hover(bg("#1d4ed8"))),
  variants: { wide: { true: md(p(4)) } },
});

export const Row = ({ wide, on }: { wide?: boolean; on?: boolean }) => (
  <div
    className={cn(flex().alignItems("center").gap(2), on && p(1))}
    style={style(token.set(accent, "#dc2626"))}
  >
    <button className={button({ wide })}>Save</button>
  </div>
);

with { type: "cssints" } marks what runs at build time. The plugin replaces each call with a class string, so the browser gets __cx([], "_1s47490 _1ob5z5m _g2iyum", on && "_lqk467") and button is a call of the runtime with { base: "_1t8gqy5 ...", ... }, so it never sees flex(). virtual:cssints.css is one sheet with every rule once, sorted by layer, then condition, then shorthand before longhand, then class name (the @layer reset { ... } block of reset() comes first and is left out here):

@layer _.k, _.a, _.b, _.c, _.d, _.e;
@property --accent {
  syntax: "<color>";
  inherits: true;
  initial-value: #2563eb;
}
@layer _.a {
  ._1t8gqy5 {
    padding: 0.5rem;
  }
  ._lqk467 {
    padding: 0.25rem;
  }
  ._g2iyum {
    gap: 0.5rem;
  }
  ._17xzvrh {
    background-color: var(--accent);
  }
  ._1binn6n {
    color: white;
  }
  ._1ob5z5m {
    align-items: center;
  }
  ._1s47490 {
    display: flex;
  }
}
@layer _.b {
  ._1tsjws2:hover {
    background-color: #1d4ed8;
  }
  @media (width >= 40rem) {
    ._tdcza3 {
      padding: 1rem;
    }
  }
}

In a terminal

import * as css from "cssints/tui" with { type: "cssints" } gives the members a terminal has (cells, colours, borders, flex, states, cursor), and the plugin compiles them to prop objects for OpenTUI renderables instead of classes; @cssints/tui applies their states and themes: packages/tui, docs/API.md "TUI". The package to apply them, @cssints/tui, is deprecated in favour of the terminal target in native/terminal (Clay in cells, termbox2); its README says what carries over and how to run the replacement.

More in docs/API.md: property names and short names, flex() and grid() chains, conditions and layers, tokens and themes, cn and cv, and the errors you can get.

Debugging

CSSINTS_TRACE=otlp bun run build (or dev) sends a trace of every Vite hook, with the file of each module, to a local OpenTelemetry backend; unset, it costs nothing. How to start the backend in one docker run, and the spans: docs/API.md.

For agents

cssints ships two agent skills in its package, skills/cssints (writing styles: setup, cn/cv, conditions, tokens and themes, the plugin packages, build errors) and skills/cssints-plugin (writing a plugin on scope(), with its tests). Install them into your agent's skills folder:

npx skills-npm                                # links the skills of every installed package that ships some
npx skills add ./node_modules/cssints/skills  # or the skills CLI, for opencode, Claude Code, Codex, Cursor, ...

Agents working on this repository get .agents/skills/cssints-contributor (also .claude/skills) with no install.

@cssints/mcp is an MCP server with the build's own checks (check_declaration, check_support, check_contrast, compile, search_docs, list_plugins), in packages/mcp with the config for opencode, Claude Code and Cursor. The skills use it when it is configured and work without it.

Layout

PathWhat
packages/cssintsVite plugin (cssints/vite) on the Vite Module Runner, and the cssints library
packages/css-grammarType-level recognizer and its runtime twin over mdn-data grammars, Typed OM values, browser support and prose rules
packages/icons@cssints/icons: icons from iconify JSON collections or SVG folders, a mask style with no runtime
packages/mise-en-mode@cssints/mise-en-mode: looks as themes in the layers app < author < viewer, on data-mode scopes, checked against the tokens and by check.contrast
packages/headless@cssints/headless: headless APG widgets on Solid 2 (state and DOM attribute objects, no styling), conformance-checked against Quint specs; not published yet
packages/apg-specs@cssints/apg-specs: the APG and canvas Quint specs, generated models, scenario bridges and ported scenarios the widgets are tested against (the test oracle, published)
packages/tui@cssints/tui (deprecated): the runtime of cssints/tui styles on OpenTUI and @bomb.sh/tty; native/terminal replaces it
apps/demoReact demo of every 0.1 feature
apps/docsThe documentation site: this file and docs/API.md as pages, with search and type hovers (cd apps/docs && bun run dev)
docs/research, docs/archiveComparisons with other libraries; outdated plans

Development

bun install
bun run test    # all packages (vp run -r test, cached where possible); includes the type-check of the code in docs/API.md and this file
bun run bench   # type instantiation budgets (tsc and tsgo)
bun run check   # format, lint, type-check (vp check), then tsc 7 with the Effect diagnostics (bun run typecheck)
bun run diff:check   # the added lines against master: anti-slop rules, key-file changes (tools/ai-automation)
cd apps/demo && bun run dev
cd apps/docs && bun run dev   # the documentation site, on the pages of README.md and docs/API.md

See AGENTS.md for the layout, commands and code style.

Credits

cssints is MIT. It stands on other people's work; this is what we took, from whom, and under which license. A package that copies data or code carries the upstream notice (a Credits or Licenses section of its README, or THIRD_PARTY_NOTICES.md).

Data and code that ships

WhereWhatFromLicense
@cssints/tokensthe Open Props, Radix Colors, Flexoki and Reasonable Colors setsOpen Props (Adam Argyle), Radix Colors, Flexoki (Steph Ango), Reasonable Colors (Matthew Howell)MIT, notices in its README
@cssints/css-grammarthe CSS syntax strings (src/mdn.ts, keywords.ts, functions.ts), also in the types of cssintsmdn-data; the numeric ranges it omits from @webref/cssCC0-1.0; MIT (W3C)
@cssints/css-grammarbrowser support warnings, read from the package (not copied)@mdn/browser-compat-dataCC0-1.0
@cssints/fontsthe latin character weights and the metrics of Arial, Times New Roman and Courier NewCapsize (SEEK)MIT, notice in its README
@cssints/iconsnothing: the collections are your dependencyIconify @iconify-json/*each collection's own
tools/ai-automation/vendorlint rules, not publisheddmmulroy/anti-slop (Dillon Mulroy)MIT, LICENSE and UPSTREAM.md
apps/cssskylayout and token values; Inter; Phosphor iconsMu and @bsky.app/alf (Bluesky Social PBC), Inter, PhosphorMIT; OFL-1.1; MIT
apps/demoMaterial Design Icons (@iconify-json/mdi)PictogrammersApache-2.0

Ideas and designs

No code is copied from these; each package README says which part follows which.

Built on

Effect, Vite and Vite+, OXC, LightningCSS (MPL-2.0; its wasm build runs in the playground), culori, TypeScript and TypeScript Go, Bun, Solid, OpenTUI, Shiki, Pierre's highlights, Monaco Editor, Playwright, fast-check, Quint, atcute, and Beans for the tickets. Phosphor icons (MIT) are on this site through @iconify-json/ph. Every dependency keeps its own license; none is copied into the repository.

License

MIT

版本与发布记录

@cssints/css-grammar 共发布 43 个版本,首次发布于 2026/10/11;过去 12 个月发布了 43 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.35.1latest2026/11/073 天前
0.35.02026/11/073 天前
0.34.02026/11/073 天前
0.33.02026/11/046 天前
0.32.02026/11/046 天前
0.31.02026/11/047 天前

关于 @cssints/css-grammar 的常见问题

@cssints/css-grammar 是什么?

Type-level and runtime recognizer of CSS values over mdn-data grammars (the engine of cssints)

如何安装 @cssints/css-grammar?

在项目目录运行 npm install @cssints/css-grammar,或使用 pnpm add / yarn add / bun add。

@cssints/css-grammar 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@cssints/css-grammar 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@cssints/css-grammar 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@cssints/css-grammar 可以商用吗?

@cssints/css-grammar 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@cssints/css-grammar 的下载量有多少?

根据 npm 官方下载统计,@cssints/css-grammar 在 2026/10/11 – 2026/11/09 这 30 天内被下载 14,906 次,日均约 497 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cssints/css-grammar 还在维护吗?

最新版本 0.35.1 发布于 2026/11/07(3 天前);至今共发布 43 个版本,其中过去 12 个月发布了 43 个;首次发布于 2026/10/11。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。