跳到主要内容
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.app-bar
层级
基础

概览

Web
tanrei-app-bar
schedule
SwiftUI
TanreiAppBar
schedule
Jetpack Compose
TanreiAppBar
schedule
Flutter
TanreiAppBar
schedule
React Native
AppBar
schedule

生成自 docs/status/status.json, specs/app-bar.spec.json

Web 和 React 的示例展示的是当前规格:应用栏中的项是纯图标的按钮。SwiftUI、Compose、Flutter 和 React Native 待跟进,它们提供的仍是上一版,其中图标按钮是一个独立的组件;在跟上之前,这些平台的示例展示的是上一版。

带返回按钮和两个操作的小号应用栏

arrow_backsearchmore_vert

用法

应用栏是一块布局区域,不是浮层。它在屏幕顶部占据自己的高度,内容从它下方开始,应用栏本身从不获得焦点。

它容纳两类项:起始侧的一个 navigation 项(返回、菜单或关闭),以及末尾侧最多三个 action 项。两者都是你自己提供的纯图标按钮,各有自己的标签和自己的点击处理;如果它通向某个地方,则有自己的 href。应用栏只负责排列它们,从不改变它们的样式。每个平台用各自的插槽接收这些项:在 Web 上是带 slot="navigation" 和 slot="actions" 的子元素,在 SwiftUI 上是 navigation 和 actions 视图构建器,在 Compose 上是 navigationIcon 和 actions lambda,在 Flutter 上是 leading 和 actions:,在 React Native 上是 navigation 和 actions 节点。

标题是屏幕的名称,也是屏幕的标题元素(heading)。在 Web 上它叫 headline,因为 HTML 的全局属性 title 会让整个应用栏出现工具提示。

滚动后。 只要有内容位于应用栏下方,应用栏就呈现滚动后的外观。把屏幕的滚动视图连接到应用栏,它就会自己设置 scrolled:在 Web 上用 scroll-target(默认是文档),在 SwiftUI 上用 .tanreiAppBarScrollSource()(加在容纳应用栏的 .safeAreaInset 之后),在 Compose 上用通过 Modifier.nestedScroll 连接的 scrollBehavior,在 Flutter 上靠页面的滚动通知,在 React Native 上用 useAppBarScroll()。没有连接时,请自己设置 scrolled。

系统栏。 应用栏的颜色会延伸到它上方的状态栏、摄像头挖孔或窗口标题栏之下。它的内容则留在这些区域的下方,并位于两侧的边衬区(insets)之内。Web 读取 env(safe-area-inset-*),Compose 接收 windowInsets(默认是状态栏和水平方向的屏幕挖孔),Flutter 读取 MediaQuery 的 padding,SwiftUI 则用 .safeAreaInset(edge: .top) 放置应用栏。React Native 没有安全区域 API,Tanrei 也不引入安全区域方面的依赖,所以边衬区只能来自属性。请把窗口的 insets 交给 TanreiProvider(如果你使用 react-native-safe-area-context,把它的 useSafeAreaInsets() 直接传过去)。应用栏自己的 insets 属性会替换它所指定的那几条边,因此不在窗口顶部的应用栏要传入 { top: 0 }。

<!-- 标题用 headline:HTML 的 title 属性会在应用栏上显示工具提示。 -->
<tanrei-app-bar headline="收件箱">
  <tanrei-button variant="text" slot="navigation" label="返回"><span slot="icon">arrow_back</span></tanrei-button>
  <tanrei-button variant="text" slot="actions" label="搜索"><span slot="icon">search</span></tanrei-button>
  <tanrei-button variant="text" slot="actions" label="更多选项"><span slot="icon">more_vert</span></tanrei-button>
</tanrei-app-bar>

<!-- 随 #inbox 滚动而折叠的大标题。除非 heading-level 另有指定,标题是 h1。 -->
<div style="display: flex; flex-direction: column; block-size: 100dvh">
  <tanrei-app-bar size="large" headline="收件箱" scroll-target="inbox">
    <tanrei-button variant="text" slot="navigation" label="菜单"><span slot="icon">menu</span></tanrei-button>
  </tanrei-app-bar>
  <main id="inbox" style="flex: 1; overflow: auto">…</main>
</div>

<!-- 通向某个页面的按钮是链接:给它一个 href。搜索可以作为一个操作:它的图标触发器。 -->
<tanrei-app-bar headline="标签页">
  <tanrei-button variant="text" slot="navigation" href="/components/" label="所有组件"><span slot="icon">arrow_back</span></tanrei-button>
  <tanrei-search slot="actions" bar="icon" presentation="dialog" label="搜索文档" placeholder="搜索"
    clear-label="清除搜索内容" back-label="返回"></tanrei-search>
</tanrei-app-bar>

<script type="module">
  import '@tanrei/web/components/app-bar';
  import '@tanrei/web/components/button';
  import '@tanrei/web/components/search';
  // 按钮是你自己的:应用栏不添加任何自己的事件。
  document.querySelector('[label="返回"]').addEventListener('click', () => history.back());
</script>
import { AppBar, Button, Search } from '@tanrei/react';

<AppBar headline="收件箱">
  <Button variant="text" slot="navigation" label="返回" onClick={goBack}><span slot="icon">arrow_back</span></Button>
  <Button variant="text" slot="actions" label="搜索" onClick={search}><span slot="icon">search</span></Button>
  <Button variant="text" slot="actions" label="更多选项" onClick={openMore}><span slot="icon">more_vert</span></Button>
</AppBar>

// 通向某个页面的按钮是链接:给它一个 href。搜索可以作为一个操作:它的图标触发器。
<AppBar headline="标签页">
  <Button variant="text" slot="navigation" href="/components/" label="所有组件"><span slot="icon">arrow_back</span></Button>
  <Search slot="actions" bar="icon" presentation="dialog" label="搜索文档" placeholder="搜索" clearLabel="清除搜索内容" backLabel="返回" />
</AppBar>
import Tanrei

