---
title: 一块材料切出来的界面
url: https://ui.zhaozimin.cn/
markdown: https://ui.zhaozimin.cn/index.md
group: 开始
origin: 规范文档
version: v0.2.0  # 设计系统版本，发布于 2026-09-23
scope: .zzm-v4   # 根节点必须带这个类，否则样式不生效
css: https://ui.zhaozimin.cn/v/0.2.0/zzm.css   # 锁版本地址，本仓库再改也不影响你
---

# 一块材料切出来的界面

> 赵子民全部产品共用的设计系统。三种颜色、一把 8pt 梯子、一个「光从正上方来」的光照模型——每个令牌和组件都同时有人读版和机读版。

## 给 Agent 的一行

在 Cursor、Claude Code 或任何能联网的工具里，把下面这个地址交给它，说「按这个设计系统做」。它会从目录读到每一页的 Markdown 版本，包括令牌、铁律和可以直接粘贴的代码。

Agent 入口：

```text
https://ui.zhaozimin.cn/llms.txt
```

写静态页时，一行引入全部质感，然后在根节点加上作用域类名：

静态页（锁版本引用）：

```html
<link rel="stylesheet" href="https://ui.zhaozimin.cn/v/0.2.0/zzm.css">
<body class="zzm-v4">
  <button class="zzm-btn zzm-btn--primary">墨键 · 主操作</button>
</body>
```

## 从这里开始

## 这套系统相信什么

- **一屏一枚朱印。** 朱砂红只出现一次，永远标「你在这里 / 下一步」。红是导航信号，不是装饰。
- **圆是徽章，方角是控件。** 文字按钮一律圆角矩形；999 胶囊只留给不可点的徽章。看形状就知道能不能点。
- **一个光源。** 光从正上方来，每个控件都是一枚真实的键。阴影只从质感类取，组件里不许各写各的光。
- **一把梯子。** 间距、高度、行高、圆角都从 4 的倍数里取，不发明数字。整站看起来才像一块材料切出来的。
- **留白即上手。** 能收进次级入口的，绝不摆在主动线上。

完整说明见[设计原则](/foundations/principles)。

## 如果你是 Agent

