告别裸色值bg-pink-500:@shadcn/lint的no-raw-colors规则让设计Token落地
【免费下载链接】lintAn agent-first linter for Tailwind design systems. Write design system rules that agents can verify.项目地址: https://gitcode.com/gh_mirrors/lint3/lint
@shadcn/lint是一款面向 Agent 的 Tailwind 设计系统 linter,它的no-raw-colors规则会自动揪出bg-pink-500这类裸色值,并基于你的主题 Token 给出可直接采纳的替换建议——让设计 Token 真正落地,而不是停在文档里。
为什么裸色值是设计系统的"天敌" 🎨
想象一下这个场景:设计稿上明明约定了品牌色,可代码评审时你看到的却是——
<div className="bg-pink-500">Account settings</div>问题不在于 Tailwind 调色板不够用,而在于Tailwind 默认调色板人人可用,没人管。裸色值(raw palette colors)会绕过你精心定义的@themeToken,带来三个后果:
| 问题 | 后果 |
|---|---|
| Token 形同虚设 | 主题文件里的--color-primary没人用,改色要全局搜索替换 |
| 视觉漂移 | 同一产品里pink-500、rose-500、#ec4899混用 |
| Agent 乱写 | AI 写 UI 时倾向直接用text-red-500,不知道你的主题里有destructive |
no-raw-colors就是为此而生的:它要求颜色工具类必须使用你在主题里声明的 Token,其余一律报错,并告诉你要用哪个。
no-raw-colors 能抓 3 类颜色违规 🚨
这条规则不只盯className,覆盖范围如下:
- 裸调色板颜色——
bg-pink-500、text-zinc-100等直接使用 Tailwind 默认色板; - 未声明的伪 Token——
bg-highlight:名字像 Token 但主题里根本没声明,报错时还会提示你是不是拼错了; - SVG 硬编码颜色——
<svg fill="#ec4899" />、stroke="red"这类属性里的字面色值,规则会建议改用currentColor+ 文本颜色类,或var(--color-<token>)。
细节可查阅官方规则文档:docs/rules/no-raw-colors.md,核心逻辑在 packages/lint/src/rules/no-raw-colors.ts。
快速上手:三步启用 no-raw-colors ⚡
以 React + ESLint 为例(Vue、Svelte 配置方式相同,见 docs/vue.md、docs/svelte.md):
第 1 步:安装依赖(需 Node.js 20.19+,兼容 ESLint 与 Oxlint)
npm install -D @shadcn/lint eslint @typescript-eslint/parser第 2 步:在 ESLint 配置中注册插件并开启规则,只有一行:
"shadcn/no-raw-colors": "error"第 3 步:跑一遍npx eslint .。如果不想手写配置,把 SETUP.md 喂给你的编码 Agent 即可,它会自动完成安装与注册。
启用后,写bg-pink-500时会收到类似这样的报错:
"bg-pink-500" uses the raw Tailwind palette. Nearest theme tokens: bg-brand. Use one of those, or declare --color-<name> in app/globals.css for a new color.注意最后半句——错误本身就带解决方案:用哪个 Token、去哪声明新颜色,一次说清。这正是"agent-first"的含义:报错直接给 AI 当修复指令用。
建议是怎么算出来的:OKLab 最近色 🧮
no-raw-colors的智能之处在于"建议"而非"空报"。它的原理(详见 docs/how-it-works.md):
- 从
components.json找到主题 CSS,解析@theme里所有--color-*声明,并跟随@import; - 把 Token 和裸色都解析成真实颜色值,在OKLab 色彩空间里算距离,找出最接近的 Token;
- 命中相近色时,编辑器里直接出现可一键采纳的替换建议,且变体、透明度、important 标记都会保留——
hover:bg-pink-500/50会被安全地替换为hover:bg-brand/50。
换句话说,你写的每个 Token 都会变成规则的知识库,主题越完善,建议越精准。
常用配置:allow、deny 与 contracts 🛠️
现实项目总有例外(比如合作方品牌色)。规则内置了策略三件套:
| 选项 | 作用 | 示例 |
|---|---|---|
allow | 放行匹配的颜色类 | "*-amber-*" |
deny | 从放行中剔除 | "bg-amber-500" |
contracts | 给单个组件开例外 | 只有Badge允许amber-500 |
"shadcn/no-raw-colors": ["error", { allow: ["*-amber-*"], deny: ["bg-amber-500"], }]还可以用message把报错改成团队自己的话术,{{file}}占位符会自动填上你的主题文件路径:
message: 'Use a theme color for "{{className}}". See {{file}}.'完整选项表见 docs/rules.md。
存量项目落地:从 warn 开始的渐进路线 📈
老项目一开error可能被几百条报错淹没。官方推荐的渐进策略(见 docs/adoption.md):
- 先设为
warn,用--max-warnings给总数封顶,CI 里只允许降不允许升; - 修复高频模式(通常是几处反复出现的裸色值);
- 某条规则清零后升级为
error; - 新代码严格、旧代码宽松:对
app/**用error,legacy/**保持warn。
真正的例外(比如"合作方品牌色,设计已批准")用带原因的禁用注释留在代码旁边,rg一下就能审计所有豁免。
小结:让 Token 从文档走进 CI ✅
no-raw-colors的价值不在于"禁掉"bg-pink-500,而在于把你的主题变成了 linter 的判定依据和修复建议来源:
- 裸色值、伪 Token、SVG 硬编码颜色,三类违规一网打尽;
- 建议基于 OKLab 最近色计算,编辑器内一键替换;
- allow / deny / contracts 三级策略,例外写得清清楚楚;
- 报错自带指引,人读得懂,Agent 更读得懂。
设计 Token 落地的最后一块拼图,就是把"约定"变成"检查"。装上这个规则,你的主题文件就再也不会只是摆设。
【免费下载链接】lintAn agent-first linter for Tailwind design systems. Write design system rules that agents can verify.项目地址: https://gitcode.com/gh_mirrors/lint3/lint
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考