// 应用栏放在 NavigationStack 顶部的安全区域 inset 中,该 NavigationStack 的系统栏已隐藏。
// isScrolled 保持 nil 时,跟随标记了 .tanreiAppBarScrollSource() 的滚动视图。
NavigationStack {
    ScrollView { InboxRows() }
        .safeAreaInset(edge: .top, spacing: 0) {
            TanreiAppBar("收件箱", size: .large) {
                TanreiIconButton("菜单", action: openMenu) { Image(systemName: "line.3.horizontal") }
            } actions: {
                TanreiIconButton("搜索", action: search) { Image(systemName: "magnifyingglass") }
            }
        }
        // 加在容纳应用栏的 inset 之后:加在 inset 内部的修饰符影响不到应用栏。
        .tanreiAppBarScrollSource()
        .toolbar(.hidden, for: .navigationBar)
}
import io.github.chnotchy.tanrei.components.TanreiAppBar
import io.github.chnotchy.tanrei.components.TanreiAppBarDefaults
import io.github.chnotchy.tanrei.components.TanreiIconButton
import io.github.chnotchy.tanrei.primitives.TanreiText
import io.github.chnotchy.tanrei.tokens.TanreiAppBarSize

// 小号应用栏。没有 scrollBehavior 时它保持平的外观。
TanreiAppBar(
    title = "收件箱",
    navigationIcon = { TanreiIconButton(onClick = onBack, contentDescription = "返回") { TanreiText("arrow_back") } },
    actions = {
        TanreiIconButton(onClick = onSearch, contentDescription = "搜索") { TanreiText("search") }
        TanreiIconButton(onClick = onMore, contentDescription = "更多选项") { TanreiText("more_vert") }
    },
)

// 随列表滚动而折叠的大号应用栏:在滚动视图的某个父级上连接 behavior。
// pinnedScrollBehavior() 用于小号应用栏:它从不折叠,只在内容位于其下方时变为滚动后的状态。
val scrollBehavior = TanreiAppBarDefaults.collapseScrollBehavior()
Column(Modifier.nestedScroll(scrollBehavior.nestedScrollConnection)) {
    TanreiAppBar(title = "收件箱", size = TanreiAppBarSize.Large, scrollBehavior = scrollBehavior)
    LazyColumn { /* 屏幕的内容 */ }
}
import 'package:tanrei/tanrei.dart';

// 小号应用栏,放在 Scaffold 的应用栏插槽里,或放在 Column 的最前面。
// scrolledUnder 保持 null 时,和 AppBar 一样跟随最近的 ScrollNotificationObserver。
TanreiAppBar(
  leading: TanreiIconButton(onPressed: () => Navigator.of(context).maybePop(), icon: const Icon(AppSymbols.arrowBack), semanticLabel: '返回'),
  title: '收件箱',
  actions: <Widget>[
    TanreiIconButton(onPressed: search, icon: const Icon(AppSymbols.search), semanticLabel: '搜索'),
    TanreiIconButton(onPressed: openMore, icon: const Icon(AppSymbols.moreVert), semanticLabel: '更多选项'),
  ],
),

// 随内容一起折叠的大号应用栏是一个 sliver,固定在其 CustomScrollView 的顶部。
CustomScrollView(
  slivers: <Widget>[
    TanreiSliverAppBar(title: '收件箱', size: TanreiAppBarSize.large, leading: menuButton),
    SliverList.list(children: messages),
  ],
),
import { useState } from 'react';
import { ScrollView, View } from 'react-native';
import { AppBar, IconButton, useAppBarScroll } from '@tanrei/react-native';

// 边衬区来自 TanreiProvider 的 insets 属性,或来自应用栏自己的 insets 属性。
<AppBar
  title="收件箱"
  navigation={<IconButton accessibilityLabel="返回" onPress={goBack}>arrow_back</IconButton>}
  actions={
    <>
      <IconButton accessibilityLabel="搜索" onPress={search}>search</IconButton>
      <IconButton accessibilityLabel="更多选项" onPress={openMore}>more_vert</IconButton>
    </>
  }
/>

// 会折叠的大号应用栏:连接滚动视图,把应用栏叠放在它上面,并给内容加上与应用栏等高的内边距。
const scroll = useAppBarScroll();
const [barHeight, setBarHeight] = useState(0);
<View style={{ flex: 1 }}>
  <ScrollView onScroll={scroll.onScroll} scrollEventThrottle={16} contentContainerStyle={{ paddingTop: barHeight }}>
    {messages}
  </ScrollView>
  <View style={{ position: 'absolute', top: 0, left: 0, right: 0 }} onLayout={(e) => setBarHeight((h) => Math.max(h, e.nativeEvent.layout.height))}>
    <AppBar size="large" title="收件箱" scrollState={scroll.state} navigation={menuButton} />
  </View>
</View>

规格

带副标题的大号应用栏,以及标题居中的应用栏

menusearchaccount_circlearrow_backsearch

作为链接的导航按钮,以及操作中的搜索触发器

arrow_backmore_vert

构成

部件 说明
1 container The bar across the top of the screen. Its color reaches under the system inset above it (status bar, camera cutout, window caption).
2 navigation · 可选 The navigation item: one icon-only Button at the start (back, menu or close). The product's icon-only Button, not restyled by the bar.
3 brand · 可选 The product's brand: one link to its first page (or one image), after the navigation item, in a cell as large as an icon button's. It draws one image, the symbol alone, the wordmark alone, the symbol and the wordmark side by side (lockup), or one of the two by the window's width (responsive).
4 context · 可选 The product's context: one control after the brand (a workspace, a project, a design system), the product's own Button, not restyled by the bar.
5 title The screen's name. In the top row for a small bar; under the top row for an expanded large bar, moving into the top row as it collapses.
6 subtitle · 可选 One line under the title: context for it (an account, a status, when it was edited).
7 actions · 可选 The action items: up to three icon-only Buttons at the end. The product's icon-only Buttons, not restyled by the bar.
8 outline The bar's bottom edge. In the default system it is drawn at rest and while content is under the bar; dividerVisibility scroll draws it only once content has scrolled under the bar.

