计量条
以条形或圆环显示一个已知的值在已知范围中的位置,例如已用存储空间、电池电量、配额用量或密码强度。外观与进度指示器相同,但不表示有任何事情正在进行。
- 类别
- 信息传达
- 令牌
comp.meter- 层级
- 基础
- Web
tanrei-meterclock_loader_40 - SwiftUI
TanreiMeterradio_button_unchecked - Jetpack Compose
TanreiMeterradio_button_unchecked - Flutter
TanreiMeterradio_button_unchecked - React Native
Meterradio_button_unchecked
生成自 docs/status/status.json, specs/meter.spec.json
线性和环形
Web 和 React 的示例展示的是当前的规格。SwiftUI、Compose、Flutter 和 React Native 尚在计划中:它们还没有提供计量条。
<tanrei-meter value="0.62" label="已用存储空间" value-text="已用 9.3 GB,共 15 GB"></tanrei-meter>
<tanrei-meter value="37" max="50" label="已占座位" value-text="已占 37 个,共 50 个座位"></tanrei-meter>
<!-- 值意味着什么由产品决定,并且也要用文字说出来。 -->
<tanrei-meter value="0.85" status="warning" label="已用存储空间" value-text="即将用满:已用 12.8 GB,共 15 GB"></tanrei-meter>
<tanrei-meter variant="circular" size="small" value="0.62" label="电池"></tanrei-meter>
<script type="module">
import '@tanrei/web/components/meter';
const meter = document.querySelector('tanrei-meter');
meter.value = used / quota;
meter.status = used / quota > 0.8 ? 'warning' : 'default';
</script>import { Meter } from '@tanrei/react';
<Meter value={used / quota} label="已用存储空间" valueText={`已用 ${usedText},共 ${quotaText}`} />
<Meter value={seats} max={50} label="已占座位" valueText={`已占 ${seats} 个,共 50 个座位`} />
<Meter
value={used / quota}
status={used / quota > 0.8 ? 'warning' : 'default'}
label="已用存储空间"
valueText={used / quota > 0.8 ? `即将用满:已用 ${usedText},共 ${quotaText}` : `已用 ${usedText},共 ${quotaText}`}
/>
<Meter variant="circular" size="small" value={charge} label="电池" />语义状态:default、info、success、warning、error
各种尺寸、范围的两端,以及自定义范围
分隔方式:divider(默认系统的选择)和 gap
构成
构成
linear 之上。| 部件 | 说明 |
|---|---|
1 track | The full length of the bar, or the full circle of the ring: the whole range from min to max. |
2 indicator | The part of the track drawn in the indicator color of the meter's status: the fraction of the range up to the value. It meets the rest of the track, or stands a gap from it (separation). |
3 stop-indicator · 可选 | A dot at the end of a bar's track that marks where the range ends, drawn whenever its size is above 0. |
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
variant | linear | circular | "linear" | Linear is a bar that fills the width its layout gives it; circular is a ring of a fixed size, for tight places and beside text. A structural choice drawn by code, not a token axis, as the progress indicator's is. |
size | small | medium | large | "medium" | The bar's thickness or the ring's box, the progress indicator's three sizes by default (2 / 4 / 8 and 16 / 24 / 40). A design system may add values. |
separation | auto | divider | gap | "auto" | How the indicator is told from the rest of its track. divider: drawn on the track with no space between them. gap: empty space between them. Auto takes comp.meter.track.separation, which follows the design system's choice. |
value | number | 0 | Where the measured quantity stands, between min and max. Always a number: a meter has no unknown value, and a task under way is a progress indicator. |
min | number | 0 | The low end of the range. |
max | number | 1 | The high end of the range. |
status | default | info | success | warning | error | "default" | What the product says the value means, in the names the tag and the snackbar use: default draws the indicator in the meter's own color; info, success, warning and error in that status's color. The product decides it — the meter has no thresholds of its own — and it changes colors only: the words that say so are valueText's and the product's. |
label | string | "" | The accessible name: what is measured ("Storage used"). Required: a bar alone is not a name. |
valueText | string | "" | How assistive technology reads the value when a percentage is not the natural reading ("12.4 GB of 15 GB", "Strong"). Empty reads the platform's percentage. Where status means something, say it here too ("Almost full: 14.2 GB of 15 GB"). |
状态
行为
以 EARS 形式写成的需求。每个平台的实现都按这些 ID 逐条测试。需求原文取自规格文件,原样以英文呈现。
| ID | 需求 |
|---|---|
MTR-1 | THE meter SHALL draw the indicator over the fraction (value − min) / (max − min) of the track, from the track's start: the inline-start of a bar, the top of a ring, turning clockwise. |
MTR-2 | THE meter SHALL draw a bar comp.meter.linear.thickness.medium high for medium (and so on for each size) across the full inline size its layout gives it, and a ring whose outer edge fills a comp.meter.circular.size.medium square with a stroke of comp.meter.circular.thickness.medium for medium (and so on for each size). |
MTR-3 | THE meter SHALL draw the track in comp.meter.track.color and the indicator over it in the indicator color of its status — comp.meter.indicator.color WHILE status is default, comp.meter.info.indicator.color WHILE it is info, comp.meter.success.indicator.color WHILE it is success, comp.meter.warning.indicator.color WHILE it is warning and comp.meter.error.indicator.color WHILE it is error; the ends of a bar's track and indicator SHALL be rounded by comp.meter.track.shape, clamped to half the thickness, and a ring's arcs SHALL have round caps unless comp.meter.track.shape is sys.shape.corner.none. |
MTR-4 | THE meter SHALL tell the indicator from the rest of its track as its separation names — WHILE separation is auto, as comp.meter.track.separation names; WHILE it is divider or gap, as that value names — and WHILE the separation is gap and value lies strictly between min and max SHALL leave comp.meter.track.gap of empty space, measured along the track, between the indicator and the rest of the track (on a ring, at both ends of the indicator's arc); WHILE it is divider THE meter SHALL draw the indicator on the track with nothing between them. |
MTR-5 | WHILE comp.meter.stop-indicator.size is above 0 THE meter SHALL draw at the end of a bar's track a round dot of that size, centred across the track, in the indicator color of its status; a ring SHALL draw none. |
MTR-6 | WHEN value, min, max or status changes after the first frame THE meter SHALL move the indicator's end to the new fraction over comp.meter.motion.value-duration with comp.meter.motion.value-easing, and change the indicator's color over the same duration; WHEN it changes again during that motion THE meter SHALL go on from the place and the color then shown. THE meter SHALL draw its first frame at its value and in its status's color without a motion, and WHERE reduced motion is requested SHALL move the end at once and keep the change of color as a fade over the same duration. |
MTR-7 | THE meter SHALL expose to assistive technology a meter — the platform's own meter where it has one, and otherwise an element with a value range and no busy state — named by label, with min and max as its range, the clamped value as its current value, and valueText as the value's text WHILE valueText is not empty; it SHALL NOT expose the progressbar role or a busy state, because nothing is under way. |
MTR-8 | THE meter SHALL NOT be focusable, SHALL take no input and SHALL NOT announce a change of its value or its status by itself; assistive technology SHALL read the current value when it reaches the meter. |
MTR-9 | THE meter SHALL expose nothing of status by itself: status SHALL change the indicator's color and nothing else, so that what the color means reaches every person only through the words the product gives in valueText, label or the text beside the meter. |
MTR-10 | IF value is below min or above max THE meter SHALL draw and expose it clamped to that range; IF value is not a finite number THE meter SHALL draw and expose min; IF max is not greater than min THE meter SHALL draw the track with no indicator and expose a current value of 0 in a range of 0 to 1; in each case debug builds SHALL report the values. |
MTR-11 | WHEN size names a value that the active design system does not have, or variant, separation or status a value the meter does not define, THE meter SHALL render with the default value's tokens (medium, linear, auto, default), and in debug builds report the unknown value. |
MTR-12 | WHERE the layout direction is right-to-left THE meter SHALL fill a bar from the right and draw its stop indicator at the left; a ring SHALL NOT be mirrored: it starts at the top and turns clockwise in every direction, as a clock does. |
MTR-13 | THE meter SHALL take its layout direction from where it is used and SHALL have no direction setting of its own; WHEN that direction changes while the meter is shown THE meter SHALL draw itself for the new direction at once, without a motion of its own, keeping its value. |
MTR-14 | WHILE label is empty THE meter SHALL still render, and in debug builds report that it has no accessible name. |
MTR-15 | WHERE the platform draws with a person's own forced colors THE meter SHALL draw its track as an edge sys.border.hairline wide in the platform's text color and its indicator filled in the platform's text color, whatever its status, so that the value is still read from where the indicator ends. |
MTR-16 | WHERE the platform has ARIA attributes (the web), the host carries its meter role (MTR-7) itself, so what the product writes on it is not moved, but for a name: WHILE label is not empty THE meter SHALL hold the product's aria-label and aria-labelledby on that host as their data-aria- twins, so that label is its whole name although the platform gives aria-labelledby the precedence, and WHEN label is emptied SHALL give them back as they were written; WHILE label is empty a name the product gives so — aria-label, or aria-labelledby naming an element — SHALL be its name and SHALL NOT be reported as having none in debug builds (MTR-14). WHEN the product removes one, or its data-aria- twin, or sets the ARIA property that reflects it (ariaLabel, ariaLabelledByElements) to null, THE meter SHALL take it away. |
各平台名称对照
对等并不意味着 API 完全相同。同一份契约,由各平台以自己的惯用方式表达。
| 规格 | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| 组件 | tanrei-meter | TanreiMeter | TanreiMeter | TanreiMeter | Meter |
variant · 属性 | variant | variant | variant | variant | variant |
size · 属性 | size | size | size | size | size |
separation · 属性 | separation | separation | separation | separation | separation |
value · 属性 | value | value | value | value | value |
min · 属性 | min | bounds.lowerBound | valueRange.start | min | min |
max · 属性 | max | bounds.upperBound | valueRange.endInclusive | max | max |
status · 属性 | status | status | status | status | status |
label · 属性 | label | label | label | label | label |
valueText · 属性 | valueText | valueText | valueText | valueText | valueText |
| 备注 | Drawn as the progress indicator is (the two share the drawing code; the meter never runs the indeterminate animation). The host carries role="meter", aria-valuemin, aria-valuemax, aria-valuenow, aria-label and aria-valuetext while value-text is set. separation and status are attributes; auto reads the name in --tanrei-comp-meter-track-separation. | TanreiMeter("Storage used", value: 9.3, in: 0...15). Exposed as SwiftUI exposes a Gauge: an element with the label and an accessibility value, accessibilityValue(valueText) while it is set; no updates-frequently trait. | Semantics progressBarRangeInfo with the range (Android has no separate meter role) and stateDescription from valueText; never the indeterminate range info. | Semantics(label:, value:) with the value text or the percentage; on the web renderer the role is meter. | accessibilityRole="progressbar" is not used; the view carries accessibilityValue={{ min, max, now, text }} with role="meter" where React Native passes it through (web), and the label. |
令牌
| 令牌 | 引用 | 解析值(浅色) |
|---|---|---|
--tanrei-comp-meter-circular-size-large | comp.progress-indicator.circular.size.large | 40px |
--tanrei-comp-meter-circular-size-medium | comp.progress-indicator.circular.size.medium | 24px |
--tanrei-comp-meter-circular-size-small | comp.progress-indicator.circular.size.small | 16px |
--tanrei-comp-meter-circular-thickness-large | comp.progress-indicator.circular.thickness.large | 2px |
--tanrei-comp-meter-circular-thickness-medium | comp.progress-indicator.circular.thickness.medium | 2px |
--tanrei-comp-meter-circular-thickness-small | comp.progress-indicator.circular.thickness.small | 2px |
--tanrei-comp-meter-error-indicator-color | sys.color.error | |
--tanrei-comp-meter-indicator-color | comp.progress-indicator.indicator.color | |
--tanrei-comp-meter-info-indicator-color | sys.color.info | |
--tanrei-comp-meter-linear-thickness-large | comp.progress-indicator.linear.thickness.large | 8px |
--tanrei-comp-meter-linear-thickness-medium | comp.progress-indicator.linear.thickness.medium | 4px |
--tanrei-comp-meter-linear-thickness-small | comp.progress-indicator.linear.thickness.small | 2px |
--tanrei-comp-meter-motion-value-duration | comp.progress-indicator.motion.value-duration | 300ms |
--tanrei-comp-meter-motion-value-easing | comp.progress-indicator.motion.value-easing | cubic-bezier(0.2, 0, 0, 1) |
--tanrei-comp-meter-stop-indicator-size | comp.progress-indicator.stop-indicator.size | 0px |
--tanrei-comp-meter-success-indicator-color | sys.color.success | |
--tanrei-comp-meter-track-color | comp.progress-indicator.track.color | |
--tanrei-comp-meter-track-gap | comp.progress-indicator.track.gap | 4px |
--tanrei-comp-meter-track-separation | comp.progress-indicator.track.separation | 0 |
--tanrei-comp-meter-track-shape | comp.progress-indicator.track.shape | 9999px |
--tanrei-comp-meter-warning-indicator-color | sys.color.warning |
测试样例
作为基准的渲染结果。所有平台都以相同的 ID 为每个样例截取快照,以便相互比较。
size: small (2)
linear-small
size: small value: 0.62 label: Storage used circular-small
variant: circular size: small value: 0.62 label: Battery size: medium (14)
linear
value: 0.62 label: Storage used valueText: 9.3 GB of 15 GB linear-info
value: 0.4 status: info label: Monthly quota linear-success
value: 0.9 status: success label: Password strength valueText: Strong linear-warning
value: 0.85 status: warning label: Storage used valueText: Almost full: 12.8 GB of 15 GB linear-error
value: 0.98 status: error label: Storage used valueText: Full: 14.7 GB of 15 GB linear-empty
value: 0 label: Storage used linear-full
value: 1 label: Storage used linear-range
value: 37 min: 0 max: 50 label: Seats taken valueText: 37 of 50 seats linear-gap
separation: gap value: 0.62 label: Storage used linear-divider
separation: divider value: 0.62 label: Storage used linear-on-container-highest
value: 0.62 label: Storage used linear-rtl
value: 0.62 label: Storage used direction: rtl circular
variant: circular value: 0.62 label: Battery circular-warning
variant: circular value: 0.15 status: warning label: Battery valueText: Low: 15% size: large (2)
linear-large
size: large value: 0.62 label: Storage used circular-large
variant: circular size: large value: 0.62 label: Battery 生成自 specs/meter.spec.json, tokens/comp/meter.tokens.json, design/tokens/
当你要显示某个量在一个有真实最小值和最大值的范围中处于什么位置时,使用计量条:配额中已用的存储空间、电池电量、房间里已占的座位、新密码的强度。它显示的是一个水平;没有任何事情正在进行,也没有任何事情会结束。
对于正在运行的任务,例如上传、导入、耗时较长的保存,请改用进度指示器。两者外观相同,但辅助技术会告诉用户某件事正在进行,而计量条绝不能这样说。没有有意义的最大值的值,例如消息数量,两者都不适用:请用文本显示。
| 变体 | 用途 |
|---|---|
| 线性 | 属于某个页面或某个区域的水平:设置页上的存储空间、卡片里的配额、套餐列表中的一行。条形会占满布局分配给它的宽度。 |
| 环形 | 空间紧凑的地方,以及文本旁边的水平:状态栏里的电池、设备列表中的一行。圆环的尺寸是固定的。 |
| 尺寸 | 默认系统中的条形粗细 / 圆环尺寸 | 用途 |
|---|---|---|
| Small | 2 / 16 | 紧凑的行、小号文本旁边。 |
| Medium | 4 / 24 | 大多数地方。这是默认尺寸。 |
| Large | 8 / 40 | 整个视图所围绕的那一个水平,例如账户的存储空间页面。 |
尺寸、轨道和默认颜色与进度指示器相同,因此计量条和进度指示器并排放置时也能保持一致。设计系统可以通过计量条自己的令牌,只改变计量条。
计量条不决定一个值意味着什么。值越多越好还是越坏,是你的产品才知道的事:存储空间快满了是 warning,密码接近最高强度是 success。请自己计算语义状态并传入。语义状态的名称与标签和消息条所用的相同。
| 语义状态 | 用途 |
|---|---|
| Default | 不需要任何说明的水平。大多数计量条都保持这个状态。 |
| Info | 值得知道、但不要求任何操作的水平,例如即将重置的配额。 |
| Success | 处于应有位置的水平,例如强度高的密码。 |
| Warning | 很快就需要注意的水平,例如快用满的存储空间或电量低的电池。 |
| Error | 已经妨碍了某件事的水平,例如已经用满的存储空间。 |
语义状态只改变指示部分的颜色,不改变其他任何东西。请同时用文字说明它的含义:写在值文本里,以及计量条旁边的文字里。
- 给它一个说明测量对象的标签:“已用存储空间”,而不是“计量条”。如果旁边显示了说明文字,请使用相同的措辞。
- 当百分比不是自然的读法时,使用值文本:“已用 9.3 GB,共 15 GB”“已占 37 个,共 50 个座位”“强”。
- 当语义状态有含义时,也把它写进值文本:“即将用满:已用 12.8 GB,共 15 GB”。
- 不要把它用于正在运行的任务。那是进度指示器。
- 不要只依靠语义状态的颜色。看不到颜色的人也必须能得知存储空间快满了。
- 不要显示范围之外的值。计量条会把它限制在范围内再绘制和公开,用户听到的数字就不是你手上的那个数字了。
- 角色
meter- 标注
- label is the accessible name. valueText, when given, replaces the platform's percentage as the spoken value. A visible caption beside the meter is the product's composition; when it exists, use the same words as label. status is never announced: say in valueText what it means.
- 最小目标
- 即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px
键盘操作
| 按键 | 动作 |
|---|
备注
- Not interactive: the meter takes no input and is never focusable (MTR-8), so the minimum target holds without extending anything.
- A meter shows where a value stands in a known range; it is not progress (WAI-ARIA APG, Meter: not for loading or percent completion) and not for a value without a meaningful maximum. A task under way is a progress indicator.
- The value is read from the boundary between indicator and track, so every indicator color — default and the four statuses — must stay at least 3:1 against comp.meter.track.color and the surface behind it (WCAG 1.4.11). In the default system each is above 4.6:1 in light and 7.3:1 in dark.
- Color is never the only sign of a status (WCAG 1.4.1): MTR-9.
- Web: the host carries role="meter" and the aria-value attributes; the native <meter> element is not drawn, because its look cannot be styled in every engine.
生成自 specs/meter.spec.json, tokens/sys/measure.tokens.json
- 它公开计量条(meter)角色,以标签作为名称,并公开范围、当前值(限制在范围内)以及值文本(如果有)。它从不表示自己处于忙碌状态,也不表示有任务正在进行。
- 它永远不可获得焦点,也不会主动播报自己的变化。辅助技术会在用户到达它时读出当前值。
- 语义状态从不被单独播报:它只改变颜色。
- 值变化时,指示部分的末端会移动;语义状态变化时,颜色会渐变。在请求减弱动态效果时,末端立即移动,只有颜色渐变。
- 在强制颜色模式下,无论语义状态如何,轨道都变成一条细的边线,指示部分则被填充,两者都使用文本颜色绘制,因此仍可以从指示部分结束的位置读出值。
- 空标签、范围之外的值、不是数字的值,以及未知的
size、variant、separation或status,都会在调试构建中报告。
- 用文字说明语义状态的含义:写在值文本里,以及计量条旁边的文字里。
- 重要的变化(例如存储空间已满)要由你自己告知:用实时区域中的消息,或用户会看到的通知。计量条不会说出来。
- 如果你更改了指示部分的颜色(默认颜色和四种语义状态),请让每一种颜色相对于轨道和其背后的表面都至少保持 3:1。值是从指示部分与轨道相接的位置读出的。默认系统中,这五种颜色在浅色下都高于 4.6:1,在深色下都高于 7.3:1。