描述列表
把关于一件事物的已知信息呈现为一项项有名称的信息:一个低调的项名,加上回答它的值。项名可以在值的旁边、值的上方,或者在一个大数字的下方。它按自身的宽度布局,从不是控件。
- 类别
- 容器
- 令牌
comp.description-list- 层级
- 基础
- Web
tanrei-description-listschedule - SwiftUI
TanreiDescriptionListradio_button_unchecked - Jetpack Compose
TanreiDescriptionListradio_button_unchecked - Flutter
TanreiDescriptionListradio_button_unchecked - React Native
DescriptionListradio_button_unchecked
生成自 docs/status/status.json, specs/description-list.spec.json
一份订单的各项信息
- 订单号
- A-20418
- 下单时间
- 2026 年 10 月 6 日
- 收货地址
- 东京都港区芝公园 4-2-8
- 状态
- 合计
- 12,800 日元
描述列表展示一件事物的各项信息:一份订单、一个文件、一个账户、一个组件。每项信息由一个项名和回答它的值组成。项名是低调的标签,值才是用户要找的内容。
同样的信息可以用三种布局来绘制:
layout |
绘制什么 | 用于 |
|---|---|---|
inline(默认) |
项名在值的旁边。所有项名排在同一列,列宽与最宽的项名相同。 | 供人查阅的一组信息。 |
stacked |
项名在值的上方。 | 值或项名较长的情况,以及分成多列的信息。 |
stat |
值在前,画成一个大数字,项名在它下方作为标签。 | 屏幕开头的少数几个数字。 |
在 Web 上,它是包在你自己的原生 <dl> 外面的 <tanrei-description-list>。这个元素没有 shadow root,也不给列表任何角色,所以屏幕阅读器、爬虫和不运行脚本的页面遇到的都是一个普通的 HTML 描述列表。其他平台尚未实现。
<link rel="stylesheet" href="@tanrei/web/description-list.css" />
<tanrei-description-list>
<dl>
<div><dt>订单号</dt><dd>A-20418</dd></div>
<div><dt>负责人</dt><dd>田中爱子</dd><dd>萨米尔·哈达德</dd></div>
<div>
<dt>状态</dt>
<dd><tanrei-tag size="small" status="success" label="已发货"></tanrei-tag></dd>
</div>
</dl>
</tanrei-description-list>
<script type="module">
import '@tanrei/web/components/description-list';
</script>import { DescriptionList } from '@tanrei/react';
import '@tanrei/web/description-list.css';
<DescriptionList layout="stat" columns={3}>
<dl>
{figures.map((figure) => (
<div key={figure.label}>
<dt>{figure.label}</dt>
<dd>{figure.value}</dd>
</div>
))}
</dl>
</DescriptionList>@tanrei/web/description-list.css 在任何脚本运行之前就画出整个列表。元素自己也会把同一份样式表加进页面,所以只加载了脚本的页面同样能得到画好的列表,只是晚一会儿。
| 部件 | 在 Web 上 |
|---|---|
| 一项信息 | <dl> 里的一个 <div>,包住一个 <dt> 和它的各个 <dd>。 |
| 项名 | <dt>。里面是文本,或者一个由值来解释的组件(图例里的 Tag)。不要写冒号。 |
| 值 | 一个 <dd>。里面是文本、组件,或者什么都没有。 |
| 多个值 | 同一项信息里的多个 <dd>。每个值单独占一行。 |
有些 Markdown 渲染器输出的 <dl> 没有用 <div> 分组,这样的列表仍然会以单列绘制,采用 inline 或 stacked 布局。columns 和 stat 布局需要分组。
Stat:屏幕开头的几个数字
- 本周订单
- 1,284
- 比上周增长 12%
- 准时送达
- 98.6%
- 构建时间中位数
- 4 分 12 秒
Stacked 分列:列表变窄时,列数随之减少
- 计划中
- 已有规格,在这个平台上尚未实现。
- 待跟进
- 已实现,但落后于当前规格。
- Alpha
- 已实现并经过测试;API 仍可能变动。
- Beta
- API 已经确定;希望收到来自实际使用的反馈。
- Stable
- 受版本承诺的约束。
- 已弃用
- 仍在提供;已指明替代方案。
Compact,用留白分隔:供人扫读的信息
- 值
- #1b1c1e
- → ref.palette.neutral.10
- 种类
- 别名 · color
- 说明
- 任何表面或表面容器上的文本和字形。
构成
| 部件 | 说明 |
|---|---|
1 container | The list's box: as wide as its layout gives it, as tall as its facts. It has no fill, edge, corner or outer space of its own, and carries no state: nothing about it answers a pointer, a press or focus. |
2 fact | One term with the value or values that answer it. Facts are drawn in the order given: one under another, or in equal columns. |
3 term | The name of a fact, in a label style and a quieter color than its value: beside the value in a column all terms share, above it, or — in the stat layout — under it as the figure's label. Text, or a component of the product's (a tag that is explained by the value). |
4 value | What answers the term: text that wraps inside its column, or a component of the product's (a tag, a link, inline code, a button). A fact may have several, each on a line of its own. In the stat layout the first value is the figure, in a heading style. |
5 divider · 可选 | The one hairline between a fact and the fact below it, where facts are told apart by a line. |
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
layout | inline | stacked | stat | "inline" | How a fact is drawn. inline: the term beside its value, every term in one column as wide as the widest term; the list draws its terms above their values by itself while it is too narrow for that (DSL-4). stacked: the term above its value, for long values or long terms, and for facts in several columns. stat: the value first, as a large figure, with the term under it as its label — the few numbers a screen opens with. |
columns | number | 1 | The most columns of facts the list draws in the stacked and stat layouts; it draws fewer while it is too narrow for that many (DSL-7), and never more than it has facts. An inline list is one column whatever this says. |
density | regular | compact | "regular" | How close the facts are and how large their text is. Regular is for facts a person reads: a page, a card, a dialog. Compact (smaller text, half the space) is for facts a person scans: a side panel, an inspector, a card of many figures. A design system may add values. |
separation | auto | divider | gap | "auto" | How a fact is told from the fact below it. divider: one hairline between them. gap: empty space and no line. Auto takes comp.description-list.separation, the design system's answer (divider in the default system). |
条目
该组件重复排列的条目种类。测试样例按顺序列出条目;各平台以各自的惯用方式为每个种类命名。
fact · 分组 — 包含条目
One fact: a term, and the value or values that answer it.
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
term | string | "" | The fact's name, as short as it can be and without a colon ("Ships to"). In the stat layout it is the label under the figure ("orders this week"). |
| 插槽 | 说明 |
|---|---|
term | What the term holds in place of plain text: a tag that the value explains (a legend), inline code, text with a glyph. The list places it and styles nothing inside it (DSL-10). |
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 条目 | div | TanreiFact | fact | TanreiFact | DescriptionList.Fact |
term · 属性 | dt | term | term | term | term |
| 备注 | A <div> inside the <dl> that groups one <dt> (its children are the term: text, or the term slot's content) with its <dd>s. A second <dt> in one group keeps working as HTML and is drawn under the first. | TanreiFact("Category", value: "Actions"), or with view builders for the term and the values. | A call in the list's scope: fact("Category", "Actions"), or fact(term = { … }) { value { … } }. | TanreiFact(term: "Category", value: "Actions"); termChild: and values: take widgets. | term takes a string or an element; the children are the values. |
value · 分组 — 包含条目
One value of a fact: plain text, a component of the product's, or nothing.
| 插槽 | 说明 |
|---|---|
content | What the value holds in place of plain text: a tag, a link, inline code, a button, a short list, any view of the product's. The list places it and styles nothing inside it (DSL-10). |
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 条目 | dd | TanreiFactValue | value | TanreiFactValue | DescriptionList.Value |
| 备注 | A <dd>; its children are the content. | A string or a view builder; several in one fact's builder are several values. | value(text) or value { content } in a fact's scope. | TanreiFactValue.text("…") or TanreiFactValue(child: …). | Its children are a string or elements. A fact whose children are a string has that one value. |
tag
A tag placed in a value: the Tag component, as it is drawn anywhere else.
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
label | string | "" | The tag's text. |
variant | tonal | outlined | filled | "tonal" | The tag's look. |
status | default | info | warning | error | success | "default" | What the tag reports. |
size | small | medium | "medium" | The tag's size; small in a value, so that it does not make its line taller. |
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 条目 | tanrei-tag | TanreiTag | TanreiTag | TanreiTag | Tag |
label · 属性 | label | title | label | label | label |
variant · 属性 | variant | variant | variant | variant | variant |
status · 属性 | status | status | status | status | status |
size · 属性 | size | size | size | size | size |
状态
行为
以 EARS 形式写成的需求。每个平台的实现都按这些 ID 逐条测试。需求原文取自规格文件,原样以英文呈现。
| ID | 需求 |
|---|---|
DSL-1 | THE description list SHALL draw its facts in the order given, each fact a term and the value or values that answer it, as a block as wide as the layout gives it and as tall as its facts; it SHALL draw no fill, no edge, no corner and no elevation of its own, and SHALL bring no outer space of its own — no space above its first fact and none below its last — so that it is spaced by what holds it. |
DSL-2 | THE description list SHALL set every term in comp.description-list.term.typescale.regular while density is regular and in comp.description-list.term.typescale.compact while density is compact, in comp.description-list.term.color, and every value in comp.description-list.value.typescale.regular or comp.description-list.value.typescale.compact by density, in comp.description-list.value.color, with digits in figures of equal width so that the numbers of a column of values line up; it SHALL NOT add a colon or any other mark of its own after a term, and SHALL NOT change the weight, the case or the family of what the product wrote. |
DSL-3 | WHILE layout is inline THE description list SHALL draw one column of facts, and in each fact the term at the start and its values after it: every term in one term column, as wide as the widest term of the list set on one line, with no term wrapped or cut; every value in one value column that takes the rest of the list's width; and the two columns comp.description-list.term.gap.regular apart while density is regular and comp.description-list.term.gap.compact apart while density is compact. The first line of a term SHALL share its baseline with the first line of its first value. |
DSL-4 | WHILE layout is inline and the value column of DSL-3 would be narrower than comp.description-list.column.min-width THE description list SHALL draw every fact as layout stacked draws it (DSL-5) — all of its facts together, never some of them — and SHALL return to the two columns when the room is there again; it SHALL decide this from its own width, not from the window's, SHALL change at once and without a motion, and SHALL change nothing that is exposed (DSL-17). |
DSL-5 | WHILE layout is stacked THE description list SHALL draw in each fact the term on a line or lines of its own and its values below it after comp.description-list.stack.gap, both beginning at the start edge of the fact's column and no wider than it. |
DSL-6 | WHILE layout is stat THE description list SHALL draw in each fact the first value first, as a figure: in comp.description-list.stat.value.typescale.regular while density is regular and comp.description-list.stat.value.typescale.compact while density is compact, in comp.description-list.value.color, with digits in figures of equal width, on one line wherever the fact's column holds it; and the term below the figure after comp.description-list.stack.gap, in the term's own style and color (DSL-2), both beginning at the start edge of the fact's column. It SHALL set the figure's letter-spacing by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them. THE description list SHALL still expose the term before its value (DSL-17): the order it draws changes nothing that is read. |
DSL-7 | WHILE layout is stacked or stat THE description list SHALL lay its facts out in columns of equal width, comp.description-list.column.gap apart, filled row by row in reading order from the start edge, the facts of a row beginning at one top edge: as many columns as the least of columns, the number of its facts, and the number of columns at least comp.description-list.column.min-width wide that its own width holds, and never fewer than one; WHEN its width changes it SHALL lay its facts out again at once, without a motion. WHILE layout is inline and columns is greater than 1 THE description list SHALL draw one column and in debug builds report that an inline list has one. IF columns is less than 1 or not a whole number THE description list SHALL draw one column and in debug builds report the value. |
DSL-8 | THE description list SHALL wrap the text of a value inside its column, and of a term wherever DSL-5 or DSL-6 places it, breaking lines by the rules of the text's language, and SHALL never cut it or end it with an ellipsis; a run with no break opportunity that is wider than its column (an identifier, an address) SHALL be broken where it meets the column's edge rather than be cut or reach outside the list. |
DSL-9 | WHERE a fact has more than one value THE description list SHALL draw each value on a line or lines of its own below the one before it, comp.description-list.stack.gap apart, in the order given, where the layout places a value: in the value column while the term sits beside it, under the term while it is stacked. WHILE layout is stat only the first value SHALL be the figure of DSL-6; those after it SHALL be drawn below the term, after comp.description-list.stack.gap, in the value's own style (DSL-2). |
DSL-10 | WHERE a term or a value holds a component or any content of the product's that is not plain text — a tag, a link, inline code, a button, a short list — THE description list SHALL place it where the text would begin, on the first line, SHALL add nothing to it and style nothing inside it, and SHALL let pointer, touch and keyboard input reach it as it would outside the list, in the reading order of the facts. |
DSL-11 | WHERE a fact has a term and no value, or a value with no content, THE description list SHALL draw the term, keep the value's place and one line of its height so that the fact stays in step with the others, expose the fact with an empty value, and SHALL NOT put a dash, a word or any other mark of its own in it. IF a fact has no term THE description list SHALL draw its values where they would be and in debug builds report that a value has no term. IF the list has no facts THE description list SHALL draw nothing, take no space and expose nothing. |
DSL-12 | WHILE the list's separation is divider (DSL-13) THE description list SHALL draw one line of comp.description-list.divider.thickness in comp.description-list.divider.color above every fact that is not in its first row, as wide as that fact's column — the whole width of the list where it draws one column, a term and its value under one line — and SHALL leave comp.description-list.fact.gap.regular between the line and the content on each side of it while density is regular, and comp.description-list.fact.gap.compact while density is compact, the line taking no room of its own; it SHALL draw no line above the first row or below the last, and none between two columns or between a term and its value. |
DSL-13 | THE description list SHALL tell a fact from the fact below it as its separation names: WHILE separation is auto, as comp.description-list.separation names, which follows sys.behavior.separation unless a design system sets it apart; WHILE separation is divider or gap, as that value names, whatever the tokens say; divider draws the lines of DSL-12 and gap leaves the space of DSL-14. WHEN separation, or the token it follows, changes THE description list SHALL draw the other form at once, without animation; WHEN separation names a value the description list does not define THE description list SHALL treat it as auto and in debug builds report the unknown value. A platform that cannot draw a choice SHALL fall back to the first value, divider, and state that in its README. |
DSL-14 | WHILE the list's separation is gap (DSL-13) THE description list SHALL leave comp.description-list.fact.gap.regular of empty space while density is regular, and comp.description-list.fact.gap.compact while density is compact, between every fact and the fact below it, SHALL draw none of the lines of DSL-12, and SHALL leave no such space above the first row or below the last; the facts SHALL stay exposed as facts (DSL-17). |
DSL-15 | THE description list, its facts, its terms and its values SHALL NOT take pointer, touch or keyboard input of their own, SHALL NOT take focus or be a stop in the focus order, and SHALL NOT change anything they draw under a pointer, a press or focus: a fact has no hovered, focused, pressed, selected or disabled state, draws no state layer and no focus indicator, and the list emits no event. |
DSL-16 | WHEN the facts, a term or a value change THE description list SHALL draw the new content at once, without a motion, lay itself out again where a width changed with it (DSL-3, DSL-4, DSL-7), and SHALL NOT announce the change by itself. |
DSL-17 | THE description list SHALL be exposed to assistive technology as terms each followed by the value or values that answer it, every value associated with its term, in the order given: on a platform that has the semantics of a description list, as that structure; on a platform that has none, each fact as one element whose text is the term followed by its values, set apart so that they are read as separate phrases ("Category, Actions"), with whatever inside the fact takes input still reached as an element of its own. The layout, the number of columns, the density, the separation and the order DSL-6 draws SHALL change nothing that is exposed; THE description list SHALL give a term no heading role and itself no name. |
DSL-18 | THE description list SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the description list is shown THE description list SHALL draw itself for the new direction at once, without a motion of its own, keeping what it shows. |
DSL-19 | WHERE the layout direction is right-to-left THE description list SHALL place the term column at the right and the value column at its left, begin every term and every value at the right edge of its column, fill its columns of facts from the right, and apply every gap by logical start and end. It draws no glyph of its own, so nothing in it is mirrored but its order. |
DSL-20 | THE description list SHALL lay out the text of each term and of each value as text of its own direction, isolated from the text beside it: it takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right name, an identifier, a number with its sign, unit or currency, a version, an address and a date keep their own order in a right-to-left layout and reorder nothing beside them; THE description list SHALL place that text and align its lines by the layout direction, not by the text's own, and SHALL NOT reverse the digits of a number. |
DSL-21 | WHILE the text size is enlarged THE description list SHALL grow every text style with it, keep its gaps and its lines, take comp.description-list.column.min-width as grown by the same factor, and lay itself out again by DSL-3, DSL-4 and DSL-7, so that an inline list draws its terms above their values and a list in columns draws fewer of them where the larger text no longer fits; it SHALL cut no content, SHALL set no fixed height on a fact, SHALL lose no content when the reader raises line height, paragraph spacing, letter spacing or word spacing, and SHALL need no sideways scrolling at a width of 320 points with text at 200 %. |
DSL-22 | WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE description list SHALL draw the lines of DSL-12 in the platform's text color and its terms and values in that color, a term still told from its value by its text style and its place; it draws no fill, so nothing else changes. |
DSL-23 | WHEN density names a value that the active design system does not have, or layout names a value this spec does not have, THE description list SHALL render with the default value (the default density's tokens, layout inline), and in debug builds report the unknown value. |
DSL-24 | WHEN its inline size changes THE description list SHALL choose between terms beside and above their values again from the new size. |
各平台名称对照
对等并不意味着 API 完全相同。同一份契约,由各平台以自己的惯用方式表达。
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 组件 | tanrei-description-list | TanreiDescriptionList | TanreiDescriptionList | TanreiDescriptionList | DescriptionList |
layout · 属性 | layout | layout | layout | layout | layout |
columns · 属性 | columns | columns | columns | columns | columns |
density · 属性 | density | density | density | density | density |
separation · 属性 | separation | separation | separation | separation | separation |
| 备注 | It is the form the table takes. <tanrei-description-list> is a custom element with **no shadow root**, wrapped around the product's native <dl>, which stays in the light DOM — <tanrei-description-list layout="stacked" columns="3"><dl><div><dt>Category</dt><dd>Actions</dd></div>…</dl></tanrei-description-list>. The dl, dt and dd are never given a role, so the description-list semantics are the browser's own, for a screen reader, a crawler and a page without script alike (DSL-17). Everything drawn comes from one stylesheet, @tanrei/web/description-list.css, whose selectors start at tanrei-description-list and are wrapped in :where(); it styles the page before and without script (an element that is not yet defined is still an element), and the element adopts the same sheet into the root it is connected to, so it also works inside another component's shadow root. Props are attributes of the wrapper: layout, columns, density, separation. The wrapper is display: block; container-type: inline-size with no margin; the dl has its browser margins removed and every dd its inset. inline (DSL-3): the dl is a grid of max-content minmax(0, 1fr) and each group a subgrid row spanning both tracks, align-items: first baseline. DSL-4 needs the widest term's width, which CSS cannot compare with the container's: the element watches its own box and its terms with a ResizeObserver and sets data-stacked while the value column would be under the least width; without script the term track is fit-content(50%), so a list that is too narrow wraps its terms instead of stacking — nothing is cut. stacked and stat columns (DSL-7) are pure CSS: grid-template-columns: repeat(auto-fit, minmax(min(100%, max(<least width>, (100% - (n - 1) * <gap>) / n)), 1fr)), n coming from attribute selectors for columns 2 to 6 and from a custom property the element sets for larger numbers; auto-fit already draws no more columns than facts. The least width is the token multiplied by the reader's text scale (the root font size over 16), so that it grows with enlarged text (DSL-21). stat (DSL-6): each group is a column-direction flex box with order on the dd:first-of-type, so the dt stays before its dd in the document while the figure is drawn first. Lines (DSL-12) are border-block-start on each group with the same negative margin and overflow: clip on the dl, so the first row's lines are not drawn and no script counts rows. font-variant-numeric: tabular-nums and overflow-wrap: anywhere on dd (DSL-2, DSL-8); unicode-bidi: plaintext on dt and dd (DSL-20); under :lang(ja, zh, ko) a stat figure's letter-spacing is 0 and line-break: strict applies. Under forced-colors: active the lines are CanvasText (DSL-22). A dl without groups — bare dt and dd children, as some Markdown extensions emit — is drawn in one column, inline or stacked, with the line above each dt that follows a dd; columns and stat need the groups, and debug builds say so. Tanrei does not transform content: nothing wraps a bare dl by itself. Inside .tanrei-prose the element is an island by its tag name (PRS-16): prose spaces it and styles nothing inside it, while a bare dl beside it stays prose's (PRS-13). | Proposed spelling, for the platform's agent to settle. TanreiDescriptionList(layout: .stacked, columns: 3, density:, separation:) { TanreiFact("Category", value: "Actions"); TanreiFact("Status") { TanreiTag("Stable", status: .success, size: .small) } }. A custom Layout measures the terms once (DSL-3), compares what is left with the least width (DSL-4) and places the facts in equal columns (DSL-7); it is proposed its own width, so the decision is the container's. The least width is a @ScaledMetric. Not a Form, a LabeledContent or a List: each brings a look, insets or a row behaviour of its own. Accessibility: SwiftUI has no description-list container, so DSL-17's fallback applies — each fact is accessibilityElement(children: .combine) with the term's text before the values', a control inside a value stays an element of its own, and the stat layout sorts the term first with accessibilitySortPriority. | Proposed spelling, for the platform's agent to settle. TanreiDescriptionList(layout = Stacked, columns = 3) { fact("Category", "Actions"); fact("Status") { value { TanreiTag("Stable", status = Success, size = Small) } } }. A custom Layout (or SubcomposeLayout) measures the terms' intrinsic widths, decides DSL-4 and DSL-7 from its own constraints, and aligns the first baselines; the least width is converted with the font scale. No ListItem: it is a pressable row with a look of its own. Semantics: each fact is semantics(mergeDescendants = true) with a contentDescription of the term and its values joined by commas, the term first in every layout; a clickable inside a value is not merged. | Proposed spelling, for the platform's agent to settle. TanreiDescriptionList(layout: TanreiDescriptionListLayout.stacked, columns: 3, facts: [TanreiFact(term: "Category", value: "Actions")]). A LayoutBuilder gives the list its own width; the term column is measured with a TextPainter over the terms (or a custom RenderBox with intrinsic widths where a term holds a widget), and the least width is multiplied by the TextScaler. Not a Table, a ListTile or a DataTable. Semantics: one MergeSemantics per fact with a label of the term and its values joined by commas and sortKeys that put the term first in the stat layout; a control inside a value keeps its own node. | Proposed spelling, for the platform's agent to settle. <DescriptionList layout="stacked" columns={3}><DescriptionList.Fact term="Category">Actions</DescriptionList.Fact></DescriptionList>. The list's own width comes from onLayout, and the widest term from a first measuring pass, so the first frame of an inline list is drawn after measuring; columns are flexBasis percentages computed from that width, and the least width is multiplied by the font scale. Each fact is one accessible view with accessibilityRole="text" and an accessibilityLabel of the term and its values joined by commas, the term first in every layout; a pressable inside a value stays its own element. Follows the app's direction where an ancestor's is not known. |
令牌
| 令牌 | 引用 | 解析值(浅色) |
|---|---|---|
--tanrei-comp-description-list-column-gap | sys.space.space400 | 32px |
--tanrei-comp-description-list-column-min-width | — | 144px |
--tanrei-comp-description-list-divider-color | sys.color.outline-variant | |
--tanrei-comp-description-list-divider-thickness | sys.border.hairline | 1px |
--tanrei-comp-description-list-fact-gap-compact | — | 6px |
--tanrei-comp-description-list-fact-gap-regular | — | 12px |
--tanrei-comp-description-list-separation | sys.behavior.separation | 0 |
--tanrei-comp-description-list-stack-gap | sys.space.space50 | 4px |
--tanrei-comp-description-list-term-color | sys.color.on-surface-variant | |
--tanrei-comp-description-list-term-gap-compact | sys.space.space100 | 8px |
--tanrei-comp-description-list-term-gap-regular | sys.space.space200 | 16px |
--tanrei-comp-description-list-value-color | sys.color.on-surface | |
--tanrei-comp-description-list-stat-value-typescale-compact | sys.typescale.heading-3 | 500 20px/1.4 |
--tanrei-comp-description-list-stat-value-typescale-regular | sys.typescale.heading-1 | 500 32px/1.25 |
--tanrei-comp-description-list-term-typescale-compact | sys.typescale.label-small | 500 12px/1.3333 |
--tanrei-comp-description-list-term-typescale-regular | sys.typescale.label | 500 14px/1.4286 |
--tanrei-comp-description-list-value-typescale-compact | sys.typescale.body-small | 400 13px/1.5385 |
--tanrei-comp-description-list-value-typescale-regular | sys.typescale.body | 400 14px/1.5714 |
测试样例
作为基准的渲染结果。所有平台都以相同的 ID 为每个样例截取快照,以便相互比较。
density: regular (22)
inline
items: 4 inline-long-values
items: 3 inline-falls-back
items: 2 stacked
layout: stacked items: 3 several-values
items: 3 tags
items: 4 empty-value
items: 4 unbreakable
items: 2 columns
layout: stacked columns: 3 items: 3 columns-legend
layout: stacked columns: 3 items: 6 stat
layout: stat columns: 4 items: 4 stat-single
layout: stat items: 1 stat-note
layout: stat columns: 2 items: 2 separation-divider
separation: divider items: 4 separation-gap
separation: gap items: 4 separation-divider-columns
layout: stacked columns: 2 separation: divider items: 4 separation-gap-stat
layout: stat columns: 4 separation: gap items: 4 japanese
items: 4 japanese-stat
layout: stat columns: 4 items: 4 rtl
direction: rtl items: 4 rtl-stat
layout: stat columns: 3 direction: rtl items: 3 ltr-values-rtl
direction: rtl items: 3 density: compact (4)
inline-compact
density: compact items: 5 stacked-compact
layout: stacked density: compact items: 3 columns-compact
layout: stacked columns: 4 density: compact items: 4 stat-compact
layout: stat columns: 3 density: compact items: 3 生成自 specs/description-list.spec.json, tokens/comp/description-list.tokens.json, design/tokens/
- 用它来呈现一件事物的各项信息。几件事物共用同一组名称时,应该用表格,由表头为各列命名。
- 夹在段落之间、按顺序阅读的词语解释属于长文排版:让它在你的内容里保持为一个裸的
<dl>。长文排版把它排成连续文本,突出的是词语。这个组件是同一种列表经过布局的形态,突出的是值。 - 供人从中选择或按下的列表,是列表。
列表的一切都由它自身的宽度决定,而不是窗口的宽度。同一个列表放在页面、卡片、侧边面板和对话框里都合适。
- Inline 会自行改为上下排列。 当最宽的项名旁边留给值的宽度不足 144 时,所有信息项会一起改为项名在上、值在下,等空间足够时再恢复成两列。每当宽度变化时,列表都会重新判断;最初在尚未显示的面板或标签页中、没有宽度时布局的列表也是如此。不要因为窗口小就自己切换布局。
- 列数会自行减少。
columns是 stacked 和 stat 布局最多绘制的列数。每列至少宽 144,所以四个数字在宽页面上是四列,在窄页面上是两行各两列,在手机上是一列。列表的列数绝不会多于信息项的数量。 - Inline 列表只有一列。
columns对它不起作用。 - 什么都不截断。 值会换行。无法断开的标识符或地址会在列的边缘断开。列表绝不横向滚动。
density |
项名和值 | 信息项之间 | 用于 |
|---|---|---|---|
regular(默认) |
14,行高 20;以及 14,行高 22 | 12;有线时,线的两侧各 12 | 供人阅读的信息:页面、卡片、对话框。 |
compact |
12,行高 16;以及 13,行高 20 | 6;有线时,线的两侧各 6 | 供人扫读的信息:侧边面板、检查器。 |
stat 的数字在 regular 时是 32,行高 40;在 compact 时是 20,行高 28。
separation |
绘制什么 |
|---|---|
auto(默认) |
设计系统选定的方式:在默认系统中是一道细线。 |
divider |
每项信息与它下面那一项之间一道细线。 |
gap |
留空,不画线。 |
第一行上方、最后一行下方、两列之间以及项名和它的值之间都没有线。需要外框的列表,就把列表放进一张带轮廓的卡片。
- 项名越短越好:写“收货地址”,而不是“这份订单寄往的地址”。
- 如果“没有”本身就是信息,就用文字把它写出来:“无”“未设置”“不限”。
- 用文字说明变化:在数字下方加第二个值,写“比上周增长 12%”。
- 值里的状态用小号 Tag(
size="small"),这样它不会把所在的行撑高。
- 不要在项名后面加冒号。标点属于语言,而项名靠样式和位置就已经与它的值区分开了。
- 不要在空值里放破折号。让它留空,或者把“没有”写出来。
- 不要用颜色来表示一个数字是好是坏。方向用一个词来说,或者用一个标签文字说出了它的 Tag。
- 不要用这个列表把互不相关的东西并排摆放。那是布局的事。
- 角色
none- 标注
- WAI-ARIA has no role for a description list as a whole, only for its parts (term, definition), so the component names none: on the web the product's own dl, dt and dd stay in the document and carry the structure; elsewhere each fact is one element read "term, value" (DSL-17). The list has no accessible name of its own: the heading above it says what the facts are about, as it does for a person who sees them.
- 最小目标
- 即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px
键盘操作
| 按键 | 动作 |
|---|
备注
- Not interactive: the list, its facts, its terms and its values take no input and no focus (DSL-15), so there is no target to size. minimumTarget holds trivially. What is pressable inside a value — a link, a button, a copy button — meets the minimum target by its own spec and keeps its place in the focus order.
- A description list is for the facts of one thing (WCAG 1.3.1): each term names what its value is. Several things that share the same names are a table, whose headers name columns; text that is read in order, with a term now and then, is prose, which sets a bare description list as running text (PRS-13). Do not use this component to place unrelated things side by side.
- Every value has a term, and a term is a name, not a heading: it takes no heading role (DSL-17), so a screen reader's list of headings is not filled with "Size", "Owner" and "Date". A block of facts that needs a title gets a heading above it, which the product writes.
- What is drawn first is not always what is read first: the stat layout draws the figure above its label and still exposes "orders this week, 1,284" (DSL-6). Both orders are a meaningful sequence (WCAG 1.3.2); the exposed one is the same in every layout, so that a person hears a list the same way wherever it is drawn.
- An empty value is exposed as empty (DSL-11). Where the absence itself is information ("None", "Not set", "Unlimited"), write it as the value, in words: a dash is read as punctuation or not at all.
- Meaning never rests on color. A figure is the surface's text color whatever it says; a change (up, down, better, worse) is a tag or text in the value whose words say the direction ("up 12 % since last week"), with a glyph if the product wants one, never a color alone (WCAG 1.4.1).
- Reflow (WCAG 1.4.10) and enlarged text (1.4.4, 1.4.12): the list decides its layout from its own width, so the same rules that stack it in a narrow panel stack it at 200 % text and in a 320 wide window (DSL-4, DSL-7, DSL-21). Nothing is cut and nothing scrolls sideways; an unbreakable value is broken at the edge (DSL-8).
- Contrast in the default system: a value is on-surface and a term on-surface-variant, each held to 4.5:1 on every surface and container step by the token invariants. The line between facts is decorative: facts are exposed without it.
- A list does not announce a change of its facts (DSL-16). Where a change must be heard (a figure that updates while the person watches), the product puts the list, or the one fact, in a live region and decides how often it speaks.
生成自 specs/description-list.spec.json, tokens/sys/measure.tokens.json
- 原生列表始终是描述列表:项名和它们的定义都是浏览器自己的,无论采用哪种布局、哪种密度、有没有线。
- 朗读的顺序从不改变。stat 布局把数字画在它的标签上方,但向辅助技术提供时仍然是项名在前。
- 列表里没有任何东西会获得焦点或接受输入。值里的链接或按钮保留自己的目标尺寸和在焦点顺序中的位置。
- 文本放大到 200% 时,以及在宽 320 的窗口里,同样的宽度规则会让列表改为上下排列并减少列数。最小宽度随文本一起变大。
- 在从右到左的布局中,项名那一列位于右侧,各列从右侧排起。每个项名和值保持自己的方向,所以版本号、地址和金额绝不会被颠倒。
- 在强制颜色模式下,线和文本都是文本颜色。列表没有会被去掉的填充。
- 没有项名的值、写在 inline 列表上的
columns、不是整数的列数、在没有分组的列表上使用 stat 布局或多列,以及未知的布局、密度或分隔方式,会在调试构建中报告。
- 在列表上方放一个标题,说明这些信息是关于什么的。列表没有自己的名称,项名也从不是标题。
- 给每个值一个项名。
- 如果某个数字会在用户注视时变化,并且这个变化必须让人听到,请把列表或那一项信息放进你自己的实时区域(live region)。列表不会朗读变化。