属性

属性 类型 默认值 说明
size small | large "small" Small puts the title in the one row the bar has; large gives the title a larger row of its own under the top row, which collapses into the top row as the content scrolls. One product uses small on most screens and large on its top-level ones. A design system may add values.
title string "" The screen's name, and the heading of the screen for assistive technology.
subtitle string "" One line under the title. Empty draws none.
titleAlignment start | center "start" Where the title sits in the top row: after the navigation button, or centered on the bar. An expanded large bar's own title row always starts at the start.
brandHref string "" The address of the product's first page: the brand is a link to it. Empty draws the brand as an image that is not a link.
brandLabel string "" The product's name: the brand's one accessible name, whichever of its images is shown. Required wherever the bar has a brand.
brandLayout lockup | responsive "lockup" How the brand's symbol and wordmark stand when the product gives both (APB-21): lockup sets them side by side, comp.app-bar.brand.lockup.gap apart and aligned as comp.app-bar.brand.lockup.alignment says; responsive shows the wordmark while the window is medium or wider and the symbol while it is compact, never both. One image, a symbol alone or a wordmark alone is shown as it is, at every width, under either value.
scrolled boolean false Whether content lies under the bar. A scrolling view connected to the bar sets it (see platforms); a product without one sets it itself. It selects the bar's scrolled condition, and a large bar is drawn collapsed while it is true.
dividerVisibility auto | always | scroll "auto" When the bar's bottom edge is drawn. always: at rest and while content is under the bar, so that the edge of the screen's header stands still (an app shell's header, a screen whose content starts right under the bar). scroll: only while content lies under the bar, so that the line itself says the content has moved (the scrolled condition's edge alone). auto takes comp.app-bar.outline.visibility, the design system's answer (always in the default system). The bar's color and elevation follow scrolled under either choice.

插槽

插槽 说明
navigation Holds the navigation item: one icon-only Button at the start.
brand The brand as one image: a product's single logo file, drawn comp.app-bar.brand.image.height high. Takes the place of brand-symbol and brand-wordmark where both are given.
brand-symbol The brand's symbol: comp.app-bar.brand.symbol.size high alone, or while the window is compact under brandLayout responsive; comp.app-bar.brand.lockup.symbol.size high (the wordmark's height) beside the wordmark in a lockup.
brand-wordmark The brand's wordmark, drawn comp.app-bar.brand.wordmark.height high: alone at every width, after the symbol in a lockup, or while the window is medium or wider under brandLayout responsive.
context Holds one control of the product's context after the brand: a Button, or a Button that opens a Menu, that says and changes the workspace, the project or the design system the screen is in. The product's own control, not restyled by the bar.
actions Holds the action items, up to three icon-only Buttons at the end, in reading order; more belong in an overflow menu the product provides.

条目

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

navigation

The one icon-only Button at the start of the top row (back, menu or close): a Button of the text variant and the medium size with an icon and no label, unless the product sets otherwise, placed in the navigation slot, which the bar lays out and does not restyle.

属性 类型 默认值 说明
label string "" Its accessible name ("Back"), as the Button's label. Required.
插槽 说明
icon Its glyph, as the Button's icon slot. A fixture item's content is this glyph.
事件 说明
click The button was activated, as the Button's click.
规格 Web SwiftUI Jetpack Compose Flutter React Native
条目 tanrei-button TanreiButton TanreiButton TanreiButton Button
label · 属性 label label contentDescription semanticLabel accessibilityLabel
click · 事件 click action onClick onPressed onPress
备注 An icon-only <tanrei-button> child with slot="navigation"; the glyph is its content. An icon-only TanreiButton in the navigation view builder. An icon-only TanreiButton in the navigationIcon lambda. An icon-only TanreiButton given as leading. An icon-only Button element passed as navigation.

action

An icon-only Button at the end of the top row, up to three in reading order: a Button of the text variant and the medium size with an icon and no label, unless the product sets otherwise, placed in the actions slot, which the bar lays out and does not restyle.

属性 类型 默认值 说明
label string "" Its accessible name ("Search"), as the Button's label. Required.
插槽 说明
icon Its glyph, as the Button's icon slot. A fixture item's content is this glyph.
事件 说明
click The button was activated, as the Button's click.
规格 Web SwiftUI Jetpack Compose Flutter React Native
条目 tanrei-button TanreiButton TanreiButton TanreiButton Button
label · 属性 label label contentDescription semanticLabel accessibilityLabel
click · 事件 click action onClick onPressed onPress
备注 An icon-only <tanrei-button> child with slot="actions"; the glyph is its content. An icon-only TanreiButton in the actions view builder. An icon-only TanreiButton in the actions lambda. An icon-only TanreiButton in the bar's actions: list. An icon-only Button element among the actions nodes.

状态

行为

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

