跳到主要内容
menumenu tanreiexpand_morecontrasttranslate
tanreiexpand_more
开始使用WebReactSwiftUIJetpack ComposeFlutterReact Native预设你自己的设计系统与 AI 代理一起使用 Tanrei品牌设计令牌设计系统与定制Theme Studio颜色字体排印图标形状层级动效交互状态行为布局无障碍文字颜色令牌字阶令牌形状令牌层级令牌动效令牌状态令牌间距与度量令牌组件按钮主操作按钮分段按钮按钮组带菜单的按钮工具栏复制按钮复选框单选按钮开关纸片(Chip)菜单滑块滑块字段日历DateTimePicker字段组单选组复选框组下拉选择框下拉选择字段菜单栏文件上传文件选择器 进阶放置区文本输入框 进阶文本字段纸片字段字段组合框 进阶组合框字段数字输入框 进阶数字字段颜色输入框 进阶颜色字段一次性验证码输入框 进阶一次性验证码字段嵌入式文本输入框 进阶聊天输入栏卡片分隔线模态层 进阶对话框列表列表行底部面板侧边面板轮播代码块表格弹出框步骤折叠面板描述列表图示应用外壳页头树视图时间线图片预览调整手柄可调整大小的框滚动区域徽标进度指示器计量条数字滚动器加载指示器消息条(Snackbar)工具提示键盘快捷键标签(Tag)行内代码提示块(Callout)头像空状态标签组(Tag group)骨架屏文件项色块跑马灯文本标签页标签页视图应用栏导航栏导航抽屉搜索链接分页上一页/下一页链接步骤条面包屑目录链接卡片FAB 菜单状态Tanrei 是如何构建的参与贡献许可与致谢
首页组件步骤

步骤

把一套操作流程写成带编号的步骤:每一步有一个写着编号的圆环、可选的标题和由你的内容构成的正文,并用一道细线与下一步相连。它是供人阅读的有序列表,从不是控件,也从不记录进度。

content_copy以 Markdown 格式查看
类别
容器
令牌
comp.steps
层级
基础

概览

Web
tanrei-steps
schedule
SwiftUI
TanreiSteps
radio_button_unchecked
Jetpack Compose
TanreiSteps
radio_button_unchecked
Flutter
TanreiSteps
radio_button_unchecked
React Native
Steps
radio_button_unchecked

生成自 docs/status/status.json, specs/steps.spec.json

标题和正文

  1. 提案

    编写或修改规格;改动需要令牌时,一并修改令牌。

  2. 验证

    检查各个 schema、令牌规则和每种配色方案的对比度。

  3. 生成

    重新生成令牌输出、脚手架和状态矩阵。

有三样东西看起来相似,却并不相同:

组件 它是什么 有没有状态 表达的意思
有序列表(长文排版) 按顺序排列的项,每项是一个短语或一句话 没有 “这些,按这个顺序”
步骤 供人阅读、再到别处去执行的一套操作流程 没有 “先做这个,再做这个”
步骤条(stepper) 用户在产品所运行的流程中走到了哪里 有 “你在这里”

步骤没有当前步骤、已完成步骤或失败步骤,标记也不是控件。结账流程或设置向导需要的是步骤条,Tanrei 目前还没有这个组件。

用法

在 Web 上,步骤是加在你自己的有序列表上的一个类,而不是一个元素。在任何脚本运行之前,这个列表就是文档里的列表;Markdown 渲染器输出的 <ol> 只需要一个类,不需要包裹元素;没有样式表时,它就是浏览器的编号列表。

SwiftUI、Compose、Flutter 和 React Native 尚在计划中:本页开头各平台旁边的名称是规格为它们定下的,这些平台目前还没有提供任何实现。React 也还没有 Steps 组件,请使用加了这个类的列表。

<link rel="stylesheet" href="@tanrei/web/tokens.css" />
<link rel="stylesheet" href="@tanrei/web/steps.css" />

<!-- 在控件之间:面板、对话框、卡片。 -->
<ol class="tanrei-steps" role="list">
  <li>把文件保存到存放项目设置的文件夹中。</li>
  <li>在设置中指定这个文件的名称。</li>
  <li>运行构建,并提交它写出的内容。</li>
</ol>

