用途#
呈现信息:标签、数字、表格、时间。
标签与徽章#
分两族,形状就是语义:直角 = 归档性的、不变的信息;胶囊 = 短暂的、会变的状态。
直角标签#
| 类型 | 外观 | 用在哪 | 来源 |
|---|---|---|---|
| 名值对 | "名"墨底白字 + "值"浅灰底墨字,紧贴无缝 | 属性:阵营、种族、配音… | 实测 |
| 名值对(强调) | "名"换成黄底墨字 | 一组里需要突出的那一项 | 实测 |
| 类型标签 | 深灰底(#38383A)白字,圆角 2px |
媒体类型:PV、OST |
实测 |
| 类型标签(浅) | 白底、1px line-strong 描边、直角 |
活动类型、分类 | 观察 |
| 日期块 | 墨底白字,等宽数字;可在左上加一个小红角 | 时间轴上的日期锚 | 观察 |
| 微标行 | // 类目 日期,无底色 |
新闻、列表的元信息 | 观察 |
| 状态签 | 黄底墨字的小块 | NEW、推荐 |
社区 |
规格:
| 项 | sm |
md |
|---|---|---|
| 高度 | 20px | 28px |
| 字号 | text-xs |
text-sm |
| 字重 | Medium | Medium |
| 水平内边距 | 6px | 10px |
名值对的两半紧贴,中间没有缝也没有分隔线;多组名值对之间留 8px。
已实现的写法:
| 类型 | 写法 |
|---|---|
| 名值对 | <TagPair name="阵营" value="…" /> |
| 名值对(强调) | <TagPair emphasis … /> |
| 类型标签 | <Tag variant="solid"> |
| 类型标签(浅) | <Tag variant="outline"> |
| 日期块 | <Tag variant="inverse" numeric>;加 marked 出现左上角的小红角 |
| 状态签 | <Tag variant="accent"> |
| 增益签 | <Tag variant="gain" numeric>,见下一节 |
名值对在暗色主题下整体反转:"名"是近白底墨字,"值"是纯黑底白字。
小红角是一个 6px 的 alert 色三角,用来在一组日期块里标出需要留意的那一个;它在两个主题下取值相同。
云游戏页里有几样相近的东西,库里照旧是上表的直角标签:
- 公告列表的日期写成"15 ╱ 10月":大号的日、小号的月,中间一根转 −45° 的 1.5px 细线,是 CSS 画的,不是字符(实测(云游戏页),公告页)。它是日期块的另一种写法,不另做组件。
- 有新内容的公告项右上角探出一枚品牌黄(
#FFF100)底、黑字的角标,左端是向左的尖角,整体是个五边形(观察(云游戏页):整枚是一张图,字没有逐字认过)。状态签照旧是直角的小块。 - 采购中心的商品卡左上角可以有一枚向左探出 4px 的小标签,2px 圆角:赠送是
#FFF200底、#3A3A3A字,限时是#FC5410底、白字加一个时钟图标,写剩余的天数、小时或分钟;两种不会同时出现。售罄的卡盖一层黑 80%,中间一个图形和"- 售罄 -"(实测(云游戏页))。
胶囊与角标#
| 类型 | 外观 | 用在哪 | 来源 |
|---|---|---|---|
| 筛选胶囊 | 白底细边;选中反转为墨底白字 | 类目筛选 | 社区 |
| 资源胶囊 | 深色胶囊,圆形图标 + 等宽数字 | 货币、材料数量 | 社区 |
| 倒计时 | 实色胶囊,等宽数字;绿 = 充裕,红 = 紧迫 | 限时内容 | 社区 |
| 通知角标 | 橙色菱形(无数字)或橙色小方块(带数字) | 未读、待处理 | 社区;橙色菱形:实测(云游戏页) |
| 增益签 | 荧光黄绿底墨字,直角 | +6%、增量 |
社区 |
规则:
- 一个元素上的徽章不超过两个。
- 徽章的颜色严格按 色彩 的角色表:橙 = 提醒与数量,红 = 紧迫,绿 = 充裕,黄 = 新。
- 通知角标压在元素的右上角,向外偏移半个自身大小。
- 数字超过 99 显示
99+。
云游戏页顶栏"公告"的图标右上角压着一个无数字的菱形:#FF7500 的 10px 方块转 45°,外面一圈 2px 的黑色投影,读屏名是"有新内容"(实测(云游戏页))。它和上表的橙色菱形是同一个样子,这一项的证据因此多了一条实测;库里的画法不变。公告页的页签上是另一种:一个 #FF7600 的橙色圆点,外面一圈橙色的菱形描边每秒放大淡出一次(观察(云游戏页):圆点和描边都是图片)。见 云游戏页。
已实现的写法:
| 类型 | 写法 | 取色 |
|---|---|---|
| 筛选胶囊 | <FilterChip selected onSelectedChange> |
未选是细边(line-strong);选中反转为 surface-inverse 底、ink-inverse 字 |
| 资源胶囊 | <ResourceChip icon label> |
control 底、on-control 字,两个主题下相同 |
| 倒计时 | <Countdown to urgentWithin onExpire> |
充裕 success 底、紧迫 danger 底,字都是 ink-inverse;到期后 surface-muted 底 |
| 通知角标 | <Badge count={12}>、<Badge dot> |
notice 底、墨字 |
| 增益签 | <Tag variant="gain" numeric> |
gain 底、neutral-900 字(11.9:1),两个主题下相同 |
几处实现时定下的细节:
- 筛选胶囊是一个切换按钮(
aria-pressed),几个并排就是多选筛选;几项里只能选一项时用页签的capsule变体。两者共用一份样式;不同的是页签选中的墨底是同一块,换一个时 滑过去,筛选胶囊各自开关,不滑。 - 筛选胶囊在高对比模式下底色被系统换掉、选中时透明的边线也显了形,选中的和没选的成了一个样子:选中的改用系统的"选中"色(
Highlight底和边线、HighlightText字),选中又禁用的是GrayText底、Canvas字。见 色彩。(推断) - 资源胶囊不带图标:本库不收录资源图标,由使用方传入,放进左端的圆形底托。
- 倒计时的两种状态色没有直接用角色色。
alert红作底时墨字白字都不到 4.5:1(见 色彩),所以改用按主题切好的文字档语义色作底、ink-inverse作字:亮色下充裕 5.1:1、紧迫 5.1:1,暗色下 9.3:1、4.8:1。 - 紧迫态不只靠红色:数字前多一个
!。默认在剩余不到 24 小时时进入紧迫态,门槛可调。 - 倒计时超过一天写成
3天 04:12:09,不到一天写成04:12:09;到期后显示"已结束"并停表。 - 增益签形状是直角,所以做成了
Tag的一个变体,而不是胶囊。下降不用它:用danger色的文字加−。
数据行带#
游戏内数据面板的范式(社区):浅色画布上一条条深色的行。
| 部件 | 做法 |
|---|---|
| 画布 | surface-sunken(浅) |
| 列头 | 一条灰色胶囊带(neutral-300),列名之间用短竖线分隔 |
| 行 | 深色(neutral-950),直角,行间留 6px 缝 |
| 行左 | 4px 类目色条 → 收藏圆(黄色实心 = 已收藏)→ 名称 |
| 行中 | 内嵌一个小型面积图或走势线 |
| 行右 | 当前值(语义色)与参考值(neutral-400),等宽数字 |
数字语义色固定:
| 含义 | 颜色 | 令牌 |
|---|---|---|
| 产出、正向 | 蓝 | info / data |
| 消耗、关注 | 黄 | signal |
| 超支、异常 | 红 | danger / alert |
颜色之外还要有正负号或图标,不只靠颜色。
行底用 neutral-950 而不是更浅的深灰,是为了让蓝色与红色的数字达到 4.5:1(在 #141414 上分别约为 5.1:1 与 5.0:1;换成 #282828 会降到 4.1:1)。
行内图表保持极简:没有坐标轴、没有网格、没有图例,只有一个填充的面积形状。
实现#
<DataRowList label columns> + <DataRow name categoryColor favorite series value tone reference>:
columns给列名:{ name, trend, value, reference }。不给trend或reference就没有那一列。- 语义是表格(
role="table"、row、columnheader、rowheader、cell),各行用 CSS 子网格对齐到同一组列。没有用真的<table>:行间的缝、整行的底和行内的按钮用它很难画。 - 行带和列表的
band变体是同一份画法(见 卡片与列表):固定深色的局部主题、surface底、一圈 1px 的line,行高 44px。 - 列头没有照上表用
neutral-300:它在暗色页面的纯黑画布上是一条亮带。改用surface-muted(亮色#E6E6E6、暗色#282828),列名之间的短竖线是line-strong。 - 类目色条由
categoryColor给,是一个 CSS 颜色值,通常传令牌变量(var(--color-special))。类目是哪几种、各用什么颜色由产品自己定;不要用黄色——黄色是"选中"和"收藏"。 - 收藏圆直径 16px:已收藏是实心的
action黄,未收藏是一个空心的圆环——形状也不同,不只靠颜色。传了onFavoriteChange它是一个切换按钮(aria-pressed,点击区补到 36px);只传favorite它是一个静态标记,读屏另有"已收藏"。 - 高对比模式下实心的圆是底色画的,会不见(和"没有收藏圆"分不开):改用
Highlight。空心的圆环是边线,不用动。见 色彩。(推断) - 当前值按
tone着色,用的是库里已有的词:info(产出、正向)、accent(消耗、关注)、danger(超支、异常)、neutral。行是局部暗色主题,这三档文字色在上面正好是上表的取值(#2D8FC2、#FFFA00、#F74040),对比度都在 4.5:1 以上。正负号由使用方连同数值一起传。 - 走势传
series(一串数值),画成下面的小型面积图:平时是data蓝,这一行是danger时换成alert红。消耗行的图仍然是蓝的——黄色在图上留给"进度"。同一屏的几张图是一起画出来的,不逐行错开;走势列被收起(窄容器)时不播,展开了才播。 - 容器变窄时先收起走势列(512px 以下),再收起参考值列(384px 以下);列头跟着收。名称过长时截断。
- 行本身不可点:行里已经有收藏按钮,整行再做成链接就是按钮套按钮。要点进详情时把名称写成链接。
小型面积图#
<Sparkline data variant tone label> 是行内图表单独拿出来的版本,统计块旁边、表格的单元格里也能用。
| 项 | 值 |
|---|---|
| 形状 | area(默认)是一块填充的面积,75% 不透明;line 是一条 1.5px 的折线 |
| 颜色 | info 用 data 蓝(默认),danger 用 alert 红,accent 用强调色的文字档,neutral 用 ink-secondary |
| 尺寸 | 撑满给它的盒子;默认高 32px、通宽 |
| 纵向范围 | 默认从数据的最小值往下再留四分之一,让最低的那一点也有厚度;可以用 min / max 钉死 |
| 入场 | 进入视口时从左画出一次:整张图擦入,600ms(和进度条的充填同一档)。animate={false} 关掉(推断) |
- 没有坐标轴、网格和图例;折点不做平滑——这套语言里线是直的。
data和alert是不随主题变的角色色,在白底和深色行带上都够 3:1(图形的门槛)。- 高对比模式:图是 SVG 画的,上面写的颜色系统不换——四种色调还是主题里的颜色,压在使用者自己定的页面色上不一定看得清(亮色主题的墨色压在黑底上)。面积和折线都换成
CanvasText;色调说的事(超支、强调)这时候看不出来,本来也要靠旁边的数字说。见 色彩。(推断) - 默认对读屏隐藏,旁边的数字才是内容。它独自承担含义时传
label,这时它是一张有名称的图。 - 数据少于两个点时什么都不画。
- "画出"用的是擦入(
animate-wipe-in),面积和折线同一个写法。没有用描边虚线那种"沿着线画"的做法:图是被横向拉伸的,线宽不跟着变(non-scaling-stroke),这时候按路径长度做虚线各浏览器算得不一样。折线有半个线宽、尖角有一截画在盒子外面,擦的时候那一圈留着(--wipe-bleed)。
统计块#
一个需要被一眼看到的数字(推断)。
// TOTAL ← 微标
1,280 件 [+6%] ← 大号等宽数字 + 单位 + 增量签| 部件 | 做法 |
|---|---|
| 容器 | 不用卡片。左缘一条 3 – 4px 的 ink 竖线 |
| 微标 | text-xs,ink-secondary,// 起头 |
| 数字 | font-tech,text-4xl – text-5xl,Medium,等宽 |
| 单位 | text-sm,ink-secondary,基线对齐 |
| 增量 | 增益签(荧光黄绿);下降用 danger 色文字加 − |
多个统计块并排时,用留白和竖线分隔,不要各自装进卡片。让其中最重要的一个明显更大。
加载页的百分比是它的原型:数字 4.375rem、符号 3.25rem,数字与单位两种字号(实测)。
已实现为 <Stat label value unit delta trend size>:
size="md"是text-4xl,size="lg"是text-5xl——并排几个时给最重要的那个用lg;- 微标前的
//由组件加,并对读屏隐藏; delta连同正负号一起传;trend="up"(默认)渲染为增益签,trend="down"渲染为danger色文字;- 容器很窄时数字允许在任意位置折行,不会撑破版面。
- 数字要"滚上来",把一个 滚动数字 放进
value。
滚动数字#
<RollingNumber value format animate>:数字从 0 滚到终值,进入视口时滚一次(推断)。它是单出来的小组件,不是统计块的属性——数据行带的当前值、表格单元格里的数也能用同一个。
<Stat label="TOTAL" value={<RollingNumber value={1280} />} unit="件" />| 项 | 值 |
|---|---|
| 怎么动 | 从 0 到终值,先快后慢(和 ease-exit 一类,不带过冲),600ms(--duration-slower,入场那一档) |
| 什么时候 | 进入视口时一次。值后来变了直接换,不再滚——不然就成了"数字翻动"那一类持续的动效(见 动效 的"日常交互保持安静") |
| 写法 | 默认带千分位(1,280),小数位数跟着终值(42.5 一路都是一位小数);别的写法传 format,每一帧都用它 |
| 宽度 | 由终值占着,滚的时候旁边的单位、增量签不动。等宽数字由所在处给(统计块、数据行带都已经是 tabular-nums) |
- 读屏只读终值。 终值一直在 DOM 里,滚的时候只是看不见;滚动的那一份对读屏隐藏。
- 不显示错的数。 服务端渲染出来的是终值(脚本到了才从头滚);打印出来的是终值;系统开了"减少动态效果"时直接是终值,不滚。
- 它是库里唯一用脚本一帧一帧算的动效:CSS 那条全局的降级规则管不到它,所以自己看
useReducedMotion。 - 一页里不要到处都滚:留给统计块这类"需要被一眼看到的数字"。表格里一整列都滚起来就是噪音。
animate={false}关掉。
头像#
代表一个人或一个角色的圆形图。头像是这套语言里少数用正圆的东西之一:圆表示"人",直角表示"物"和"机器"(见 形状)。
| 项 | 值 | 来源 |
|---|---|---|
| 形状 | 正圆,图片铺满并裁切 | 实测(官网的头像切换) |
| 尺寸 | sm 32px、md 40px、lg 56px、xl 80px |
推断 |
| 没有图 | surface-muted 底,ink-secondary 的名字首字,字号约为直径的 40% |
推断 |
| 描边、阴影 | 没有 | 实测 |
| 选中 | 外面一圈 3px 的 action 色环,和头像隔 2px |
实测("选中者带黄环") |
- 选中环外面还有一圈 1px 的墨线。 黄色在白底上只有 1.1:1,单靠它在亮色页面上看不出来;官网的黄环是压在灰底和图像上的。墨线在暗色主题下是近白,和黄环并在一起,不碍事。
- 高对比模式下阴影不画,选中环就没了:换成一圈 3px 的
Highlight边线,画在头像里面——外面那一圈留给头像切换的焦点环。见 色彩。(推断) - 首字的取法:中文名取第一个字;拉丁字母的名字取前两个词的首字母并大写。
- 头像旁边已经写了名字时,头像是装饰,对读屏隐藏;单独出现时它是一张以名字命名的图。
- 不要用方形或带圆角的方形头像:那是"物品格"的形状。
已实现为 <Avatar name src size selected>:
- 图没给、还没加载出来、或者加载失败时显示首字;图加载好了才换上去,不会先闪一下破图。
alt默认取name。旁边已经有名字时传alt="",头像变成纯装饰。- 要在没有图时显示别的东西(一个图标),把它当子元素传进去。
- 头像自己不能点。要点的话外面包按钮或链接;一列头像里选一个,用 头像切换。
表格#
(推断)
| 项 | 值 |
|---|---|
| 表头 | surface-inverse 底、ink-inverse 文字,text-sm font-medium,高 28 – 32px |
| 行高 | 36 – 44px |
| 行分隔 | 1px line;不画竖线 |
| 悬停行 | ink 叠 5%(hover:bg-ink/5) |
| 选中行 | surface-muted + 左缘 4px action 色条 |
| 数字列 | 右对齐,font-tech,等宽 |
| 文字列 | 左对齐 |
| 斑马纹 | 不用;行数很多时可以每隔五行加重一条线 |
- 表头墨底白字是这套语言里"标题带"的通用样子(面板标题、弹窗标题栏同理)。
- 可排序的列:列名右侧一个小三角,当前排序列的三角变黄(深底上)。
- 行内操作用图标按钮或
text按钮,悬停时才显示也可以,但键盘聚焦时必须显示。 - 窄屏:横向滚动并冻结首列;或把每行改成一张属性卡。
浅表头的变体:surface-muted 底、ink 文字——用在页面已经有很多深色块的时候。
悬停行原先写的是 surface-sunken,改成了全库统一的 ink 5%:surface-sunken 在暗色主题下是纯黑,悬停会变暗而选中变亮,方向相反(页签、列表行是同一条理由)。
实现#
包一层原生 <table>,组合着用:
<Table label="运输批次">
<TableHead>
<TableRow>
<TableHeaderCell>批次</TableHeaderCell>
<TableHeaderCell numeric sort={direction} onSort={setDirection}>
件数
</TableHeaderCell>
</TableRow>
</TableHead>
<TableBody>
<TableRow selected>
<TableCell rowHeader>TR-2041</TableCell>
<TableCell numeric>12</TableCell>
</TableRow>
</TableBody>
</Table>| 部件 | 属性 |
|---|---|
Table |
label(名称,必填)、headerVariant、size、stickyFirstColumn、stickyHeader、ruled |
TableHeaderCell |
numeric、align、sort、onSort |
TableRow |
selected;能展开的行另有 detail、expanded / defaultExpanded / onExpandedChange |
TableCell |
numeric、align、rowHeader、reveal |
TableExpander |
aria-label(默认"明细") |
- 表头 32px 高。
headerVariant="band"(默认)是反转的标题带,和面板的标题带是同一个样子;"muted"是上面说的浅表头。反转的表头是一个 反转主题(data-theme="inverse"):列头的焦点环、排序的三角、放在表头里的复选框都按带子的底色取值。 - 行高两档:
sm36px、md44px(默认)。行间 1pxline,最后一行下面不画;ruled打开后每隔五行换成line-strong(只数主行,展开的明细不算;第五行展开着的时候,加重的那条线画在它的明细下面)。- 这是行的最小高度:格子里的东西比它高,行就跟着高。复选框自带 40px 的点击区,所以带勾选的行实际是 49px 上下,换成
sm也矮不下来。要一张真的紧凑的表(有鼠标的密集界面),给行里的复选框加className="min-h-0 py-0"把点击区收掉——调度台示例页的"紧凑行高"就是这么做的。
- 这是行的最小高度:格子里的东西比它高,行就跟着高。复选框自带 40px 的点击区,所以带勾选的行实际是 49px 上下,换成
- 单元格默认不折行。 放不下的时候表格在自己的容器里横向滚动,不把字挤成两行,也不撑破页面。确实要折行的长文字列,自己加
whitespace-normal并给一个最小宽度。 - 只有真的溢出时(横向或纵向),滚动的那一层才是一个能聚焦的区域(
role="region",名称同表格):键盘得能滚它,但不溢出的时候不该白占一个 Tab 停靠点。 stickyFirstColumn冻结首列,溢出时它的右缘多一条线。冻结的那一格必须不透明,否则滚过去的内容会从它下面透出来——所以它的底不是透明的:平时是表格所在的底色,悬停时是"ink5% 混进这个底色"算出来的实色(看上去和其余单元格上那层半透明的悬停底一样),选中时是surface-muted。表格默认认为自己压在surface上;压在别的底色上(比如面板里)时,给Table加className="[--table-surface:var(--ef-surface-raised)]"。stickyHeader表头吸顶:表身在容器里纵向滚动时表头留在容器的上沿。容器要有一个高度上限才滚得起来,由使用方给:<Table stickyHeader className="max-h-96">。和stickyFirstColumn同开时,左上角那一格压在两者之上。- 表头吸不到页面的上沿。 表格要在自己的容器里横向滚动,而 CSS 的
sticky只认最近的那个滚动容器——容器一旦能横向滚,表头就只能相对它吸附。行数多到要整页滚着看时,给容器一个max-h-[70vh]之类的上限,让表身在容器里滚。
- 表头吸不到页面的上沿。 表格要在自己的容器里横向滚动,而 CSS 的
- 排序的状态由使用方自己拿着。传了
onSort的列,列名变成一个铺满整格的按钮,右侧一个 8px 的实心三角;onSort拿到的是点了之后该换成的方向(没排或降序时是升序,升序时是降序)。- 没按这一列排时三角是 40% 的不透明度,朝下;按它排时三角指明方向(升序朝上、降序朝下),颜色换成强调色。
- 强调色是
accent-ink。反转的标题带是反转主题,它在那里面取的是"压在这条带子上"的那一档:亮色页面上是黄,暗色页面上是强调色的文字档。焦点环同理,用的就是普通的focus。 - 数字列的三角放在列名左边,列名的右缘才能和下面的数字对齐。
aria-sort只写在当前排序的那一列上。
- 选中行:
surface-muted底 + 左缘 4px 的action色条,输出aria-selected。色条是第一格上的一道内阴影,冻结首列时跟着它不动。 - 整行不可点。 要进详情,把名称写成链接;要勾选,在第一列放
Checkbox,表头里放一个全选(部分选中时是半选)。两种表头里都可以放。 - 行内操作放在加了
reveal的单元格里:有鼠标的设备上平时藏着,悬停这一行、或者键盘焦点进了这一行就显示;触屏上没有悬停,所以常显。藏着的时候它们仍然在 Tab 序列里。 - 没有数据时,放一行通栏的单元格(
colSpan),里面是 空状态。 - 窄屏的另一种做法——每行改成一张属性卡——没有做成表格的属性:那是另一种布局,不是同一张表换个样子。需要时用 面板 的属性行另搭,按断点切换。
行展开#
(推断:从表格自己的画法延伸。小三角是列头排序用的那一个,转 90° 的做法同 侧轨的二级;明细区是凹陷的底——"里面的一层")
一行下面还压着一层明细(装车清单、几行属性、一段说明)时用。先问两句:每一行的明细都要看的,直接多加几列;明细多到是另一页的事,把名称写成链接。
<TableRow detail={<Manifest id="TR-2041" />}>
<TableCell rowHeader>
<span className="flex items-center gap-2">
<TableExpander aria-label="TR-2041 的明细" />
TR-2041
</span>
</TableCell>
<TableCell numeric>12</TableCell>
</TableRow>| 项 | 值 |
|---|---|
| 展开钮 | 24px 的方钮,里面一个 8px 的实心三角:收起朝右,展开朝下 |
| 钮的颜色 | ink-secondary;悬停 ink + ink 叠 5% 的底 |
| 点击区 | 用伪元素向外补到 40px |
| 明细区 | surface-sunken 底,内边距 12px 16px,下面一条 1px line |
| 展开着的主行 | 自己的下边线去掉:它和明细是一块 |
| 展开 / 收起 | 明细区按高度长出来 300ms、收回去 200ms,ease-standard(和 折叠面板 同一条);只动高度,不淡 |
TableRow传了detail才能展开。 展开时在这一行后面多出一行,里面是一个通栏的单元格(colSpan自己算:按这一行各格的colSpan加起来);收起之后明细不在页面里——收的那 200ms 里它还在,但点不到、Tab不进去,展开钮的aria-expanded在点下去的那一刻就变了。- 展开钮
TableExpander由使用方放进某一格,通常是第一格、名称前面——和"要勾选就在第一列放Checkbox"是同一个思路,表格不替你加一列。它是一个按钮:aria-expanded说开没开,展开时aria-controls指向明细那一行。名称默认是"明细",一张表里有很多个,写成"TR-2041 的明细"读屏才分得清。放在不能展开的行里它不渲染。 - 状态默认各行自己记着(
defaultExpanded);要"全部展开""同时只开一行",用expanded+onExpandedChange自己拿着。 - 明细按高度展开、收起,三角同时转过去(
duration-fast)。表格行的高度过渡不了,过渡的是单元格里的那一层:只有一行的网格,行高在0fr和1fr之间走,不用量高度。一次展开好几行("全部展开")时各行同时、同速,不错开。一开始就展开着的行载入时是静止的。(推断,见 动效) - 主行"不画下边线"看的是后面有没有跟着明细,不是开没开:正在收起的那一会儿线仍然在明细下面,跟着它升上来。
- 横向滚动时明细不跟着滚走:明细的内容钉在容器的左缘,宽度是容器看得见的那一段,不是整张表的宽度。
- 明细区没有悬停底,也不算"这一行":行内操作的
reveal、选中的色条都只管主行。 - 明细里放什么都行(面板 的属性行、一张小表、一段文字),但不要再放一层能展开的表格。树形表格(子行和父行共用列)是另一种东西,没有做。
时间线#
(推断,参照版本日历的日期锚)
| 部件 | 做法 |
|---|---|
| 轴 | 2px line-strong 竖线 |
| 节点 | 16px 菱形 |
| 已过 | 实心墨色菱形 |
| 当前 | 黄色菱形,墨色描边 |
| 未到 | 空心菱形,ink-tertiary 描边 |
| 日期 | 节点右侧上方,font-tech text-xs,ink-secondary |
| 内容 | 日期下方;当前项加粗,未到的项用 ink-secondary |
横向的时间轴(排期、日历)是另一个控件,见下面的排期。
已实现为 <Timeline> + <TimelineItem status date title>,status 取 past(默认)、current、upcoming:
| 状态 | 节点 | 文字 |
|---|---|---|
past |
ink 实心 |
ink |
current |
action 底 + 1px ink 描边 |
ink,加粗 |
upcoming |
2px ink-tertiary 描边,空心 |
ink-secondary |
- 当前节点的描边只有 1px,是能画的最细一档。两头都试过:2px 的一圈黑框在亮色界面上显得重;完全不描边,黄色菱形对白底的明度差又太小,只靠色相认出来。1px 刚好够把形状勾出来。
- 描边用
ink,跟着主题走:亮色下是墨色,暗色下是近白。暗色下如果仍用墨色,描边会融进页面,节点看上去比前后两个小一圈。 - "当前"不只靠节点表达:标题同时加粗,读屏另有
aria-current。 - 轴只画在节点之间,不从节点后面穿过,空心菱形不需要垫底色,放在哪种表面上都是空的。
- 没有日期时节点对齐标题的第一行;标题换行时节点不跟着居中。
- 列表是
<ol>;当前项带aria-current="step",节点与轴线对读屏隐藏。 - 高对比模式下底色都被系统换掉:"已过"的实心菱形和轴整个不见,"当前"的黄底也没了,只剩一圈 1px 的线,比"未到"的 2px 空心菱形还轻。已过的节点和轴用
CanvasText;当前的节点用Highlight(描边照旧);未到的是描边画的,不用动。三种是实心的字色、实心的"选中"色、空心。见 色彩。(推断)
排期#
横向的时间轨图:什么时候有什么。官网的版本日历是它的原型(观察,结构见 宣传物料 的"版本日历"):
| 部件 | 做法 | 来源 |
|---|---|---|
| 时间轴 | 浅色的轴条横贯,高 32px,一天一格,格里是日号(text-micro、font-tech) |
观察;日号是补的 |
| 日期锚 | 压在轴条上的日期块:墨底白字、等宽数字、MM.DD,左上一个小红角 |
观察 |
| 引线 | 从每个日期锚往下一条 1px 的虚线,穿过所有的轨,画在条目后面 | 观察 |
| 类目竖轨 | 左侧 48px 宽的色块:图标 + 竖排小字;横向滚动时冻结 | 观察 |
| 条目 | 从起始日那一格的左缘开始,到结束日那一格的右缘为止;高 48px | 观察 |
| 活动条目 | 浅底,可以垫一张图;左上是墨色的名称块,右上是白底描边的类型小标签 | 观察 |
| 系统条目 | 炭灰底(control)+ 左端 6px 的行动色侧签 + 名称 + 一条行动色的虚线;不带图 |
观察 |
| 空档 | 没有条目的时段露出底上的淡斜纹 | 社区 |
| 今天 | 可选:一条 2px 的强调色竖线,画在条目上面 | 推断 |
规则:
- 位置就是信息。 条目的左端对齐起始日,长度就是持续时间,不用再写"开始于"。
- 多条并行时按类目分轨。同一条轨里时间重叠的条目会自动错到下一行,但那是兜底,不是排版手段。
- 名称块、类型标签、日期锚的样子全表统一;条目自己的识别靠垫的那张图。
- 最小单位是天。要排到小时的日程不是这个控件。
- 类目竖轨的颜色可以换成版本的主题色(见 色彩 的"主题色接管"),其余部件保持中性。
实现#
<Schedule label start end anchors today dayWidth locale describeRange>,里面是 <ScheduleTrack label icon>,轨里直接放 <ScheduleItem start end title type variant media href>:
<Schedule label="十月排期" start="2026-10-01" end="2026-10-31" today="2026-10-09">
<ScheduleTrack label="活动" icon={<RouteIcon />}>
<ScheduleItem start="2026-10-03" end="2026-10-12" title="管廊北段测绘" type="限时" />
</ScheduleTrack>
<ScheduleTrack label="系统" icon={<SlidersIcon />}>
<ScheduleItem variant="system" start="2026-10-01" end="2026-10-31" title="每日签到" />
</ScheduleTrack>
</Schedule>- 日期都是
YYYY-MM-DD的字符串,end是包含的最后一天:10 月 3 日到 12 日的条目占十格。 - 布局是 CSS 网格,一天一列:条目只写起止列,哪一行由网格的自动摆放决定(
row dense)——重叠的条目错到下一行,这件事不用自己算。 - 一天默认至少 32px 宽(
dayWidth)。容器够宽时各列平分多出来的宽度;不够时在自己的容器里横向滚动,不撑破页面。只有真的溢出时,滚动的那一层才是一个能聚焦的区域(同表格)。 - 类目竖轨冻结在左边,底是不透明的(
surface-inverse)。要换颜色,在ScheduleTrack上写className="[--track-color:…] [--track-ink:…]"。 - 日期锚默认是范围的第一天和范围内每个月的 1 号;
anchors自己指定。日期锚比一天的格子宽,它盖住的那两格不写日号。 - 起止超出范围的条目被裁到范围内(读屏听到的仍然是它真正的起止日期);整个都在范围外的不画。
- 条目可以是链接:传
href,或者用render交给路由库的链接组件——链接写在名称里,点击范围铺满整个条目,焦点环画在条目上。 - 读屏:位置读不出来,所以每个条目的名称后面有一句隐藏的"10月3日至10月12日"(只有一天时是"10月5日";
describeRange可以换说法)。每条轨是一个以类目命名的分组,里面是列表;时间轴、引线、今天的竖线都对读屏隐藏。 - 高对比模式下底色都被系统换掉:没垫图的活动条目只剩名称块和类型标签,系统条目只剩名称和那条虚线——"位置就是信息",起止却看不出来了。每个条目补一圈 1px 的
CanvasText线。"今天"的竖线原来和引线、斜纹一起被当成装饰去掉了,但"今天在哪"是信息:它留着,用Highlight。引线和空档的斜纹照旧去掉。见 色彩。(推断) - 本库不带图。
media由使用方给,预览站里是原创的灰色占位图。
富文本里的语义着色#
游戏内的技能与效果描述会在正文里给机制词上色,并配一个小图标(社区):
- 数值用黄色或加粗;
- 机制、属性按固定的颜色映射着色。
用在组件库里:
- 同一个产品内,"颜色 → 含义"的映射必须唯一并写成表;
- 亮色表面上用各语义色的文字档(
danger、success、warning、info、accent-ink),不要直接用填充色; - 着色的词同时加粗或配图标,不只靠颜色。
已经做成组件 <Term tone icon>,渲染成 <strong>:
tone |
颜色 | 建议的含义 |
|---|---|---|
accent(默认) |
accent-ink |
数值、一般的强调 |
info |
info |
中性的机制 |
success |
success |
增益、获得 |
warning |
warning |
消耗、代价 |
danger |
danger |
伤害、减益 |
"建议的含义"只是起点:每个产品自己定一张表,然后全产品只用这一张。这些都是页面表面上的文字档颜色,压在反转块上不够亮,不要用在那里。
行为与无障碍#
- 表格用语义化的
<table>;表头用<th scope>;排序状态用aria-sort。 - 徽章如果承载信息(未读数),要有文字替代:"12 条未读"。
- 纯装饰的色条、菱形对辅助技术隐藏。
- 倒计时不要每秒播报;用
aria-live="off",并提供静态的截止时间。 - 图表提供文字摘要或数据表替代。
宜 / 忌#
宜
- 用形状区分"归档信息"与"可变状态"。
- 数字一律等宽、右对齐。
- 让一个数字成为主角。
忌
- 每个指标一张等大的卡片。
- 彩虹色的图例和标签。
- 用同一种胶囊徽章表达所有东西。
- 表格画满横竖线。
- 给标签加圆角渐变和图标"让它更好看"。
来源#
- 名值对、类型标签、加载页数字:measurements.md 第 8.13、9 节。
- 通知角标的菱形、公告页的日期与角标、商品卡的标签:measurements-cloud.md 第 8.2、8.12、9.4 节;对照见 云游戏页。
- 数据行带、数字语义色、徽章分工、富文本着色:Statrue/endfield-design-skill。
- 菱形时间线节点:VBeatDead/ReEnd-Components。