开始 · START
快速接入 Quickstart
三种接法:只要样式(任何技术栈)、直接用 React 组件、或者把地址交给 Agent。先读完这页的四条前提,能省掉九成的对不上。
先读:四条前提
✓ 要根节点加
class="zzm-v4"——全部样式只在这个作用域里生效✓ 要用系统字体,不引入网络字体;中文靠 PingFang SC,Windows 落到微软雅黑
✓ 要只有浅色:v4 已废除暗色分支,界面永远是纸白底
✓ 要不需要 Tailwind:zzm.css 自带组件依赖的那部分基线(box-sizing、零外距等)
一、只要样式(任何技术栈)
引入一个 CSS 文件,用类名写 HTML。Vue、Svelte、纯静态页、服务端模板都一样。
index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://ui.zhaozimin.com/zzm.css">
</head>
<body class="zzm-v4">
<button class="zzm-btn">纸键</button>
<button class="zzm-btn zzm-btn--primary">墨键 · 主操作</button>
<button class="zzm-btn zzm-btn--accent zzm-btn--lg">朱键 · 大</button>
</body>
</html>不方便给根节点加类名时,改用 https://ui.zhaozimin.com/zzm.global.css:同样的规则,去掉了 .zzm-v4 前缀,对整页生效。
订阅更新
新课上线时发一封邮件,不发别的。
export function StaticPage() {
return (
<div className="zzm-card" style={{ width: 360, maxWidth: '100%', padding: 24, display: 'grid', gap: 16 }}>
<div style={{ display: 'grid', gap: 4 }}>
<div style={{ fontSize: 16, fontWeight: 650, lineHeight: '24px' }}>订阅更新</div>
<div style={{ fontSize: 13, lineHeight: '20px', color: '#72726E' }}>新课上线时发一封邮件,不发别的。</div>
</div>
<input className="zzm-input" type="email" placeholder="you@example.com" aria-label="邮箱" style={{
height: 36, borderRadius: 8, border: '1px solid rgba(0,0,0,.14)', padding: '0 12px', fontSize: 12.5, outline: 'none',
}} />
<div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
<button type="button" className="zzm-btn zzm-btn--ghost">以后再说</button>
<button type="button" className="zzm-btn zzm-btn--primary">订阅</button>
</div>
</div>
)
}<div
class="zzm-card"
style="width: 360px; max-width: 100%; padding: 24px; display: grid; gap: 16px"
>
<div style="display: grid; gap: 4px">
<div style="font-size: 16px; font-weight: 650; line-height: 24px">订阅更新</div>
<div style="font-size: 13px; line-height: 20px; color: #72726e">
新课上线时发一封邮件,不发别的。
</div>
</div>
<input
class="zzm-input"
type="email"
placeholder="you@example.com"
aria-label="邮箱"
style="
height: 36px;
border-radius: 8px;
border: 1px solid rgba(0, 0, 0, 0.14);
padding: 0 12px;
font-size: 12.5px;
outline: none;
"
/>
<div style="display: flex; gap: 8px; justify-content: flex-end">
<button type="button" class="zzm-btn zzm-btn--ghost">以后再说</button>
<button type="button" class="zzm-btn zzm-btn--primary">订阅</button>
</div>
</div>/* base.css */
.zzm-v4 input.zzm-input:focus, .zzm-v4 textarea.zzm-input:focus { border-color: #161616 !important; }
/* controls.css */
.zzm-v4 .zzm-btn {
-webkit-appearance: none;
appearance: none;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
height: 36px;
padding: 0 16px;
font-family: inherit;
font-size: 13px;
font-weight: 600;
letter-spacing: .2px;
white-space: nowrap;
cursor: pointer;
user-select: none;
border-radius: 8px; /* 圆角矩形——按钮禁胶囊 */
border: 1px solid rgba(0, 0, 0, .14);
color: #3F3F3B;
background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
box-shadow:
0 0 0 3px rgba(255, 255, 255, .55), /* ④ 反光光晕环 */
0 1px 2px rgba(0, 0, 0, .09), /* ③ 近影 */
0 2px 6px rgba(0, 0, 0, .06), /* ③ 远影 */
inset 0 1px 0 rgba(255, 255, 255, .92), /* ② 顶部反光 */
inset 0 -1px 0 rgba(0, 0, 0, .05); /* ① 底缘收沉 */
transition: box-shadow .16s ease, transform .16s ease, background .16s ease,
border-color .16s ease, filter .16s ease, opacity .16s ease;
}
.zzm-v4 .zzm-btn:hover {
transform: translateY(-1px);
border-color: rgba(0, 0, 0, .18);
box-shadow:
0 0 0 4px rgba(255, 255, 255, .8),
0 2px 4px rgba(0, 0, 0, .10),
0 4px 12px rgba(0, 0, 0, .09),
inset 0 1px 0 rgba(255, 255, 255, .95),
inset 0 -1px 0 rgba(0, 0, 0, .05);
}
.zzm-v4 .zzm-btn:active {
transform: translateY(0);
background: linear-gradient(180deg, #ECECE9 0%, #F4F4F1 100%); /* ⑤ 凹面翻转 */
box-shadow:
0 0 0 3px rgba(255, 255, 255, .45),
0 1px 0 rgba(255, 255, 255, .65),
inset 0 2px 4px rgba(0, 0, 0, .13),
inset 0 1px 2px rgba(0, 0, 0, .09);
}
.zzm-v4 .zzm-btn:focus-visible {
outline: none;
box-shadow:
0 0 0 3px rgba(166, 64, 47, .20), /* 键盘焦点=朱色光晕 */
0 1px 2px rgba(0, 0, 0, .09),
0 2px 6px rgba(0, 0, 0, .06),
inset 0 1px 0 rgba(255, 255, 255, .92);
}
.zzm-v4 .zzm-btn:disabled {
cursor: not-allowed;
transform: none;
}
.zzm-v4 .zzm-btn:disabled:not(.zzm-btn--busy) {
color: #A2A29C;
background: #F2F2EF;
border-color: rgba(0, 0, 0, .08);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .7), 0 1px 2px rgba(0, 0, 0, .04);
}
.zzm-v4 .zzm-btn--primary {
color: #FFFFFF;
border-color: rgba(0, 0, 0, .85);
background: linear-gradient(180deg, #3A3A36 0%, #1D1D1B 58%, #141412 100%);
box-shadow:
0 0 0 3px rgba(22, 22, 22, .06),
0 1px 2px rgba(0, 0, 0, .18),
0 3px 10px rgba(22, 22, 22, .24),
inset 0 1px 0 rgba(255, 255, 255, .20),
inset 0 -1px 0 rgba(0, 0, 0, .38);
}
.zzm-v4 .zzm-btn--primary:hover {
filter: brightness(1.12);
border-color: rgba(0, 0, 0, .85);
box-shadow:
0 0 0 4px rgba(22, 22, 22, .09),
0 2px 4px rgba(0, 0, 0, .20),
0 5px 14px rgba(22, 22, 22, .28),
inset 0 1px 0 rgba(255, 255, 255, .24),
inset 0 -1px 0 rgba(0, 0, 0, .38);
}
.zzm-v4 .zzm-btn--primary:active {
filter: none;
background: linear-gradient(180deg, #101010 0%, #22221F 100%);
box-shadow:
0 0 0 3px rgba(22, 22, 22, .06),
inset 0 2px 5px rgba(0, 0, 0, .55),
inset 0 1px 2px rgba(0, 0, 0, .4);
}
.zzm-v4 .zzm-btn--ghost {
border-color: transparent;
background: transparent;
box-shadow: none;
color: #4A4A46;
}
.zzm-v4 .zzm-btn--ghost:hover {
transform: translateY(-1px);
border-color: rgba(0, 0, 0, .14);
background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
box-shadow:
0 0 0 3px rgba(255, 255, 255, .55),
0 1px 2px rgba(0, 0, 0, .09),
0 2px 6px rgba(0, 0, 0, .06),
inset 0 1px 0 rgba(255, 255, 255, .92);
}
.zzm-v4 .zzm-btn--ghost:active {
transform: translateY(0);
border-color: rgba(0, 0, 0, .14);
background: linear-gradient(180deg, #ECECE9 0%, #F4F4F1 100%);
box-shadow: inset 0 2px 4px rgba(0, 0, 0, .12);
}
.zzm-v4 .zzm-card {
background: #FFFFFF;
border: 1px solid rgba(0, 0, 0, .09);
border-radius: 16px;
box-shadow:
0 1px 2px rgba(0, 0, 0, .04),
0 6px 18px rgba(0, 0, 0, .05),
inset 0 1px 0 rgba(255, 255, 255, .85);
}
.zzm-v4 input.zzm-input,
.zzm-v4 textarea.zzm-input {
background: #FDFDFC;
box-shadow:
inset 0 1.5px 3px rgba(0, 0, 0, .06),
inset 0 1px 1px rgba(0, 0, 0, .04);
}
.zzm-v4 input.zzm-input:focus,
.zzm-v4 textarea.zzm-input:focus {
box-shadow:
inset 0 1.5px 3px rgba(0, 0, 0, .06),
0 0 0 3px rgba(22, 22, 22, .07); /* 聚焦光晕 */
}二、用 React 组件
组件源码按 edu 的目录结构原样放在本站 /src/system/ 下,从提炼层来的组件在 /src/extracted/。把需要的文件复制进项目,保持相对路径不变即可 import。
- 运行时:React 19。
- 只有
MarkdownNotes(笔记标注块)额外需要lucide-react和framer-motion。 LessonCard会 import 一个播放预取函数,在设计系统里用空实现代替(见课节卡页)。- 样式仍然要引入 zzm.css,并在外层加
zzm-v4。
App.jsx
import './zzm.css'
import { Btn } from './components/v4/Button.jsx'
export default function App() {
return (
<div className="zzm-v4">
<Btn variant="primary">墨键 · 主操作</Btn>
</div>
)
}| 要什么 | 去哪拿 |
|---|---|
| 全部样式 | /zzm.css(带作用域)或 /zzm.global.css(不带) |
| 令牌 | /tokens.json(W3C 设计令牌格式),或直接用 CSS 变量 var(--zzm-*) |
| 一份完整规范 | /DESIGN.md |
| 组件源码 | /src/system/components/v4/*.jsx、/src/extracted/*.jsx |
| 某个组件的规则 + 代码 | 组件页右上「复制给 Agent」,或直接读 /components/<名字>.md |
三、交给 Agent
把下面这段话贴给你的编程助手。它会自己去读目录和需要的页面。
给 Agent 的提示词
请按「赵子民设计系统 v4」实现这个界面:
- 规范与目录:https://ui.zhaozimin.com/llms.txt(先读),完整规范 https://ui.zhaozimin.com/DESIGN.md
- 样式:引入 https://ui.zhaozimin.com/zzm.css,根节点加 class="zzm-v4"
- 颜色只用 var(--zzm-*);间距、高度、圆角只取 4 的倍数
- 按钮用 .zzm-btn 家族,圆角矩形,禁胶囊;阴影只从质感类取,不要自己写 box-shadow
- 一屏只用一次朱砂红(--zzm-accent),标「下一步」
- 需要某个组件时,读 https://ui.zhaozimin.com/components/<名字>.md,里面的 HTML 可以原样粘贴