<!-- 在阅读型页面上,带标题,接续前面的一组步骤。 -->
<ol class="tanrei-steps" role="list" data-size="large" start="4" aria-label="工作流程(续)">
  <li>
    <p class="tanrei-steps-title">实现</p>
    <p>在规格列出的每个平台上完成这项改动。</p>
  </li>
  <li>
    <!-- 标题同时是页面的标题元素:它保留自己的角色和级别。 -->
    <h3 id="check">检查</h3>
    <p>按顺序运行每一项检查。</p>
    <pre><code>pnpm check</code></pre>
  </li>
</ol>

<script type="module">
  // 可选:编号达到三位数的一组步骤的标记列宽度、运行时 `start` 变化后的重新编号,
  // 以及调试报告。`@tanrei/web` 也会加载它。
  import '@tanrei/web/steps';
</script>
import '@tanrei/web/steps.css';

<ol className="tanrei-steps" role="list" data-size="large">
  <li>
    <p className="tanrei-steps-title">安装</p>
    <p>把这个包添加到项目中。</p>
  </li>
</ol>
属性 在 Web 上
label aria-label(或者用 aria-labelledby 指向列表前面的标题元素)
start 列表自己的 start
size: large data-size="large"
一个步骤 <li>
步骤的 title 列表项中带 class="tanrei-steps-title" 的第一个子元素(一个 <p>)
标题插槽 作为列表项第一个子元素的标题元素(h2 到 h6)

请在列表上写 role="list":有一种浏览器引擎会在列表的标记被去掉后丢掉它的列表语义。

规格

每步一行,以及一组接续的步骤

  1. 把文件保存到存放项目设置的文件夹中。
  2. 在设置中设计层对应的键下,指定这个文件的名称。
  3. 运行构建,并提交它写出的内容。
  1. 9 仍然是圆形。
  2. 10 也是。
  3. 11 同样如此:三步的内容都从同一条边开始。

大尺寸,正文里有一个块

  1. 把这个包添加到项目中。

    npm install @tanrei/web
  2. 在页面的其他任何样式之前,加载一次样式表。

  • 标记是一个用系统细线画出的圆环,里面是步骤的编号;中号时直径 24,大号时 28。一位或两位数字时它保持圆形;更长的编号会把它撑宽成胶囊形,而每个步骤的内容仍然从同一条边开始。
  • 连接线从每个圆环通向下一个圆环,两端都不与圆环相接。最后一步没有连接线。
  • 标题是可选的。它是所在步骤的文本,而不是标题元素,除非你把一个标题元素作为列表项的第一个子元素:这时它会像任何标题一样绘制,并保留自己的角色和级别,于是这个步骤会出现在页面大纲里。
  • 正文是你的内容。两个块之间相距 8,两个步骤之间相距 16。不是文本的块(代码块、表格、标签页、提示块)占满正文的整个宽度。
  • 尺寸就是长文排版的那两种:在控件之间用中号,在以文本为主的页面上用大号。位于长文排版内部的步骤采用这段长文排版的尺寸。
  • 颜色:编号、标题和正文采用步骤所在表面的内容颜色。圆环和连接线都用系统唯一的那种细线颜色绘制。没有任何部分带填充。

构成

部件 说明
1 list The ordered list itself: one column of steps, as wide as its container gives it. It has no fill, no edge, no padding and no state of its own, and it brings no text color.
2 step One item of the list: its marker at the start, and beside it its content — a title, where it has one, and a body. A step has no state: none is current, done or failed.
3 marker What begins a step: a ring in the system's one hairline holding the step's number. At least as high and as wide as the marker's height of the size; a circle in the default system, widened into a pill by a number too long for one. The ring is decorative; the number is the step's number, exposed once with the list item.
4 connector · 可选 The line from a step's marker to the next step's: the same hairline, on the marker column's centre line, kept a small distance from both rings. It shows that the steps are one sequence and where a step of several blocks ends. Decorative. The last step has none.
5 title · 可选 A step's name, in a few words ("Install", "Say where each output goes"), set at the body's size in a heading weight. Text of its step and not a heading, unless the product gives a heading of its own as the title.
6 body · 可选 A step's content: what the product puts in it. Text placed directly takes the body's text style; long-form blocks are set as prose; a block that is not text — a code block, a table, tabs — takes the body's whole width.

属性