ID 需求
APB-1 WHILE scrolled is false THE app bar SHALL fill its container with comp.app-bar.flat.container.color, raise it by comp.app-bar.flat.container.elevation and draw its bottom edge comp.app-bar.outline.width thick: in comp.app-bar.scrolled.outline.color WHILE its divider visibility (APB-18) is always, so that the edge stands still whether or not content lies under the bar, and in comp.app-bar.flat.outline.color WHILE it is scroll.
APB-2 WHILE scrolled is true THE app bar SHALL fill its container with comp.app-bar.scrolled.container.color, raise it by comp.app-bar.scrolled.container.elevation and draw its bottom edge comp.app-bar.outline.width thick in comp.app-bar.scrolled.outline.color, under either divider visibility (APB-18).
APB-3 WHEN scrolled changes THE app bar SHALL change its container color, elevation and bottom edge over comp.app-bar.motion.condition-duration with comp.app-bar.motion.condition-easing, and at once where motion is reduced; WHILE its divider visibility (APB-18) is always the bottom edge SHALL NOT change.
APB-4 THE app bar SHALL span the full width of its parent and lay out a top row at least comp.app-bar.container.height.small high: the navigation item comp.app-bar.container.padding-inline from the start edge, the title block, and the action items comp.app-bar.container.padding-inline from the end edge, with comp.app-bar.container.gap between them and comp.app-bar.actions.gap between two actions, each vertically centered in the row; a navigation item SHALL go to the start and action items to the end wherever they stand among the items; WHILE there is no navigation item the title block SHALL start comp.app-bar.title.inset from the start edge, and WHILE there are no action items it SHALL end comp.app-bar.title.inset from the end edge. Right-to-left layouts SHALL mirror the order.
APB-5 THE app bar SHALL draw a title in the top row on one line in comp.app-bar.title.typescale.small and comp.app-bar.title.color, and WHILE subtitle is not empty the subtitle on one line below it in comp.app-bar.subtitle.typescale.small and comp.app-bar.subtitle.color, the two vertically centered as a block; each SHALL be truncated at the end with an ellipsis when it does not fit. THE app bar SHALL set the title's letter-spacing, in every size, 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.
APB-6 WHILE titleAlignment is center THE app bar SHALL center the top row's title block on the bar's full width and narrow it equally on both sides, truncating its text, so that it never overlaps the navigation or actions slots, and SHALL center its text; WHILE titleAlignment is start THE app bar SHALL start the title block after the navigation slot (or at comp.app-bar.title.inset) with its text start-aligned.
APB-7 WHILE size is large and the bar is expanded THE app bar SHALL be at least comp.app-bar.container.height.large high, SHALL draw no title in its top row, and SHALL draw below the top row the title in comp.app-bar.title.typescale.large and, WHILE subtitle is not empty, the subtitle in comp.app-bar.subtitle.typescale.large, both starting comp.app-bar.title.inset from the start edge, each on one line truncated at the end, the block ending comp.app-bar.container.padding-block-end above the bar's bottom edge.
APB-8 WHILE size is large and a scrolling view is connected THE app bar SHALL shrink by the distance the content has scrolled from its top, one for one, from its expanded height to comp.app-bar.container.height.small, the expanded title block moving up with the bar's bottom edge and clipped under the top row; the top row's title SHALL be invisible while the expanded title is wholly visible, fully visible once the bar has collapsed, and in between fade in linearly with the part of the expanded title that is covered. WHEN the content scrolls back toward its top THE app bar SHALL expand the same way.
APB-9 WHERE a scrolling view is connected THE app bar SHALL take scrolled from it: true while any content lies under the bar (for a large bar, only once it has fully collapsed) and false when the content is at its top. WHILE size is large and scrolled is true THE app bar SHALL be drawn fully collapsed; WHERE nothing is connected and scrolled is false a large app bar SHALL stay expanded.
APB-10 THE app bar SHALL extend its container under the top system inset (status bar, camera cutout, window caption) and SHALL place its content below that inset and inside the left and right insets, so that its color reaches the screen's top edge while no content sits under a system bar or cutout.
APB-11 THE app bar SHALL NOT restyle its navigation and action items: each SHALL render as the icon-only Button it is, from its own tokens, and keep its own semantics, and the app bar SHALL NOT be focusable itself, so that focus moves from the navigation item to the action items in reading order. A glyph of an item that the system's icon set marks as mirrored (a navigation item's arrow_back) SHALL be mirrored in a right-to-left layout by the item's own icon helper (BTN-19): that is the icon's own behaviour, not a restyling by the app bar.
APB-12 THE app bar SHALL expose title as a heading and subtitle as text read after it, and SHALL expose the title only once WHILE size is large: the expanded title while any of it is visible, the top row's title once the bar has collapsed.
APB-13 WHILE title is empty THE app bar SHALL draw no title block (an expanded large bar then has an empty title row) and SHALL expose no heading; IF the app bar holds more than three action items or more than one navigation item THE app bar SHALL still render them, and in debug builds report that the extra actions belong in an overflow menu or that a bar has one navigation button.
APB-14 WHEN size names a value that the active design system does not have THE app bar SHALL render with the default value's tokens, and in debug builds report the unknown value.
APB-15 WHILE the text size is enlarged THE app bar SHALL grow its rows to hold the title and subtitle lines (its heights are minimums), SHALL keep each on one line truncated at the end, and SHALL NOT scale the navigation and action items it holds.
APB-16 THE app bar 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 app bar is shown THE app bar SHALL draw itself for the new direction at once, without a motion of its own, keeping its size and the scroll state it follows.
APB-17 THE app bar SHALL lay out its title and its subtitle as text of its own direction, isolated from the text around it: each takes the base direction of its first strong character, or the layout direction where it has none, so that a left-to-right word, a number with its sign or unit, a telephone number and an address keep their own order in a right-to-left layout and reorder nothing beside them; THE app bar SHALL still place each and align its lines by the layout direction, not by the text's own, and SHALL cut a title or a subtitle that does not fit (APB-5, APB-7) at the end of its own direction, so that a left-to-right label in a right-to-left layout loses its right end and never its beginning.
APB-18 THE app bar SHALL draw its bottom edge (APB-1, APB-2) as its dividerVisibility names: WHILE dividerVisibility is auto, as comp.app-bar.outline.visibility names, which follows sys.behavior.divider-visibility unless a design system sets the app bar apart; WHILE dividerVisibility is always or scroll, as that value names, whatever the tokens say. WHEN dividerVisibility, or the token it follows, changes THE app bar SHALL draw the other form at once, moving no part and keeping the scroll position and focus; WHEN dividerVisibility names a value the app bar does not define THE app bar SHALL treat it as auto and in debug builds report the unknown value. A platform that cannot draw a choice SHALL fall back to the first value, always, and state that in its README.
APB-19 WHERE the product gives the app bar a brand (an image in brand, brand-symbol or brand-wordmark) THE app bar SHALL place it at the start of the top row, after the navigation item at comp.app-bar.actions.gap from it, or comp.app-bar.container.padding-inline from the start edge WHILE no navigation item is drawn, with the title block after it at comp.app-bar.container.gap; the brand SHALL take a cell at least the minimum target high and wide, padded at its start and end by half the minimum target less comp.app-bar.brand.symbol.size, its images centred on the row's centre line, so that a symbol stands where an icon button's icon stands and a wordmark keeps that inset from the cell's edges. Right-to-left layouts SHALL mirror the order.
APB-20 THE app bar SHALL draw the image in brand comp.app-bar.brand.image.height high, the symbol comp.app-bar.brand.symbol.size high and the wordmark comp.app-bar.brand.wordmark.height high, each as wide as its own proportions make it, and SHALL give the brand comp.app-bar.brand.color, which an image drawn in the current color takes and an image of its own colors keeps. WHILE the brand is a lockup THE app bar SHALL draw the symbol and then the wordmark in one row, comp.app-bar.brand.lockup.gap apart, aligned in the row's block axis as comp.app-bar.brand.lockup.alignment names (center, start or end).
APB-21 WHERE the brand holds one image, a symbol alone or a wordmark alone THE app bar SHALL show it at every window width. WHERE it holds both a symbol and a wordmark, WHILE brandLayout is lockup THE app bar SHALL show both as a lockup (APB-20), and WHILE brandLayout is responsive THE app bar SHALL show the wordmark WHILE the window class is medium or expanded and the symbol WHILE it is compact, never both: the window class of the app shell the bar stands in, or, outside one, the window's width against sys.breakpoint.medium. WHEN the window class changes THE app bar SHALL show the other at once, without a motion of its own, the brand's link and its focus unchanged.
APB-22 THE app bar SHALL expose the brand as one link to brandHref named by brandLabel — or, WHILE brandHref is empty, as one image named by brandLabel — between the navigation item and the action items in reading order, and SHALL hide the brand's images from assistive technology, so that the product's name is read once whichever arrangement is shown. THE brand's link SHALL be a stop in the tab order and SHALL draw the focus indicator around its cell, in the shape comp.app-bar.brand.shape.
APB-23 IF brandLayout names a value the app bar does not define THE app bar SHALL treat it as lockup and in debug builds report it; IF brand holds an image together with brand-symbol or brand-wordmark THE app bar SHALL show the image in brand alone and in debug builds report the others; IF the bar has a brand and brandLabel is empty, or a brand slot holds more than one image, THE app bar SHALL still draw what it holds and in debug builds report what is missing or extra.
APB-24 WHILE the brand is a lockup THE app bar SHALL draw the symbol comp.app-bar.brand.lockup.symbol.size high, which is the wordmark's height (comp.app-bar.brand.wordmark.height) unless a design system sets it apart, so that the symbol and the wordmark stand at one height; a symbol shown alone keeps comp.app-bar.brand.symbol.size.
APB-25 WHERE the product puts a control in context THE app bar SHALL place it at the start of the top row after the brand, at comp.app-bar.actions.gap from the brand's cell (from the navigation item WHILE no brand is drawn, and comp.app-bar.container.padding-inline from the start edge WHILE neither is), vertically centred in the row, with the title block after it at comp.app-bar.container.gap; SHALL NOT restyle it, as APB-11 says of the navigation and action items; and SHALL keep it in reading order after the brand and before the title block and the action items. Right-to-left layouts SHALL mirror the order.

