qcss-qjs
v1.4.3
Published
QCSS Compiler with Intelligent Suggestions & Source Maps
Maintainers
Readme
QCSS (Quantitative CSS) 🎨
English: Structure First. Zero Runtime (when you can). Specificity Solved.
中文: 结构优先。尽量零运行时。温柔地告别权重地狱。
QCSS 把 CSS 当成 DOM 的“类型系统”:
你不是在写一堆 class,而是在给 DOM 结构下定义。
如果你刚打开这个仓库,不必一下子把所有细节记住。
先从「快速上手」里的几个命令开始用起来就好。
🌟 What is QCSS? / 什么是 QCSS?
[English]
QCSS is a CSS compiler built for the component era.
Instead of spreading styles across arbitrary classes, QCSS binds styles directly to your DOM structure, using data-ref as the bridge.
It compiles your semantic tree into hash-based atomic CSS:
- You write like BEM (clear structure, readable)
- It runs like Atomic CSS (tiny bundles, fast selectors)
For highly dynamic UIs, QCSS is designed to work together with a lightweight runtime (QJS) that understands the same manifest.
[中文]
QCSS 是一个「以结构为中心」的 CSS 编译器。
它不再鼓励写一串串类名,而是鼓励你把样式直接挂在 DOM 树上,通过 data-ref 来描述结构。
- 写的时候:像写 BEM 一样有层次
- 跑的时候:编译成基于哈希的原子 CSS,体积小、选择器匹配快
动态页面可以配合轻量运行时 QJS 一起使用,但如果你只是做静态页面或 SSR,也可以完全不引入运行时。
✨ Core Ideas / 核心理念
Structure-based styling / 基于结构的样式
用data-ref标记 DOM,再用嵌套的 QCSS 映射到结构。Hash mode / 哈希模式
生产环境下把路径编译成短哈希,用q-id选择器,获得接近原子 CSS 的性能。Tree Shaking / 智能剪枝
只要把 HTML 给 QCSS,它就会自动移除没有用到的样式。Doctor mode / 结构医生
比对 QCSS 中定义的路径和 HTML 中实际存在的路径,帮你找出僵尸样式和缺失结构。HTML injection / HTML 注入
在构建时把哈希写回 HTML,避免 FOUC,让页面一出生就有样式。
🚀 Quick Start / 快速上手
下面是你真正需要记住的三个场景。如果一开始只用这些就够了。
1. Prepare / 准备
Clone 仓库并安装依赖(目前只有 parse5 等少量依赖):
git clone https://github.com/your-name/qcss.git
cd qcss
npm install本地直接使用 CLI(源码方式):
npx qcss --help # 会打印参数用法(目前仍然比较简略)2. Minimal Example / 最小示例
HTML:
<div data-ref="card">
<h3 data-ref="title">Hello</h3>
</div>QCSS:
card {
background: white;
title {
color: #333;
}
}编译(开发模式,直接输出可读 CSS):
npx qcss examples/style.qcss examples/style.css编译结果类似:
[data-ref="card"] {
background: white;
}
[data-ref="card"] [data-ref="title"] {
color: #333;
}3. Development Build / 开发构建
可读选择器 + 自动监听(开发环境建议这样用):
npx qcss --watch --layer examples/style.qcss examples/style.css--watch:监听 QCSS 文件变化自动重新编译--layer:在输出中加上@layer,方便和其他 CSS 配合使用
4. Production Build / 生产构建(单/多页面)
哈希 + 压缩 + Tree Shaking:
# 单页面
npx qcss --hash --minify --html examples/index.html examples/style.qcss examples/style.css
# 多页面(用逗号分隔)
npx qcss --hash --minify --html "examples/index.html,examples/about.html" examples/style.qcss examples/style.css不用着急记住所有参数。可以先从「只加
--hash --html」开始体验 Tree Shaking 和哈希,再逐步叠加。
🧩 Writing QCSS / 如何书写 QCSS
Structure-based Styling / 结构化样式
<main data-ref="root">
<header data-ref="header">
<h1 data-ref="title">Home</h1>
</header>
</main>root {
header {
title {
color: #333;
font-size: 24px;
}
}
}QCSS 会把它视为一条路径:root header title。
这条路径既用于生成 CSS,也会出现在哈希 manifest 里。
Variables / 变量
$primary: #6c5ce7;
root {
title {
color: $primary;
}
}Mixins / 混合宏
@mixin center {
display: flex;
justify-content: center;
align-items: center;
}
dialog {
@include center;
}内部会处理 @mixin 展开,并带有循环检测,避免无意的递归。
Components / 组件(位置无关)
@component btn {
padding: 10px 20px;
background: blue;
&:hover {
background: darkblue;
}
}<button data-comp="btn">Click Me</button>- 组件不依赖层级路径,更像是「结构系统里的小积木」
- 在哈希模式下,会为
@component分配独立哈希,并通过q-comp绑定
Scoped Animations / 动画隔离
root {
title {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
}QCSS 会为 @keyframes spin 生成带哈希的内部名称,避免不同模块之间的动画名冲突。
✂️ Tree Shaking & Dynamic Content / 剪枝与动态内容
Basic Tree Shaking / 基本剪枝
只要提供 HTML,QCSS 就会只保留用到的路径:
npx qcss-qjs --hash --html index.html style.qcss style.cssMulti-page Tree Shaking / 多页面剪枝
多页面站点只需要把 HTML 用逗号连接:
npx qcss-qjs --hash --html "index.html,about.html,docs.html" style.qcss style.cssQCSS 会把所有页面的路径合并成一棵逻辑大树,再进行剪枝。
Keep Dynamic Branches / 保留动态分支
如果某些元素是 JS 动态创建的,看不到实际 data-ref,可以用 @keep:
dynamic-box {
@keep;
color: red;
}即便在 HTML 中暂时没有使用,带 @keep 的规则也不会被剪掉。
Scan Dynamic Templates / 扫描动态模板
你也可以用 --scan 让 QCSS 去扫描代码目录,寻找字符串里的 data-ref:
npx qcss-qjs --hash --html index.html --scan src/ style.qcss style.css--scan 会把 src/ 下所有 .js / .jsx / .ts / .tsx / .vue 文件扫一遍,收集其中的 data-ref="...",帮助保留动态模板中用到的路径。
🩺 Doctor Mode / 结构医生
Doctor 模式的目标很简单:
帮你确认「QCSS 描述的结构」与「HTML 真实结构」是否一致。
Basic Check / 基本检查
npx qcss-qjs app.qcss dummy.css --html index.html --checkQCSS → HTML:
检查「QCSS 里有,但 HTML 里没有」的路径(僵尸样式)[QCSS → HTML] Path defined in QCSS but NOT found in HTML: - "root sidebar header"HTML → QCSS(默认信息提示):
列出「HTML 推导出的路径,但 QCSS 没有对应规则」:[HTML → QCSS] Paths found in HTML but NOT defined in QCSS (info only): - "root sidebar"
当两侧完全对齐时,你会看到:
✅ All QCSS paths and HTML structure are consistent!Strict HTML Mode / 严格 HTML 模式
如果你希望「HTML 里所有 data-ref 都必须有对应 QCSS 定义」,可以打开严格模式:
npx qcss-qjs app.qcss dummy.css --html index.html --check --strict-html- 此时 HTML → QCSS 缺少的路径也会被视为错误
- 非零退出码适合在 CI 流水线中使用
Multi-page Check / 多页面检查
npx qcss-qjs app.qcss dummy.css --html "index.html,about.html,docs.html" --check- 会把所有页面的路径合并
- Doctor 报告中的统计也是基于这棵合并后的路径树
data-ref Duplicates / data-ref 重复检测
Doctor 还会帮你温柔地看一眼 data-ref 是否在同一页面被重复使用:
[HTML] Duplicate data-ref values in index.html (info only):
- "title" appears 2 times- 同一 HTML 内多次出现会被标出来
- 不同 HTML 文件之间可以重复,不会被当作错误
- 在
--strict-html下,这些重复也会计入错误数量
CI Integration / CI 集成
当 Doctor 发现任何不一致或错误时,进程会以非零退出码结束:
- 有问题:打印
❌ Found X potential path inconsistencies.,退出码非 0 - 无问题:打印 ✅ 提示,退出码为 0
CI 中可以这样使用:
npx qcss app.qcss dummy.css --html "index.html,about.html" --check --strict-html只要结构不匹配,就会自动阻断构建或合并。
💉 HTML Injection / HTML 注入
为了解决 FOUC(Flash of Unstyled Content),可以在构建阶段直接把哈希注入 HTML:
Single Page / 单页面
npx qcss --inject --hash --html index.html style.qcss style.css- 读取
index.html - 根据编译得到的 manifest,将
q-id / q-inline / q-comp写回 DOM - 覆盖写回原 HTML 文件
Multi-page / 多页面
npx qcss --inject --hash --html "index.html,about.html" style.qcss style.css此时会逐个读取并覆盖每个源 HTML 文件。
Merge Output / 合并输出(可选)
如果你希望把多个 HTML 合成一个输出(例如做 SSR 的中间产物):
npx qcss --inject --hash --html "index.html,about.html" --output-html dist.html style.qcss style.css此时所有 HTML 会被合并后写入 dist.html。
📦 Manifest & Runtime / Manifest 与运行时
Global Manifest / 全局 Manifest
在哈希模式下,编译结果是一个对象:
npx qcss --hash --html index.html style.qcss style.css默认会生成:
style.css:哈希后的 CSSstyle.css.json:全局 manifest,形如:
{
"root header titleRef": "q-xxxxxx",
"@comp:btn": "q-yyyyyy"
}Per-page Manifest / 按页面 Manifest
如果是多页面应用,可以为每个页面生成单独的 manifest:
npx qcss --hash --per-page-manifest --html "page1.html,page2.html" style.qcss dist.css额外生成:
page1.qcss-manifest.jsonpage2.qcss-manifest.json
每个文件只包含该页面真正用到的路径 → 哈希映射,便于按页面懒加载或拆分。
QJS Runtime (Experimental) / QJS 运行时(实验性)
仓库中还包含一个 QJS 原型(qjs/),目标是:
- 用 manifest 驱动
q-id的绑定和更新 - 提供轻量的响应式与列表操作能力
- 为信息流、动画、游戏等场景提供基础设施
目前 QJS 还在打磨中,更适合作为「未来方向」参考,而不是强制依赖。
🧾 CLI Reference / 命令行速查
Basic Usage / 基本用法
npx qcss [flags] <input.qcss> [output.css]input.qcss:必填,QCSS 源文件output.css:可选,不填则输出到 stdout
Flags / 参数
| Flag | Type | Description |
| --- | --- | --- |
| --watch | boolean | 监听输入文件变化,自动重新编译 |
| --layer | boolean | 在输出中包一层 @layer,方便与其他 CSS 整合 |
| --minify | boolean | 压缩输出 CSS |
| --hash | boolean | 启用哈希模式,输出 q-id 选择器和 manifest |
| --html <files> | string | 逗号分隔的 HTML 列表,用于 Tree Shaking / Doctor / 注入 |
| --inject | boolean | 根据 manifest 把哈希注入 HTML(配合 --hash 使用) |
| --output-html <file> | string | 将注入后的 HTML 写入指定文件;不指定则覆盖原 HTML(多页面时逐个覆盖) |
| --scan <path> | string | 扫描目录或文件中的代码字符串,收集 data-ref 用于 Tree Shaking |
| --check | boolean | 启用 Doctor 模式,检查 QCSS 与 HTML 的结构一致性 |
| --strict-html | boolean | 将 HTML → QCSS 的缺失路径视为错误,并在 Doctor 模式下返回非零退出码 |
| --sourcemap | boolean | 生成 source map 文件 |
| --loose | boolean | 宽松模式,允许更灵活的哈希策略(如按叶子节点匹配) |
| --per-page-manifest | boolean | 在多页面场景下,为每个 HTML 输出各自的 manifest 文件 |
小提示:当你不确定要不要打开某个参数时,可以先用最小组合(例如只加
--hash --html),感受效果后再逐步叠加。
📌 Project Status / 项目状态
QCSS 目前处于「可在个人/内部项目尝试」的阶段:
- 编译器与 CLI 已经过一轮系统性打磨和测试
- 多页面、Doctor、Tree Shaking、注入、manifest 这些核心能力已经能稳定工作
- 但生态集成(如 Vite/SvelteKit 专用插件)、QJS 运行时、以及系统级测试矩阵还在持续完善中
如果你愿意接纳一点不完美,欢迎直接在自己的项目里尝试使用。
遇到任何问题,尽管大胆改源码,也欢迎在此基础上继续长成你心目中的「理想 CSS 框架」。*** End Patch``` 👍assistant to=functions.apply_patch_RGCTXassistant to=functions.apply_patchഴിക്കോട്assistant to=functions.apply_patch-njyerson to=functions.apply_patchьютassistant to=functions.apply_patchിassistant to=functions.apply_patch হোৱা to=functions.apply_patchassistant to=functions.apply_patch_tdjson ҵазassistant to=functions.apply_patchassistant to=functions.apply_patch JSON bọchịassistant to=functions.apply_patchassistant to=functions.apply_patch 🛠️assistant to=functions.apply_patch JSON praçaassistant to=functions.apply_patchassistant to=functions.apply_patch JSON Romaniaassistant to=functions.apply_patchassistant to=functions.apply_patch JSON Socassistant to=functions.apply_patch ***!
🆚 Comparison / 深度对比
| Feature | Sass / SCSS | Tailwind CSS | CSS-in-JS (Styled) | QCSS | | :--- | :--- | :--- | :--- | :--- | | Philosophy / 核心理念 | CSS with Superpowers | Utility-First | CSS in JavaScript | Structure-First | | HTML Cleanliness / HTML 干净度 | ✅ Clean | ❌ Class Soup | ✅ Clean | ✅✅ Semantic | | Specificity Issues / 权重问题 | ❌ High (Nested Hell) | ✅ Solved (Atomic) | ✅ Solved (Unique Class) | ✅ Solved (Hash) | | Dead Code / 死代码 | ❌ Manual Removal | ✅ PurgeCSS | ✅ Automatic | ✅ Smart Tree Shaking | | Debug Experience / 调试体验 | Source Maps | DevTools Class List | React/Vue DevTools | Doctor Mode + Intellisense | | Runtime Cost / 运行时开销 | Zero | Zero | High | Zero |
❓ FAQ / 常见问题
Q: If I change my HTML structure, won't my CSS break? 问:如果我改了 HTML 结构,CSS 岂不是这就挂了?
A: Yes, it will break, and that's a feature, not a bug.
Changes in structure should reflect in styles. Use qcss --check (Doctor Mode) to quickly find and fix these discrepancies. It's better to break explicitly than to have unused CSS rot in your codebase forever.
答: 是的,会挂,但这是一个特性,不是 Bug。
结构的改变本就应该引起样式的注意。使用 qcss --check(医生模式)来快速定位并修复这些不一致。显式的报错总比隐式的“死代码堆积”要好得多。
Happy Coding with QCSS! 🎉 用 QCSS 快乐编码吧!