属性 类型 默认值 说明
label string "" The list's accessible name, in the product's language ("Installing the package"). Not drawn. Give one where no heading directly before the steps already says what the procedure is.
start number 1 The number of the first step; each following step's number is one more. For a procedure that a note, a heading or a choice between tabs interrupts and that continues in a second set of steps ("4, 5, 6"). A whole number.
size medium | large "medium" The size of the steps' text, in prose's two sizes. Medium sets the body in the interface's own text style, for steps among controls: a panel, a dialog, a card. Large sets it in the style for long reading, for a page whose purpose is the text. Steps inside a prose are given that prose's size. A design system may add values.

条目

该组件重复排列的条目种类。测试样例按顺序列出条目;各平台以各自的惯用方式为每个种类命名。

step

One step of the procedure: an optional title and a body. Its number comes from its place in the list and from start, never from a prop of its own.

属性 类型 默认值 说明
title string "" The step's name, in a few words. Plain text: drawn first in the step, read with the step, and not a heading. A title that is a heading of the page is given in the title slot instead.
插槽 说明
title The title as content of the product's own: a heading of the level the page's outline needs (so the step is in the page's table of contents and can be linked to). Drawn in the title's text style whatever its level; its role and level are kept. Takes the place of the title prop.
规格 Web SwiftUI Jetpack Compose Flutter React Native
条目 li TanreiStep TanreiStep TanreiStep Step
title · 属性 tanrei-steps-title title title title title
备注 An <li> of the list; its children are the body. The title is the item's first child where that child is a heading (h2 to h6) or carries class="tanrei-steps-title" (a <p> for a title that is not a heading): the spec's title prop and its title slot are the same element on this platform, told apart by the tag the product chose. TanreiStep(_ title: String? = nil) { body } in the steps' view builder; TanreiStep(title: { Text(…).accessibilityAddTraits(.isHeader) }) { body } is the title slot. TanreiStep(title: String? = null) { body } in TanreiStepsScope; an overload takes title: @Composable () -> Unit with Modifier.semantics { heading() } for the title slot. TanreiStep(title: 'Install', child: …); titleWidget: takes a widget wrapped in Semantics(header: true) for the title slot. <Step title="Install">…</Step>; title also takes an element with accessibilityRole="header" for the title slot.

状态

行为

以 EARS 形式写成的需求。每个平台的实现都按这些 ID 逐条测试。需求原文取自规格文件,原样以英文呈现。

ID 需求
STP-1 THE steps SHALL lay out its steps in one column, in the order they are given, each step a row of two parts: its marker, in a column at the steps' start edge, and its content — its title, where it has one, and its body — beside it. The marker column SHALL be as wide as the widest marker of the set and never narrower than the marker's height of the size (comp.steps.marker.height.medium for medium, comp.steps.marker.height.large for large), each marker centred in it; every step's content SHALL begin at one edge, comp.steps.marker.gap after that column, and run to the steps' end edge. THE steps SHALL separate the end of one step from the beginning of the next by comp.steps.step.gap, SHALL give the first step no space before it and the last step no space after it, and SHALL draw no fill, no edge around itself and no elevation.
STP-2 THE steps SHALL draw each step's marker as a ring with the step's number at its centre: a box at least comp.steps.marker.height.medium high and wide for medium (comp.steps.marker.height.large for large), with corners comp.steps.marker.shape, never larger than half the box's height and eased by sys.shape.corner-smoothing, no fill, and an edge comp.steps.marker.outline.width wide in comp.steps.marker.outline.color drawn inside the box's size; the number SHALL be set on one line in comp.steps.marker.label.typescale.medium for medium (comp.steps.marker.label.typescale.large for large), in the content color of the surface the steps sit on, with at least comp.steps.marker.padding-inline between it and the ring at the start and at the end, so that a number too long for a circle widens its marker into a pill and is never cut.
STP-3 THE steps SHALL place each marker at the top of its step with its centre on the centre of the step's first line of text — the title's first line where the step has a title, else the first line of the body; WHERE the marker is taller than that line THE steps SHALL lower the step's content by half the difference, so that the marker's top is the step's top and no marker reaches into the space above its step; WHERE a step begins with a block that is not text (a code block, a table, a picture) THE steps SHALL place the marker's top on that block's top.
STP-4 THE steps SHALL number its steps in order: the first step's number is start and each following step's is one more than the one before it. THE number SHALL be written as a whole number in the digits 0 to 9, with no period, bracket or other mark beside it and no word before it. WHEN a step is added, removed or moved, or start changes, THE steps SHALL draw every step's new number at once, without a motion.
STP-5 WHILE a step is followed by another step THE steps SHALL draw a connector between their two markers: a straight line comp.steps.connector.thickness thick in comp.steps.connector.color, on the centre line of the marker column, from comp.steps.connector.gap below the upper marker's bottom edge to comp.steps.connector.gap above the lower marker's top edge, through the space between the two steps, however tall the upper step's content is. THE steps SHALL draw no connector after the last step and none for a set of one step; a connector SHALL take no room in the layout, SHALL never be drawn over a marker or over a step's content, and SHALL be kept from assistive technology.
STP-6 WHERE a step has a title THE steps SHALL draw it first in the step's content, in comp.steps.title.typescale.medium for medium (comp.steps.title.typescale.large for large) and the content color of the surface the steps sit on, SHALL wrap it and never cut it, and SHALL begin the step's body comp.steps.title.gap below it. A title given as text SHALL be exposed as text of its step and SHALL NOT be a heading; WHERE the product gives the title as content of its own in the step's title slot — a heading of the level its page's outline needs — THE steps SHALL draw it as any title, in the same text style whatever its level, and SHALL change neither its role nor its level. A step with a title and no body SHALL be drawn as its marker and its title alone. THE steps SHALL set the title'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.
STP-7 THE steps SHALL draw the content a step is given as that step's body and SHALL give it comp.steps.body.typescale.medium for medium (comp.steps.body.typescale.large for large) as the text style its text takes where nothing inside sets another. THE steps SHALL give the body no color of its own: its text takes the content color of the surface the steps sit on, so the same steps read on a page, in a card and in a callout. The body SHALL wrap and SHALL never be cut or limited to a number of lines. WHERE the body holds more than one block THE steps SHALL separate two blocks that follow each other by comp.steps.body.gap, whatever they are, and SHALL give the first block no space before it and the last block no space after it; the body's long-form blocks — paragraphs, lists, a quote — SHALL otherwise be set as prose of the steps' size sets them (PRS-1 to PRS-3, PRS-19), a link in them SHALL be underlined at rest (PRS-17), and THE steps SHALL add no style to anything inside a component placed in a body.
STP-8 THE steps SHALL give every block of a body that is not text — a code block, a table, a set of tabs, a callout, a figure or a picture, any component — the whole inline size of the body, from the edge every step's content begins at (STP-1) to the steps' end edge, and such a block SHALL scroll inside its own box when its content cannot shrink (PRS-15). WHILE the steps sit in a prose that keeps a measure THE steps themselves SHALL take that prose's full width as a block that is not text (PRS-18), and the text blocks of a body SHALL be kept no wider than comp.prose.measure times their font size, from the body's start edge; WHERE the steps sit outside a prose, or in one without a measure, every block of a body SHALL take the body's full inline size.
STP-9 WHERE a step's body holds a list THE steps SHALL leave it a list of prose, nested one depth below the steps: an ordered list is marked with lowercase letters and an unordered one with a ring (PRS-9's second depth), set in by prose's own inset from the body's start edge, so that sub-steps never repeat the steps' numbers and never draw markers or connectors of their own. WHERE the product places a set of steps inside a step's body THE steps SHALL draw it as a set of its own, numbered from its own start and laid out in the body's width, and in debug builds SHALL report that steps are nested.
STP-10 THE steps SHALL lay itself out as a block in the flow of its container: it SHALL take the whole inline size the container gives it, with its start edge on the start edge of the text around it; it SHALL bring no outer space of its own (PRS-15: the space between it and its neighbours is its container's), SHALL never be wider than its container, SHALL have no minimum width and no maximum width, and SHALL NOT scroll.
STP-11 THE steps SHALL NOT take pointer, touch or keyboard input, 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 step has no current, completed, error, hovered, focused, pressed, selected or disabled state, a marker is not a control, and the steps emit no event. What the product places in a body — a link, a code block's copy button, tabs — takes input by its own spec, and text in a title and a body SHALL remain selectable where the platform lets text be selected.
STP-12 THE steps SHALL be exposed to assistive technology as an ordered list of as many items as it has steps, named by label where label is not empty, and each step as one item of that list holding, in this order, its number, its title and its body. Each step's number SHALL be exposed exactly once, as the item's number, and SHALL be the number the marker draws (STP-4), also where start is not 1; the ring and the connector SHALL be kept from assistive technology. THE steps SHALL NOT expose a step as current, done or failed, and SHALL add no role to a title or to anything in a body.
STP-13 WHEN label, a step's title or a step's body changes THE steps SHALL draw and expose the new value at once, without a motion, and SHALL NOT announce the change by itself.
STP-14 WHILE the text size is enlarged THE steps SHALL grow each number, title and body with it and grow each marker with its number, keeping the marker's height of the size as a minimum; THE steps SHALL keep comp.steps.marker.gap, comp.steps.step.gap, comp.steps.title.gap, comp.steps.body.gap and comp.steps.connector.gap as they are, wrap, set no fixed height on a step, lose no content when the reader raises line height, paragraph spacing, letter spacing or word spacing, and SHALL need no horizontal scrolling at a width of 320 points with text at 200 %, except inside a block that scrolls in its own box (STP-8).
STP-15 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 steps SHALL draw each ring and each connector in the platform's text color at their own widths, and each number, title and body in that text color; nothing the steps draw relies on a fill.
STP-16 WHERE the layout direction is right-to-left THE steps SHALL mirror its two parts and apply its spaces by logical start and end, so that the marker column and the connectors are at the right and each step's content is at its left, beginning at one edge and running to the steps' left edge; a body's blocks that are not text SHALL still take the body's whole inline size (STP-8).
STP-17 THE steps 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 steps are shown THE steps SHALL draw themselves for the new direction at once, without a motion of their own, keeping what they show.
STP-18 THE steps SHALL draw a step's number as a left-to-right run whose digits are never reversed, in every layout direction, and SHALL lay out a title given as text as text of its own direction, isolated from the text around it: it takes the base direction of its first strong character, or the layout direction where it has none, so that a command, a file's name and a version keep their own order in a right-to-left layout and reorder nothing beside them; THE steps SHALL still place the title and align its lines by the layout direction, not by the text's own. The body's blocks are laid out as prose lays out a block (PRS-25): each by its own first strong character unless the content states a direction, with its lines aligned to the start edge of the layout.
STP-19 WHEN size names a value that the active design system does not have THE steps SHALL render with the default size's tokens, and in debug builds report the unknown value. IF start is not a whole number THE steps SHALL number from 1 and in debug builds report it; a start of zero or below is a whole number and is drawn as it is.
STP-20 IF the steps hold no step THE steps SHALL draw nothing, take no space and expose nothing, and in debug builds report that a set of steps is empty. IF a step has neither a title nor a body THE steps SHALL still draw its marker, count it in the numbering and in the list's items, and in debug builds report that a step is empty: a number is never skipped, so the numbers a reader sees are the numbers the content has.

各平台名称对照

对等并不意味着 API 完全相同。同一份契约,由各平台以自己的惯用方式表达。

规格 Web SwiftUI Jetpack Compose Flutter React Native
组件 tanrei-steps TanreiSteps TanreiSteps TanreiSteps Steps
label · 属性 aria-label label label semanticLabel accessibilityLabel
start · 属性 start start start start start
size · 属性 data-size size size size size
备注 Form: a class on the product's own ordered list, not an element — <ol class="tanrei-steps" role="list"> with <li> children — styled by one optional stylesheet of the package, @tanrei/web/steps.css, whose selectors are wrapped in :where() so one class on the product's side wins. The list stays the document's list: it is an ordered list before any script runs and for whatever reads the page as built, a Markdown renderer's <ol> needs one class and no wrapper, and there is nothing to define, so nothing changes place after the page loads; without the stylesheet it is the browser's numbered list. start is the <ol>'s own attribute, label is aria-label (or aria-labelledby naming the heading before it), data-size="large" is the size. The marker is the item's ::before showing the item's number from a counter that honours start (the implicit list-item counter where the three engines agree on it, else a counter of the stylesheet's set from start by the package's script); the connector is the item's ::after, absolutely placed, with pointer-events: none. One shared marker column (STP-1) is a grid on the <ol> with the items as subgrids. list-style: none removes list semantics in one engine's accessibility tree, which is why the contract writes role="list" on the <ol>; the number in ::before is generated content, read once with the item (STP-12), and the test of STP-12 is run with a screen reader in each engine. The number is drawn with unicode-bidi: isolate and direction: ltr (STP-18); a title is dir="auto"-like through unicode-bidi: plaintext with physical alignment by :dir(), as productText() does. STP-3 uses 1lh of the item's first line. Inside a .tanrei-prose the list is not an island (it is a class on an <ol>, not a Tanrei element), so prose's own rules keep reaching the paragraphs, lists, links and inline code of each body at any depth, with no second prose to open and no limit of depth; steps.css takes back from prose.css what a set of steps draws itself: the list's inset, its markers, the item gap, the measure on the list (STP-8) and the gap between an item's blocks (STP-7), and a list inside an item is already prose's second depth (STP-9). Outside a prose the stylesheet alone sets the body's text style and the gaps between an item's direct children; long-form content there is wrapped by the product in <div class="tanrei-prose" data-measure="false"> around the list. Under forced-colors: active the ring and the connector are CanvasText (STP-15). The package's script, where it is loaded, adds only the debug reports of STP-9, STP-19 and STP-20. React: Steps and Step render the same <ol> and <li>; Step takes title (text, rendered as <p class="tanrei-steps-title">) or a heading as its first child. TanreiSteps(label:, start:, size:) { TanreiStep("Install") { … } }. A Layout that measures the widest marker, places contents at one edge and draws the connectors in a background; not a List, so it brings no rows, separators or scrolling. Each step is an accessibility container whose first element's label is the number; the set is exposed as a list through the platform's list semantics where it has them and named by label. The body is the product's views; rendered text goes through the prose layout. TanreiSteps(label, start, size) { TanreiStep("Install") { … } }. A custom Layout, not a LazyColumn: a procedure is short and is never recycled. CollectionInfo and CollectionItemInfo expose the list and each item; the number is the first text of the item; the ring and the connector are drawn in drawBehind and have no semantics. TanreiSteps(semanticLabel:, start:, size:, children: [TanreiStep(…)]). Not the framework's Stepper, which is a control with a current step. A CustomMultiChildLayout-style render object for the shared column; connectors painted by a CustomPainter excluded from semantics. Follows Directionality. <Steps accessibilityLabel="…" start={1} size="medium"><Step title="Install">…</Step></Steps>. accessibilityRole="list" on the container; each step's number is the first text of its item. The marker column's width is measured once per set (onLayout). Follows the app's direction where an ancestor's is not known.

令牌

令牌 引用 解析值(浅色)
--tanrei-comp-steps-body-gap sys.space.space100 8px
--tanrei-comp-steps-connector-color sys.color.outline-variant #000000 · 8%
--tanrei-comp-steps-connector-gap sys.space.space50 4px
--tanrei-comp-steps-connector-thickness sys.border.hairline 1px
--tanrei-comp-steps-marker-gap sys.space.space150 12px
--tanrei-comp-steps-marker-height-large — 28px
--tanrei-comp-steps-marker-height-medium — 24px
--tanrei-comp-steps-marker-outline-color sys.color.outline-variant #000000 · 8%
--tanrei-comp-steps-marker-outline-width sys.border.hairline 1px
--tanrei-comp-steps-marker-padding-inline sys.space.space50 4px
--tanrei-comp-steps-marker-shape sys.shape.corner.full 9999px
--tanrei-comp-steps-step-gap sys.space.space200 16px
--tanrei-comp-steps-title-gap sys.space.space50 4px
--tanrei-comp-steps-body-typescale-large sys.typescale.body-large 400 16px/1.625
--tanrei-comp-steps-body-typescale-medium sys.typescale.body 400 14px/1.5714
--tanrei-comp-steps-marker-label-typescale-large sys.typescale.label 500 14px/1.4286
--tanrei-comp-steps-marker-label-typescale-medium sys.typescale.label-small 500 12px/1.3333
--tanrei-comp-steps-title-typescale-large sys.typescale.heading-5 500 16px/1.5
--tanrei-comp-steps-title-typescale-medium sys.typescale.heading-6 500 14px/1.4286

测试样例

作为基准的渲染结果。所有平台都以相同的 ID 为每个样例截取快照,以便相互比较。

生成自 specs/steps.spec.json, tokens/comp/steps.tokens.json, design/tokens/

在长文排版中

在 .tanrei-prose 内部,步骤不是一座孤岛:每个步骤里的段落、列表、链接和行内代码仍然归长文排版管。步骤占满长文排版的整个宽度,所以步骤里的代码块会占满整栏,而步骤里的段落仍然受行长限制。步骤里的列表用字母(有序列表)或圆环(无序列表)作标记,所以子步骤绝不会重复步骤的编号。@tanrei/web/prose.css 已经带有步骤的规则,所以长文排版的页面不需要第二份样式表。

Web 上绘制方式的不同之处

  • 有标题时,请把正文写在元素(<p>)里:直接写在标题后面的文本,无法得到标题下方的那段间隙。
  • 在限制行长的长文排版中,只有文本的步骤受行长限制。如果步骤里还有块,直接写在步骤里的文本就不受限制:请把它写在 <p> 里。
  • 以代码块或图片开头的步骤,标记的顶边与这个块的顶边对齐。直接写在这种块前面的文本(紧凑的 Markdown 列表项)样式表是看不到的:请把它写在 <p> 里。
  • 三位数及以上的编号会把标记撑宽成胶囊形。整组步骤的标记列只有在加载了这个包的脚本时才会跟着变宽,因为要由脚本来测量;没有脚本时,这样的标记会伸进它旁边的间隙。
  • 没有这个包的脚本时,在两种浏览器引擎中,运行时改变 start 不会重新绘制。

指南

推荐

  • 在步骤前面用一个标题或一句话说明这是什么流程。如果前面什么都没有,就给列表一个 label。
  • 一个步骤只写一个动作,以及读者完成它所需要的内容。
  • 当流程被一条说明或一组供选择的标签页打断时,用 start 把它接续下去。
  • 如果每一项只是一个短语,而不是一套流程,请使用不加这个类的长文排版有序列表。

避免

  • 不要用步骤来显示某个流程的进度。没有哪一步是“当前”或“已完成”的。
  • 不要在步骤里嵌套步骤。子步骤是正文里的一个有序列表。
  • 不要把每个标题都写成标题元素:如果页面大纲里列出了每套流程的每一步,在页面中移动反而更难。

无障碍

角色
list
标注
An ordered list, named by label where the product gives one; where a heading directly before the steps says what the procedure is, no label is needed. Each step is a list item read as its number, its title and its body, in that order. The number is the list item's own and is read once; the ring and the connector are decorative and hidden. A title is text of its item, or the product's own heading where the product gave one.
最小目标
即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px

键盘操作

按键 动作

备注

  • Not interactive: the steps take no input and no focus (STP-11), so there is no target of their own to size and minimumTarget holds trivially. What is pressable inside a body — a link, a copy button, tabs — meets the minimum target by its own spec.
  • Order is carried by structure, not by the drawing: the steps are an ordered list whose items have numbers (STP-12), so a reader who does not see the rings and the connector loses nothing. That is also why forced colors and a missing stylesheet cost nothing but the look.
  • The number a person hears is the number a person sees (STP-12), also for a set that continues another with start. A platform whose list semantics would announce a position ("1 of 3") in place of the drawn number adds the number to the item's text instead of relying on the position.
  • Contrast is the surface's: the steps bring no text color (STP-2, STP-6, STP-7), so the number, the title and the body have the contrast of the content color of the surface they sit on, which the default system holds to 4.5:1. The ring and the connector are decorative — the number is read without the ring, and the order without the line — and are not held to 3:1, as the divider's line and a quote's line are not.
  • A title is not a heading by default, because a page whose outline lists every step of every procedure is harder to move through by headings. Where the steps are the page's sections (a long guide with one screen of content per step), give each title as a heading in the title slot; its level is the page's, and the steps do not change it (STP-6).
  • Steps say nothing about progress (STP-11, STP-12): no step is current, done or failed, and none can be. A flow in which the person is somewhere — a checkout, a set-up wizard — needs a component that exposes the current step, which this is not.
  • Text size, text spacing and reflow: STP-14. A long procedure is never cut, collapsed or paged by the component.

生成自 specs/steps.spec.json, tokens/sys/measure.tokens.json

组件负责的部分

  • 它始终是文档里的有序列表:一个项数与步骤数相同的列表,每一项按编号、标题、正文的顺序朗读。
  • 用户听到的编号就是看到的编号,用 start 接续另一组的步骤也是如此。
  • 圆环和连接线是装饰性的,并且对辅助技术隐藏。顺序由列表承载,所以在强制颜色模式下或没有样式表时都不会丢失任何信息。
  • 文本随读者的设置放大并换行。只有在自己的框内滚动的块(例如代码块)才会横向滚动。

需要你做的事

  • 在列表上写 role="list"。
  • 用步骤前面的标题或 aria-label 为这套流程命名。
  • 只有当各个步骤就是页面的各个部分时,才把标题写成标题元素。