1. 先读 [llms.txt](https://ui.zhaozimin.cn/llms.txt) 拿目录，需要全文时读 [llms-full.txt](https://ui.zhaozimin.cn/llms-full.txt)。
2. 引入 [zzm.css](https://ui.zhaozimin.cn/zzm.css)，根节点加 `class="zzm-v4"`。不加这个类，样式一点都不生效。
3. 按钮用 `.zzm-btn` 家族，卡片用 `.zzm-card` / `.zzm-cardlink`，输入框用 `.zzm-input`；颜色只用 `var(--zzm-*)`。
4. 不要自己写 `box-shadow`，不要把按钮做成胶囊，不要引入网络字体。
5. 每个组件页都有 `.md` 版本，里面的 HTML 是构建时渲染出来的真实标记，可以原样粘贴。
6. 引用样式请锁版本：`https://ui.zhaozimin.cn/v/0.2.0/zzm.css`。不锁版本的 `/zzm.css` 永远指向最新，设计系统一改，你的页面就会跟着变。

本站是这套设计系统的**唯一源头**，当前版本 v0.2.0。消费方（包括赵子民自己的课程站 edu.zhaozimin）锁版本使用，不执行升级命令就不会跟随变动。

## 本页用到的 CSS

按样张里出现的类名，从源文件原样裁出（完整版见 zzm.css）：

```css
/* base.css */

.zzm-v4 input.zzm-input:focus, .zzm-v4 textarea.zzm-input:focus { border-color: #161616 !important; }

.zzm-v4 .zzm-skel {
  position: relative;
  overflow: hidden;
  background: #EFEFEC;
  border-radius: 8px;
}

.zzm-v4 .zzm-skel::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, .65), transparent);
  animation: zzmShimmer 1.4s ease infinite;
}

/* 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--ondark:disabled:not(.zzm-btn--busy) {
  color: rgba(255, 255, 255, .45);
  background: rgba(255, 255, 255, .08);
  border-color: rgba(255, 255, 255, .16);
  box-shadow: none;
}

.zzm-v4 .zzm-btn--busy {
  position: relative;
  overflow: hidden;
  pointer-events: none;
  opacity: .92;
  filter: saturate(.72);
  transform: none;
}

.zzm-v4 .zzm-btn--busy::before {
  content: "";
  position: relative;
  z-index: 1;                                            /* 旋转环压在反光层之上 */
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  opacity: .7;
  animation: zzmBtnSpin .7s linear infinite;
}

.zzm-v4 .zzm-btn--busy::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  transform: translateX(-180%);
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, .45) 50%, transparent 60%);
  animation: zzmPillShine 4.4s ease-in-out infinite;
}

.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--accent {
  color: #FFFFFF;
  border-color: rgba(122, 42, 29, .9);
  background: linear-gradient(180deg, #C25743 0%, #A6402F 56%, #99392A 100%);
  box-shadow:
    0 0 0 3px rgba(166, 64, 47, .10),                   /* 朱色反光光晕 */
    0 1px 2px rgba(0, 0, 0, .14),
    0 3px 10px rgba(166, 64, 47, .28),
    inset 0 1px 0 rgba(255, 255, 255, .32),
    inset 0 -1px 0 rgba(0, 0, 0, .20);
}

.zzm-v4 .zzm-btn--accent:hover {
  filter: brightness(1.06);
  border-color: rgba(122, 42, 29, .9);
  box-shadow:
    0 0 0 4px rgba(166, 64, 47, .16),
    0 2px 4px rgba(0, 0, 0, .16),
    0 5px 14px rgba(166, 64, 47, .34),
    inset 0 1px 0 rgba(255, 255, 255, .36),
    inset 0 -1px 0 rgba(0, 0, 0, .20);
}

.zzm-v4 .zzm-btn--accent:active {
  filter: none;
  background: linear-gradient(180deg, #8E3425 0%, #A03D2C 100%);
  box-shadow:
    0 0 0 3px rgba(166, 64, 47, .10),
    inset 0 2px 5px rgba(0, 0, 0, .34),
    inset 0 1px 2px rgba(0, 0, 0, .24);
}

.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-video-play {
  display: grid;
  place-items: center;
  width: 72px;
  height: 72px;
  padding: 0;
  border: 1px solid rgba(0, 0, 0, .16);
  border-radius: 50%;
  cursor: pointer;
  color: #1D1D1B;
  background: linear-gradient(180deg, #FFFFFF 0%, #F2F2EF 100%);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .24),
    0 2px 4px rgba(0, 0, 0, .16),
    0 6px 16px rgba(0, 0, 0, .22),
    inset 0 1px 0 rgba(255, 255, 255, .96),
    inset 0 -1px 0 rgba(0, 0, 0, .08);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}

.zzm-v4 .zzm-video-play:hover {
  border-color: rgba(0, 0, 0, .3);
  box-shadow:
    0 0 0 5px rgba(255, 255, 255, .3),
    0 3px 6px rgba(0, 0, 0, .18),
    0 9px 22px rgba(0, 0, 0, .28),
    inset 0 1px 0 rgba(255, 255, 255, .98),
    inset 0 -1px 0 rgba(0, 0, 0, .08);
}

.zzm-v4 .zzm-video-play:active {
  transform: scale(.98);
  background: linear-gradient(180deg, #E9E9E6 0%, #F4F4F1 100%);
  box-shadow:
    0 0 0 4px rgba(255, 255, 255, .24),
    inset 0 2px 5px rgba(0, 0, 0, .16),
    inset 0 1px 2px rgba(0, 0, 0, .10);
}

.zzm-v4 .zzm-video-play:focus-visible {
  outline: none;
  box-shadow:
    0 0 0 4px rgba(166, 64, 47, .28),
    0 2px 4px rgba(0, 0, 0, .16),
    0 6px 16px rgba(0, 0, 0, .22),
    inset 0 1px 0 rgba(255, 255, 255, .96);
}

.zzm-v4 .zzm-video-play__icon {
  width: 24px;
  height: 24px;
  margin-left: 4px;
  fill: currentColor;
}

.zzm-v4 .zzm-btn--sm { height: 28px; padding: 0 12px; font-size: 12px; gap: 4px; }

.zzm-v4 .zzm-btn--icon.zzm-btn--sm { width: 28px; }

.zzm-v4 .zzm-cardlink {
  background: #FFFFFF;
  border: 1px solid rgba(0, 0, 0, .09);
  border-radius: 16px;
  padding: 12px;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0, 0, 0, .04);
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}

.zzm-v4 .zzm-cardlink:hover {
  transform: translateY(-3px);
  border-color: rgba(0, 0, 0, .3);
  box-shadow: 0 10px 30px rgba(0, 0, 0, .09), 0 1px 2px rgba(0, 0, 0, .04);
}

.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);                    /* 聚焦光晕 */
}

.zzm-v4 .zzm-pill-shine {
  position: relative;
  overflow: hidden;
}

.zzm-v4 .zzm-pill-shine::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  transform: translateX(-180%);
  background: linear-gradient(105deg, transparent 34%, rgba(255, 255, 255, .85) 50%, transparent 66%);
  animation: zzmPillShine 4.6s ease-in-out infinite;
  animation-delay: var(--zzm-shine-delay, 0s);
}

/* keyframes */
@keyframes zzmShimmer { 100% { transform: translateX(100%) } }
@keyframes zzmBtnSpin { to { transform: rotate(360deg) } }
@keyframes zzmPillShine { 0% { transform: translateX(-180%) } 14% { transform: translateX(180%) } 100% { transform: translateX(180%) } }
```

---

上一页：无 · 下一页：[快速接入](https://ui.zhaozimin.cn/start/quickstart.md) · 全站目录：https://ui.zhaozimin.cn/llms.txt