各平台名称对照

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

规格 Web SwiftUI Jetpack Compose Flutter React Native
组件 tanrei-app-bar TanreiAppBar TanreiAppBar TanreiAppBar AppBar
size · 属性 size size size size size
title · 属性 headline title title title title
subtitle · 属性 subtitle subtitle subtitle subtitle subtitle
titleAlignment · 属性 titleAlignment titleAlignment titleAlignment centerTitle titleAlignment
brandHref · 属性 brandHref brandHref brandHref brandHref brandHref
brandLabel · 属性 brandLabel brandLabel brandLabel brandLabel brandLabel
brandLayout · 属性 brandLayout brandLayout brandLayout brandLayout brandLayout
scrolled · 属性 scrolled isScrolled scrollBehavior scrolledUnder scrolled
dividerVisibility · 属性 dividerVisibility dividerVisibility dividerVisibility dividerVisibility dividerVisibility
备注 title is the headline property and attribute, because HTML's global title attribute would show a tooltip over the whole bar. titleAlignment is the title-alignment attribute. The slots are navigation, context and actions. A web-only scroll-target attribute names the id of the scrolling element to connect (default: the document's scrolling element; none connects nothing), from which the bar sets scrolled itself. A web-only heading-level (default 1) sets the title's heading level. Insets are env(safe-area-inset-top|left|right). dividerVisibility is the divider-visibility attribute (auto, always, scroll); auto reads --tanrei-comp-app-bar-outline-visibility from the cascade with a style query, and where the browser has none the bar writes the name it read on its container when it renders. The brand: brand-href, brand-label and brand-layout (lockup | responsive); its images are children with slot="brand", slot="brand-symbol" or slot="brand-wordmark" (an <img> or an inline <svg>), which the bar sizes from its tokens, marks aria-hidden and draws inside its own link (part="brand"). The link is the bar's: a router that follows links by their clicks reads it from the click's composed path. The window class is the enclosing <tanrei-app-shell>'s, else matchMedia against sys.breakpoint.medium. TanreiAppBar(_ title:, subtitle:, size:, titleAlignment:, isScrolled: Bool? = nil) { navigation } actions: { … }, placed with .safeAreaInset(edge: .top) in a NavigationStack whose system bar is hidden; the system bar's heights, title font and edge cannot be set from the tokens. Hiding it must not lose the interactive back swipe: the implementation keeps it working. The connected scroll view is the one marked .tanreiAppBarScrollSource(), applied after the .safeAreaInset that holds the bar (the inset's content sees only the environment where the inset is applied); it connects on iOS 18 and macOS 15 and later. isScrolled: nil follows it, a value overrides it. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). Compose idiom (as TopAppBar): TanreiAppBar(title, navigationIcon = { … }, actions = { … }, subtitle, size, titleAlignment, scrollBehavior, windowInsets). scrollBehavior (TanreiAppBarDefaults.pinnedScrollBehavior() for small, .collapseScrollBehavior() for large) is connected with Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), and its state carries scrolled and the collapse; without one the bar is flat and expanded, and a state created with a given offset draws the scrolled fixtures. windowInsets defaults to the status bars plus the horizontal display cutout. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). Flutter idiom (as AppBar and SliverAppBar.large): TanreiAppBar is a PreferredSizeWidget for Scaffold.appBar, with leading, actions, title (a String), subtitle, size and centerTitle (true for center). scrolledUnder: null follows the ScrollNotifications of the scaffold's body, as AppBar's scrolled-under state does; a bool overrides it. A large bar that collapses is TanreiSliverAppBar inside a CustomScrollView. Insets through SafeArea/MediaQuery.padding. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25). navigation and actions are React nodes (an icon-only Button, and a fragment of up to three). The scroll connection is a hook: const scroll = useAppBarScroll() gives scroll.onScroll for a ScrollView or FlatList and scroll.state for the bar's scrollState prop, which sets scrolled and the collapse; without it the bar draws what scrolled says. Insets come from the bar's own insets prop, side by side, falling back to TanreiProvider's insets; the package takes no safe-area dependency, and a product that uses react-native-safe-area-context passes its useSafeAreaInsets() to either. Not yet: the title's letter-spacing by the script of its text (APB-5, PRS-20). Not built on this platform yet: dividerVisibility (auto, always, scroll; APB-18) — the bar still draws its bottom edge from its condition's outline color, as scroll does. Not built on this platform yet: the brand (brandHref, brandLabel, brandLayout and its slots, APB-19 to APB-24). Not built on this platform yet: the context slot (APB-25).

