mcpField
T
tab-navigation

tab-navigation

github.com/dembrandt设计与 UI174690 次安装1 周前更新
代码仓库

关于 tab-navigation

一项关于标签页选择与实现的设计技能,涵盖布局、溢出处理、无障碍、键盘操作和状态保存,适用于设计相关内容视图的界面。

主要功能

  1. 01标签页适用场景指南
  2. 02下划线、盒式与胶囊样式
  3. 03溢出与垂直标签模式
  4. 04键盘与 ARIA 无障碍支持
  5. 05URL 与 localStorage 状态保存

适用场景

  1. 01为相关内容视图选择标签页
  2. 02设计窄屏下的标签页行为
  3. 03检查键盘与屏幕阅读器支持

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dembrandt/dembrandt-skills --skill tab-navigation

安装后在 Claude Code 中输入/tab-navigation确认已加载。

详细介绍

标签页导航

标签页将相关内容组织在共同的上下文中。标签栏展示所有可用视图;切换标签页会更换内容面板,而不会跳转页面。只有当所有视图共享标题、主要操作或共同主题时,标签页才最适用——彼此无关的标签页应放在不同页面中。


何时使用标签页——何时不使用

适合使用标签页的情况……适合使用其他方式的情况……
2–7 个视图共享共同上下文(同一记录、同一设置部分)标签页超过 7–8 个——改用侧边栏或分区导航
用户在一次会话中频繁切换视图内容具有顺序性(改用步骤条/向导)
所有标签页都是同等有效的入口某个视图明显是主要视图——将其余视图放入次级导航或溢出菜单
各视图共享页眉或一组页面级操作每个“标签页”都需要不同的页眉和布局——使用独立页面

标签页类型

选择适合布局上下文的视觉样式。

下划线/指示器标签页

水平标签栏,在活动标签页下方显示滑动下划线或底部边框。视觉强调最轻——适用于标签栏位于内容区域内的页面级标签页。

Overview  |  Activity  |  Settings
──────────
包含式/方框式标签页

每个标签页都是一个独立方框;活动标签页看起来与下方面板相连。视觉强调较强——适用于屏幕顶部附近或卡片内较醒目的标签页组。

胶囊式/按钮式标签页

圆角胶囊形按钮,用于在不同状态间切换。强调较弱——适用于某个分区内的次级内容切换(非页面级)。常用于视图切换(例如“列表/网格/地图”)。


结构

┌─────────────────────────────────────────────────┐
│  Tab A  │  Tab B  │  Tab C  │                   │  ← Tab strip (role="tablist")
├─────────┴─────────────────────────────────────────┤
│                                                   │
│   Tab panel content                               │  ← Tab panel (role="tabpanel")
│                                                   │
└───────────────────────────────────────────────────┘
  • 标签栏: 高度固定(通常为 40–48px)。不会随页面滚动——页面较长时,可考虑将其设为粘性定位。
  • 标签面板: 填满剩余可用高度。内容溢出时滚动的是面板,而不是标签栏。
  • 活动指示器: 下划线标签页使用 --color-primary 的 2–3px 底部边框;包含式/胶囊式标签页使用填充背景。

状态

状态视觉样式
活动主色指示器;标签文字使用 --color-text-primary 或主色
非活动弱化标签文字(--color-text-secondary);无指示器
悬停背景颜色轻微变化(--color-grey-50);标签文字略微加深
聚焦显示可见的焦点环(outline: 2px solid --color-primary; outline-offset: 2px)
已禁用降低不透明度(0.4);cursor: not-allowed;绝不能是活动标签页

绝不要禁用活动标签页。如果内容不可用,应在面板中显示并附上说明,而不是禁用标签页。


标签页溢出

当标签栏宽度超过其容器时,不要将标签页换行到多行;这会破坏标签栏的视觉隐喻。以下是三种解决方式,按优先顺序排列。

回退为选择框

测量标签栏宽度;当其内容宽于容器时,使用相同选项渲染原生 <select>。所有选项都能一目了然地访问,且在任何宽度下都不会隐藏在边缘之外;平台也已为触控用户提供选择器。

可滚动标签栏

标签栏可水平滚动,并在右边缘显示渐隐效果以提示有溢出。这是移动设备上的平台惯例;如果用户熟悉这组标签页,这种方式也很合适;但初次阅读的用户会看不到部分选项。

.tab-strip {
  display: flex;
  overflow-x: auto;
  scrollbar-width: none; /* hide scrollbar visually on desktop */
}
.tab-strip::after {
  content: '';
  position: absolute; right: 0;
  background: linear-gradient(to left, var(--color-surface), transparent);
  pointer-events: none;
}
“更多”溢出菜单

