标签页
本页内容
给每一项一个 href,这些标签就是链接——一个标签对应一个页面,不用脚本,当前项带 aria-current。给每一项一个 panel,它们就变成一组单选按钮,面板就地切换,而且依然不用脚本。
在静态站点上,链接形态通常才是对的:它给每个视图一个 URL,而且关掉 JavaScript 也照样能用。只有当内容不多、切换不该付出一次跳转成本时,才用面板形态。
链接式标签
它们真的是链接——点一下就会跳转。下划线来自构建时的 active 或 value,而不是这次点击,所以每个页面各自标出自己的那一项。链接式标签本身不会对 URL 作出反应:想要那样,就用下面就地切换的面板。
tabs({
items: [
{ label: '面包屑', href: '/zh/ui/breadcrumbs' },
{ label: '标签页', href: '/zh/ui/tabs', active: true },
{ label: '分页', href: '/zh/ui/pagination' },
],
})面板式标签
标签就是一个 <label>,对应一个被样式表藏起来的单选按钮;紧跟在选中单选按钮之后的面板,就是 CSS 显示的那一个。本页没有导入任何东西:切换,以及在标签之间用方向键移动,本来就是一组单选按钮会做的事。
npm install sitelo javascript-to-htmlimport * as ui from 'sitelo/ui'sitelo buildtabs({
value: 'install',
items: [
{ id: 'install', label: '安装', panel: card({ variant: 'flat' }, cardBody(code('npm install sitelo javascript-to-html'))) },
{ id: 'use', label: '使用', panel: card({ variant: 'flat' }, cardBody(code("import * as ui from 'sitelo/ui'"))) },
{ id: 'build', label: '构建', panel: card({ variant: 'flat' }, cardBody(code('sitelo build'))) },
],
})可链接的标签
再给面板项一个带片段的 href,单选按钮就让位给链接:URL 指名哪个标签,:target 把它挑出来,紧跟其后的面板就显示出来,这个选择还能挺过刷新、分享链接和后退按钮。id 放在标签上而不是面板上,因为浏览器会把 URL 指名的元素滚到窗口顶端——放在面板上,就会把你刚点过的那排标签顶出屏幕。一个文档里只能有一个 :target,所以这种形态适合一页只放一组标签。滚动本身取消不了:跟随片段就意味着移动窗口。能选的只是滚到哪里、停在哪儿——标签上的 id 和它的 scroll-margin-block-start 就是干这个的——用 scrollMargin 这个 prop 来设置,粘性页头至少要留出它自己的高度。
tabs({
items: [
{ id: 'setup', label: '配置', href: '#tab-setup', panel: card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, '这个面板是 #tab-setup——把 URL 复制走,它还会回来。'))) },
{ id: 'deploy', label: '部署', href: '#tab-deploy', panel: card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, '而这个是 #tab-deploy。'))) },
],
})胶囊样式
stack({ gap: 'lg' },
tabs({
variant: 'pills',
items: [
{ label: '全部', href: '#all', active: true },
{ label: '指南', href: '#guides' },
{ label: '示例', href: '#examples' },
],
}),
tabs({
variant: 'pills',
value: 'js',
items: [
{ id: 'js', label: 'JavaScript', panel: card({ variant: 'flat' }, cardBody(code('src/index.ht.js'))) },
{ id: 'ts', label: 'TypeScript', panel: card({ variant: 'flat' }, cardBody(code('src/index.ht.ts'))) },
{ id: 'jsx', label: 'JSX', panel: card({ variant: 'flat' }, cardBody(code('src/index.ht.jsx'))) },
],
}),
)颜色
stack({ gap: 'lg' },
tabs({ color: 'primary', items: [{ label: 'Primary', href: '#p', active: true }, { label: '其他', href: '#p2' }] }),
tabs({ color: 'neutral', items: [{ label: 'Neutral', href: '#n', active: true }, { label: '其他', href: '#n2' }] }),
tabs({ color: 'danger', items: [{ label: 'Danger', href: '#d', active: true }, { label: '其他', href: '#d2' }] }),
)很多标签
标签栏会横向滚动而不是换行,这样在手机上这一排也能保持原样。面板式标签则相反,会换行——每个面板都必须紧跟自己的标签,于是没有一排元素可供滚动。
tabs({
items: [
'概览', '路由', '数据', '资源', '图片', '区块', 'TypeScript', 'CLI', '部署',
].map((label, index) => ({ label, href: '#many-' + index, active: index === 0 })),
})禁用
这个是能用的。
tabs({
value: 'now',
items: [
{ id: 'now', label: '已可用', panel: card({ variant: 'flat' }, cardBody(text({ variant: 'small' }, '这个是能用的。'))) },
{ id: 'soon', label: '即将推出', disabled: true, panel: card({ variant: 'flat' }, cardBody('')) },
],
})无障碍
面板形态是一组真正的单选按钮:标签是 <label> 元素,对应共用同一个 name 的单选按钮,所以读屏软件会念出选中的是几个里的哪一个,方向键、Home 和 End 也不用加载任何脚本就能用。可链接的那种形态只是普通链接,不带 aria-current——它只会写死一次,第一次点击之后就不对了。它刻意不是 ARIA tablist——aria-selected 只在服务端写一次,CSS 无法在你点击时让它保持为真。链接形态同样不是 tablist:会跳转的链接就是链接,给它们套上标签页语义等于谎报它们的行为。
属性
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
items | Array | [] | 字符串,或 { id, label, href, panel, active, disabled } 对象。 |
value | string | — | 当前项的 id。没有就回退到 active,再回退到第一项。 |
variant | 'underline' | 'pills' | 'underline' | 当前标签怎么标出来。 |
color | 'primary' | 'neutral' | 'success' | 'warning' | 'danger' | 'primary' | 当前标签的颜色。 |
label | string | 'Tabs' | 这一组的无障碍名称。仅面板形态有效。 |
name | string | 第一项的 id | 单选按钮组的 name。只有一页上有两组面板式标签时才需要。 |
href | string | — | 在项上:要链接到的页面;或者与 panel 一起,给出为它命名的片段。 |
scrollMargin | Space | 'md' | 窗口停在标签上方多远。仅 :target 形态有效。 |