令牌

令牌 引用 解析值(浅色)
--tanrei-comp-app-bar-actions-gap sys.target.spacing 8px
--tanrei-comp-app-bar-brand-color sys.color.on-surface #1b1b1b
--tanrei-comp-app-bar-brand-image-height comp.app-bar.brand.wordmark.height 40px
--tanrei-comp-app-bar-brand-lockup-alignment — 0
--tanrei-comp-app-bar-brand-lockup-gap sys.space.space100 8px
--tanrei-comp-app-bar-brand-lockup-symbol-size comp.app-bar.brand.wordmark.height 40px
--tanrei-comp-app-bar-brand-shape sys.shape.corner.full 9999px
--tanrei-comp-app-bar-brand-symbol-size sys.icon.medium 24px
--tanrei-comp-app-bar-brand-wordmark-height — 40px
--tanrei-comp-app-bar-container-gap sys.space.space100 8px
--tanrei-comp-app-bar-container-height-large — 120px
--tanrei-comp-app-bar-container-height-small — 64px
--tanrei-comp-app-bar-container-padding-block-end sys.space.space150 12px
--tanrei-comp-app-bar-container-padding-inline sys.space.space50 4px
--tanrei-comp-app-bar-flat-container-color sys.color.surface #ffffff
--tanrei-comp-app-bar-flat-container-elevation sys.elevation.level0
--tanrei-comp-app-bar-flat-outline-color — #000000 · 0%
--tanrei-comp-app-bar-motion-condition-duration sys.motion.role.state.large 250ms
--tanrei-comp-app-bar-motion-condition-easing sys.motion.easing.state cubic-bezier(0.2, 0, 0, 1)
--tanrei-comp-app-bar-outline-visibility sys.behavior.divider-visibility 0
--tanrei-comp-app-bar-outline-width sys.border.hairline 1px
--tanrei-comp-app-bar-scrolled-container-color sys.color.surface #ffffff
--tanrei-comp-app-bar-scrolled-container-elevation sys.elevation.level0
--tanrei-comp-app-bar-scrolled-outline-color sys.color.outline-variant #000000 · 8%
--tanrei-comp-app-bar-subtitle-color sys.color.on-surface-variant #4b4b4b
--tanrei-comp-app-bar-title-color sys.color.on-surface #1b1b1b
--tanrei-comp-app-bar-title-inset sys.space.space200 16px
--tanrei-comp-app-bar-subtitle-typescale-large sys.typescale.body 400 14px/1.5714
--tanrei-comp-app-bar-subtitle-typescale-small sys.typescale.body-small 400 13px/1.5385
--tanrei-comp-app-bar-title-typescale-large sys.typescale.heading-1 500 32px/1.25
--tanrei-comp-app-bar-title-typescale-small sys.typescale.heading-4 500 18px/1.4444

测试样例

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

生成自 specs/app-bar.spec.json, tokens/comp/app-bar.tokens.json, design/tokens/

指南

何时使用

在屏幕顶部使用应用栏,用来说明用户身在何处,带他们返回或打开菜单,并提供属于整个屏幕的少量操作:搜索、分享、账户。一个屏幕只有一个应用栏。

要在应用的各个顶级目的地之间切换,请使用导航栏或导航抽屉。应用栏的菜单按钮可以打开模态导航抽屉。Tanrei 没有底部应用栏:在 compact 屏幕底部放置操作,是工具栏的职责。

如何选择尺寸和标题位置

选项 效果 适用于
Small(默认) 只有一行:导航按钮、标题和操作。 大多数屏幕,以及所有从另一个屏幕进入的屏幕。
Large 在顶部一行的下方,用单独的一行显示更大的标题。内容滚动时,它随滚动距离一比一地折叠进顶部一行,顶部一行的标题同时淡入。内容回到顶端时,它重新展开。 产品的顶级屏幕,在那里标题也是这个屏幕的标志。
titleAlignment 为 start(默认) 标题紧跟在导航按钮之后。 大多数应用栏。
titleAlignment 为 center 标题相对于整个应用栏居中,并在两侧等量收窄,因此绝不会伸到按钮下面。 沿用 iOS 居中标题的产品。展开的大标题始终从起始侧开始。