显示所有适合的标签页,再将其余标签页折叠到 More ▾ 下拉菜单中。活动标签页位于溢出菜单中时,更新“More”标签:Settings ▾(显示当前活动的隐藏标签页名称)。

无论使用哪种方式,都只能在所选标签页下方显示下划线;在整个标签栏下方显示横线会与其争抢视觉注意力。对于包含许多视图的桌面仪表板,优先使用侧边栏导航,而不是溢出标签页。


垂直选项卡

当有 5 个或更多选项卡且布局包含左侧边栏时使用。垂直选项卡允许使用较长的标签,避免溢出问题,并能更灵活地适应不同布局。

  • 固定宽度的侧边栏(通常为 200–240px),选项卡标签垂直排列
  • 当前选项卡:左侧边框强调(3px solid --color-primary)+ 淡色背景
  • 主内容区填充剩余宽度

键盘导航

选项卡遵循 ARIA 的“roving tabindex”模式,在选项卡栏内导航。

按键操作
Tab将焦点移至选项卡栏(然后移入当前面板)
← / →在选项卡之间移动(水平选项卡栏);根据内容加载成本,立即激活或按 Enter 激活
↑ / ↓在选项卡之间移动(垂直选项卡栏)
Home跳至第一个选项卡
End跳至最后一个选项卡
Enter / Space激活获得焦点的选项卡(如果方向键尚未自动激活)

自动激活与手动激活: 如果切换选项卡会触发网络请求,请使用手动激活(方向键移动焦点,按 Enter 激活),以避免不必要的请求。如果内容已加载或加载成本较低,则可以接受按方向键自动激活。


ARIA

<div role="tablist" aria-label="Product sections">
  <button
    role="tab"
    id="tab-overview"
    aria-selected="true"
    aria-controls="panel-overview"
    tabindex="0"
  >Overview</button>
  <button
    role="tab"
    id="tab-activity"
    aria-selected="false"
    aria-controls="panel-activity"
    tabindex="-1"
  >Activity</button>
</div>

<div
  role="tabpanel"
  id="panel-overview"
  aria-labelledby="tab-overview"
>…</div>

<div
  role="tabpanel"
  id="panel-activity"
  aria-labelledby="tab-activity"
  hidden
>…</div>
  • 当前选项卡设为 aria-selected="true",其他选项卡设为 false
  • 当前选项卡设为 tabindex="0",其他选项卡设为 -1(roving tabindex)
  • 非当前面板使用 hidden 属性(或 display: none)——屏幕阅读器会跳过隐藏的面板
  • 如果上方标题不能充分说明选项卡组的内容,请为 tablist 设置 aria-label

状态持久化

在页面加载和导航之间保留当前选项卡:

  • URL 片段或查询参数: ?tab=activity — 最可靠的方式;支持深层链接以及浏览器的前进和后退
  • localStorage: 适用于无需分享的偏好设置(例如偏好的仪表盘视图)
  • 不要使用 sessionStorage — 关闭选项卡会导致状态意外丢失

当 URL 包含选项卡参数时,即使它不是第一个选项卡,也应在加载时跳转到该选项卡。


嵌套选项卡

避免在选项卡内再嵌套选项卡。嵌套选项卡会让范围变得难以理解——用户在“选项卡 A › 子选项卡 2”中编辑内容时,无法清楚理解外层选项卡的含义。

如果发现自己在嵌套选项卡,请重新考虑信息架构:

  • 能否将内层选项卡改为次级导航(胶囊按钮、面板内的侧边栏)?
  • 能否将外层选项卡改为顶层页面导航?

主要内容区最多使用一层选项卡。


审核清单

  • 是否有 2–7 个选项卡,且每个选项卡都属于同一主题或上下文?
  • 在任何目标视口下,选项卡栏是否都不会换成多行?
  • 是否通过颜色和/或指示标记清楚区分当前选项卡?
  • 悬停和焦点状态是否符合对比度要求?
  • 是否避免使用禁用的选项卡(改为在面板内显示不可用状态)?
  • 键盘导航是否遵循 roving tabindex(按 ←/→ 在选项卡间移动,按 Tab 移入面板)?
  • 是否正确设置了 role="tablist"、role="tab"、role="tabpanel" 和 aria-selected?
  • 是否通过 hidden 属性将非当前面板从无障碍树中隐藏?
  • 是否将当前选项卡持久化在 URL(适用于可深层链接的视图)或 localStorage 中?
  • 是否避免了嵌套选项卡?
  • 选项卡溢出时是否使用下拉选择框、可滚动的选项卡栏或“更多”菜单,绝不换行?
  • 是否仅在当前选项卡下方显示下划线作为选中标记,而不在整个选项卡栏下方显示横线?

评论

支持 Markdown