跳到正文
册页

数据

BarList - 排行榜

一个排行榜——条形在名字后面,而不是旁边。

用法

什么时候用它

来源排行、最慢的接口、最大的客户。横向柱状图会把三分之一的宽度花在一根重复标签的坐标轴上,而这些标签本来就可以直接写在行里。

来自@misoto22/folio/charts

TSX
import { BarList } from '@misoto22/folio/charts'

说明

一个排行榜——条形在名字后面,而不是旁边。

它回答的是「来源排行」「最慢的接口」「最大的客户」,而且比横向柱状图答得更好:横向柱状图会把三分之一的宽度花在一根重复标签的分类轴上,而这些标签本来就可以写进行里。从坐标轴上读一个名字再去对应一根柱子是两步;直接在柱子上读它是零步。

它是一个 <table>,因为它本来就是:两列、一行表头、一个条目一行。条形是名字那一格的背景,所以它永远不会变成读屏软件还要多走一遍的第二个元素。

当分类少而固定、坐标轴确实在干活时——读者需要照着刻度读数值,而不是扫一眼排名——改用 <BarChart orientation="horizontal">。

结构

BarList anatomy
部件说明
表名必填label,作为表格真正的 caption——默认 sr-only,除非 showLabel 把它当眉题印在这些行的上方。读屏软件那边,这个列表的名字就是它。
表头行必填一个 sr-only 的 thead,两个 th scope="col",Name 和 Value,所以哪怕这个列表从不显示表头,两列也都是有名字的。
名称单元格必填一个 th scope="row",装着截成一行的行名;item.icon 排在它前面、作为 aria-hidden 的装饰;item.href 会把这个名字本身变成链接。
条形必填它不是一个元素:名称单元格内层 span 上的一道 linear-gradient,在这一行占天花板的比例处硬停。要是画成一个兄弟 div,它就成了无障碍树上又一个什么都不说的空东西。
数值单元格必填一个贴尾边的 td,等宽的表格数字、--ink-2,由 formatValue 写出来——除非调用处替掉它,否则用的就是坐标轴那套紧凑写法的默认值。
Other 行limit 加出来的东西:最后一行叫 Other,装着尾巴的总和,所以显示出来的这几行,仍然交代得了自己是从哪个整体里切出来的。
空状态没有东西可排时,label 下面是一个 ChartEmpty。一个 caption 压在空的 tbody 上,在读者看来就是一个加载失败的列表,而且刷新也不会改变什么。

实践建议

推荐

  • 行是随时间陆续到来的,就要固定 max。天花板是当前显示的最大那一行,所以一个新的第一名会把它下面每一根条形重新缩放——昨天填了三分之二的轨道,今天数字一点没变却只填了四分之一,而读者看到的那次变动,其实发生在另一行身上。
  • 要用 limit,不要在调用处自己切 items。尾巴是被加总进 Other 行、而不是被丢掉,所以显示的五行仍然凑得成整体;手工切出来的前五名会悄悄扔掉另外四十项,而列表里没有一句话说这件事。
  • 名字要短到能扛过截断。名字是被截成一行的,还要和数值列分宽度,所以两个到第四十个字符之后才有区别的接口,渲染出来是同一行、同一个省略号。
  • 顺序本身就是重点时,要传 sort={false}——一条漏斗、一组步骤、一批固定的地区。sort 默认为 true 并按降序排,等于一声不吭地把一个序列变成了一个排行。

避免

  • 条形量的是这一行比上最大那一行,从来不是占总量的比例:第一名永远填满自己的轨道,所以占全部流量 3% 的五行,和占了全部流量的五行长得一模一样。整体要紧的话,那句话该写在 caption 里。
  • 数值列里不要混着几种数字形状。它是贴尾边的等宽表格数字,只有在字符串形状一致时才能把位数对齐——而默认的格式化函数在 10,000 处切到紧凑写法,所以一个跨过这个门槛的列表会把 9,400 排在 1.2M 底下,竖着比就什么都比不成了。
  • 两行不能同名。名字同时是这一行的标签和它的 React key,所以一个可能重复标签的查询建出来的列表会渲染出重复的 key——React 会为此告警,并且在列表一更新时就调和错。

示例

默认

这份排名列表最朴素的样子:八行,条形画在名字后面,而不是名字旁边。而这正是一张水平条形图做不到的事——它要拿三分之一的宽度去放分类轴,而把那根轴上的一个名字对应到它的条形是两步,直接从条形上读出名字则是零步。除非 sort 另有说明,各行按降序排列,而刻度的上限取自其中最大的那一个,所以这份列表自己读是可读的,和第二份对照着读就不是了。

Top referrers
NameValue
google.com42.1K
github.com18.8K
news.ycombinator.com9,400
x.com6,120
reddit.com3,280
lobste.rs1,940
bsky.app1,100
linkedin.com640

条数上限

limit 保留前三行,并把余下的五行汇总成一行 Other,而不是把它们丢掉。一个悄悄丢掉长尾的「前三」歪曲了整体,还让读者没有任何办法知道这件事发生过;那行 Other 才是让这一列数字加起来还等于点什么的东西。领先的三行还带着 href,这让名字本身成为链接——条形是同一个单元格上的背景,所以给一行加链接,不会给读屏软件多添一个要走过去的东西。

Top referrers
NameValue
google.com42.1K
github.com18.8K
news.ycombinator.com9,400
Other13.1K

共用上限

两份必须对照着读的列表,所以两份都被给了同一个 max。放任它自己推导,每一份都会拿自己最大的那一行当上限,于是 Enterprise 在两边都填满了自己的轨道——一个翻了一倍还多的季度,画出来会和一个原地踏步的季度分毫不差,而页面上不会有任何东西说明这一点。formatValue 让这些数字变成金额;默认是坐标轴用的那套紧凑写法,那对一个访问次数是对的,而对一种货币则什么都没说。

New ARR this quarter
NameValue
EnterpriseA$92,400
Mid-marketA$61,200
Self-serveA$28,900
EducationA$9,600
New ARR last quarter
NameValue
EnterpriseA$41,800
Mid-marketA$33,500
Self-serveA$26,100
EducationA$11,200

无障碍

  • 是真正的 <table>,两列、一行一个条目——因为排行榜本来就是这个结构。条形是名字那一格的背景,所以它不会变成读屏软件还要多走一遍的第二个元素。
  • limit 会把尾巴加总成一行「Other」,而不是丢掉——一个悄悄扔掉另外四十项的「前五」是在错误陈述整体,而读者根本看不出来。
  • 两个榜要并排比较时一定要固定 max:各自独立取刻度的话,两边的第一名都会填满整条轨道,两个差得很远的数字看起来一模一样。