设计系统可以增加尺寸。在 SwiftUI、Compose、Flutter 和 React Native 上,比 small 更高的尺寸会像 large 一样拥有单独的标题行。在 Web 上,设计系统增加的每个尺寸都有单独的标题行。m3-like 预设目前还没有 Material 的 medium 尺寸。

滚动

  • 底边保持不动。 在默认系统中,应用栏在静止时和有内容位于其下方时都会画出底边的一条细线。应用栏和应用外壳的页眉一样,是一个留在原位的区域的边缘,所以这条线不会随滚动出现或消失。
  • 也可以跟随滚动。 把 dividerVisibility 设为 scroll(在 Web 上是 divider-visibility),底边就只在有内容位于应用栏下方时才画出,让这条线本身说明内容已经移动。设计系统可以用 sys.behavior.divider-visibility 为所有应用栏、面板和对话框作出这一选择,或者用 comp.app-bar.outline.visibility 只为应用栏作出选择。cupertino 和 m3-like 按照它们的原型选择 scroll。
  • 平的外观与滚动后的外观。 内容停在顶端时,应用栏是平的。一旦有内容位于它下方,应用栏就呈现滚动后的外观:在 m3-like 中是带色调的容器,在 cupertino 中是有填充的容器。这一变化按应用栏的状态动效缓动完成;在减弱动态效果时则立即完成。
  • 大号应用栏只有在完全折叠之后才算滚动后的状态。 在此之前,折叠本身已经表明内容移动了。
  • 应用栏留在原处。 内容向下滚动时它不会隐藏。隐藏是屏幕的滚动行为,不是应用栏的。

项

  • 一个应用栏最多放一个导航按钮:从另一个屏幕进入的屏幕用“返回”,顶级屏幕用“菜单”,全屏任务用“关闭”。
  • 操作不要超过三个。其余的放进溢出菜单:一个打开 Tanrei 菜单的“更多选项”图标按钮。第四个操作和第二个导航按钮会在调试构建中报告,但仍会绘制出来。
  • 按钮的外观与在其他任何地方相同。应用栏只负责排列它们,从不给它们改色。
  • 通向某个地方的按钮是链接:给它一个 href。这样,通向父页面的返回按钮,或打开某个页面的帮助操作,就是真正的链接,画出来仍是同样的按钮。沿历史记录返回的返回按钮仍然是按钮。
  • 在 Web 上,搜索可以以图标触发器的形式(bar 设为 icon)作为操作之一:一个纯图标按钮,用来打开搜索的对话框或全屏视图。

品牌

产品可以把自己的标志放进栏中,作为通往首页的链接。把地址(brandHref,Web 上为 brand-href)和产品名称(brandLabel)交给栏:栏会在你提供的图片外绘制一个链接,并用该名称为它命名,同时对辅助技术隐藏这些图片,因此名称只会被读一次。栏把品牌放在导航按钮之后,占一个与图标按钮同样大小的单元格;除非你的图片自带颜色,否则会给它 comp.app-bar.brand.color。

  • 一张图片。 把一个标志文件放进 slot="brand",高度为 comp.app-bar.brand.image.height。
  • 只有符号。 放进 slot="brand-symbol",高度为 comp.app-bar.brand.symbol.size,位于图标按钮的图标所在的位置。
  • 只有文字标。 放进 slot="brand-wordmark",高度为 comp.app-bar.brand.wordmark.height。
  • 符号和文字标一起。 两者都提供。默认(brandLayout 为 lockup)时它们并排,间距为 comp.app-bar.brand.lockup.gap,按 comp.app-bar.brand.lockup.alignment 对齐。此时符号与文字标同高(comp.app-bar.brand.lockup.symbol.size)。
  • 按窗口宽度切换。 两者都提供,并把 brandLayout 设为 responsive(Web 上为 brand-layout):窗口为 medium 或更宽时,栏显示文字标;为 compact 时显示符号,两者从不同时显示。在应用外壳中,它跟随外壳的窗口类别。

栏会为每张图片确定尺寸,并保持其比例。不要用标题来写产品名称:标题是屏幕的名称。SwiftUI、Compose、Flutter 和 React Native 尚未绘制品牌。

本站的页眉在任何宽度下都只显示 Tanrei 的文字标。

推荐

  • 把标题写成屏幕的名称,例如“收件箱”或“季度报告”。保持简短:它只占一行,放不下时以省略号截断。
  • 副标题用来提供有助于区分两个相似屏幕的背景信息:账户、状态、编辑时间。
  • 为所有顶级屏幕选定一种尺寸,为其余屏幕选定另一种。

避免

  • 不要在插槽里放图标按钮以外的任何东西:不放文本字段,不放搜索框,不放标签页,不放分段控件。一排标签页应放在应用栏下方,更下方的标签页视图可以与它关联。
  • 不要把“新建”这样的主要操作放进应用栏。请使用主操作按钮。
  • 不要让标题出现第二行,也不要把它做成链接。

无障碍

角色
none
标注
The title is the screen's heading (a level 1 heading on the web unless the product sets another level). The subtitle is read after it. The navigation and action items, and the control in context, are named by their own labels. The brand is one link to the product's first page named by brandLabel (the product's name), whichever of its images is shown; its images are hidden from assistive technology.
最小目标
即使外观尺寸更小,点击区域也满足最小目标尺寸。 minimum 32px · pointer 44px · spacing 8px · touch 48px

键盘操作

按键 动作
Tab Moves focus to the navigation item, then to the brand's link, then to the control in context, then through the action items; the bar itself is not a tab stop.

备注

  • The app bar has no role of its own and takes no input: its buttons are the product's icon-only Buttons, which meet the minimum target themselves (BTN-5). The bar is not a landmark, because only the product knows whether it is its page's banner; a product that wants one wraps the bar in its own header element.
  • The title is truncated rather than wrapped even at 200% text size: the bar's rows grow with the text, but a bar of several lines would push the screen's content away. The full title stays available to assistive technology.
  • Where both titles of a large bar are partly visible, only the expanded one is exposed, so the heading is never read twice.

生成自 specs/app-bar.spec.json, tokens/sys/measure.tokens.json

组件负责的部分

  • 应用栏没有自己的角色,也永远不可聚焦。Tab 键按阅读顺序从导航按钮依次移到各个操作。每个按钮保留自己的角色、名称和最小目标,带 href 的按钮会暴露为链接。
  • 标题会暴露为屏幕的标题元素;在 Web 上,除非 heading-level 另有指定,它是一级标题。副标题紧随其后朗读。空标题什么也不绘制,也不暴露标题元素。
  • 大号应用栏在折叠过程中会绘制两个标题,但只暴露一个:展开的标题只要还有一部分可见,就暴露它;应用栏折叠完成后,暴露顶部一行的标题。标题元素绝不会被朗读两次。
  • 应用栏不是地标。它是不是页面的横幅(banner),只有你知道。
  • 文本变大时,应用栏的各行会随之变高,因为行高只是最小高度。标题和副标题始终只占一行,即使在 200% 时也是截断而不是换行,所以应用栏绝不会把内容挤走。辅助技术仍能获得完整的标题。图标按钮不会缩放。
  • 应用栏的方向取决于它所在的位置。在从右到左的布局中它会镜像:导航按钮在右,操作在左。图标集标记为需要镜像的图标(例如返回箭头)由它自己的按钮镜像,而不是由应用栏镜像。
  • 标题和副标题各自按自身文本的方向排布,与周围的文本相互隔离。从右到左的布局中,一个从左到右书写的名称会保持原有顺序,并且在它自己的末尾截断,绝不在开头截断。
  • 操作超过三个、导航按钮超过一个,以及使用了设计系统中没有的尺寸,都会在调试构建中报告。

已知的平台差距:

  • SwiftUI、Compose、Flutter 和 React Native:dividerVisibility 要等这些平台跟上。在此之前,它们像 scroll 一样,只在有内容位于应用栏下方时才画出底边。
  • SwiftUI、Compose、Flutter 和 React Native:从右到左的规则(在图标集标记之处镜像图标、标题按自身方向排布)要等这些平台跟上,带 href 的按钮也是如此。
  • Web:所有尺寸都跟随 rem,因此调大浏览器的文本大小时,图标按钮会随文本一起变大。只放大 Tanrei 的文字则不会。
  • Web:如果大号应用栏跟随文档自身的滚动,又以 position: sticky 位于文档流中,那么内容除了随滚动移动之外,还会因应用栏的折叠而移动,于是在应用栏折叠期间,内容的移动速度是平时的两倍。请把会折叠的应用栏放在某个滚动元素(scroll-target)的上方,或放在固定的页眉里。
  • Web:每个图标按钮都位于一个单元格中,其大小等于当前所用指针的最小目标,鼠标是 44;因此两个操作的中心间距是 52,而 Compose 和 Flutter 按 48 的触摸目标计算,画出来的间距是 56。
  • SwiftUI:应用栏只有在 iOS 18 和 macOS 15 及以上才会跟随它的滚动视图。在此之前什么都不会连接,应用栏按 isScrolled 的值绘制。
  • SwiftUI:对已连接的大号应用栏设置 isScrolled: true,它会按折叠后的样子绘制,但在布局中仍保留展开时的高度,所以内容停在顶端时,上方会露出一段空隙。
  • SwiftUI:系统栏隐藏时,应用栏通过替换导航控制器的 pop 手势 delegate,让边缘滑动返回继续可用。这一点只在 iOS 26.5 上验证过。大号应用栏一次只暴露一个标题这一点,尚未用 VoiceOver 验证。
  • Flutter:大号的 TanreiAppBar 不会随内容一起折叠,因为盒状 widget 无法随它下方的滚动视图收缩。它忽略滚动通知,保持展开,只有在 scrolledUnder 为 true 时才按折叠后的样子绘制。需要会折叠的应用栏时,请使用 TanreiSliverAppBar。
  • Flutter:preferredSize 读取不到主题,所以报告的是无界的高度。Scaffold 会让应用栏自行决定尺寸,但你自己的布局用不了这个数值。
  • Compose:滚动停在哪里,折叠就停在哪里,所以大号应用栏可能停在折叠到一半的位置。它不会像 Material 的应用栏那样,在快速滑动之后吸附到完全展开或完全折叠。规格并不要求吸附。
  • React Native:要让大号应用栏随内容一比一地折叠,需要像上面的示例那样,把应用栏叠放在滚动视图之上,并给内容加上与应用栏等高的内边距。折叠、边衬区以及屏幕阅读器朗读的内容,尚未在真机上验证。
  • 所有平台:在 cupertino 下,44 点高的顶部一行在容纳图标按钮时会变为 48,因为图标按钮的触摸目标是 48,而最小目标优先。在 Web 上,它只在粗略指针下才变高,因为鼠标的目标是 44。大号应用栏展开的那一行也比 cupertino 的容器高度高 1 点。
  • 所有平台:有副标题时,展开的标题在应用栏完全折叠之前就已被遮住。这段时间里暴露哪个标题,规格尚未说明。各平台都在展开的标题被遮住的那一刻,把标题元素移到顶部一行。

需要你做的事

  • 给每个应用栏一个标题。它是屏幕的标题元素。
  • 给每个图标按钮一个标签,例如“返回”或“搜索”。
  • 在 Web 上,如果页面已经有一级标题,请设置 heading-level;如果应用栏是页面的横幅,请用 <header> 包住它。
  • 连接屏幕的滚动视图,或者自己设置 scrolled,让应用栏在内容位于其下方时有所体现。
  • 在 React Native 上,把窗口的边衬区传给 TanreiProvider。在 React Native 和 Compose 上,不在窗口顶部的应用栏要使用不同的边衬区(insets={{ top: 0 }},或你自己的 windowInsets)。
  • 标题要简短。以省略号截断的标题仍会被完整朗读,但视力正常的用户只能看到它的开头。