---
url: /mobile/layout.md
---
# 布局与导航壳

移动页面的骨架由三段组成：**顶部导航栏**（返回 + 标题 + 右侧动作）、**中部内容滚动区**（单列信息流）、**底部固定区**（标签栏或吸底操作栏）。桌面端的「侧边菜单 + 面包屑 + 内容区」三栏结构在移动端整体让位给这一垂直壳，层级关系由页栈导航承担。

## 完整页面壳

下方演示是一个可交互的最小壳：底部标签栏切换四个真实页签，内容区独立滚动。桌面文档页里它呈现为居中手机列；真机上删除外壳装饰后即为全宽页面（配合 `max-width: 420px` 的页面壳居中，见[适配总览](/mobile/)）。

实现要点：

* **内容区独立滚动**。滚动发生在壳的内容区（`overflow-y: auto` + `overscroll-behavior: contain`），标签栏吸底不动，避免整页滚动把标签栏推走。
* **未读角标实时联动**。Tabbar 的角标读数来自页面状态（`unreadCount`），点按消息或「全部已读」后角标即时消失——标签栏不是静态装饰，必须与页面数据同源。
* **真机固定吸底 + 安全区自动适配**。页面上使用 `fixed` 默认值：脱离文档流吸底、`safe-area-inset-bottom` 自动适配全面屏并渲染等高占位；演示壳内用 `:fixed="false"` 内联（见 [Tabbar](/mobile/components/tabbar)）。
* **业务自有吸底元素用 `useSafeArea()`**。悬浮 CTA、吸底提交栏等自绘吸底元素，读取实时 insets 并补写 viewport 标记（不调用它，`env()` 在缺 `viewport-fit=cover` 的页面恒为 0）：

```js
import { useSafeArea, ensureViewportFit } from '@wil-works/evoke-business-ui'

ensureViewportFit()
const safeArea = useSafeArea() // 响应式 { top, bottom, left, right }
```

```html
<div class="float-cta" :style="{ paddingBottom: safeArea.bottom + 'px' }">…</div>
```

## 顶部导航栏

二级页面的导航栏承担三件事：返回上一页（替代桌面面包屑，见[页面导航](/mobile/navigation)）、标注当前位置（标题即位置）、承载页面级动作（右侧动作位放一个高频操作，不放按钮组）。

规则：标题始终居中且可截断；右侧动作位只放**一个**文字级高频操作（如「催办」「保存」），更多操作进底部动作面板（见[反馈与浮层](/mobile/feedback)），不要在导航栏堆按钮组。

## 吸底操作栏

表单页的主按钮吸底，与标签栏互斥（一页只保留一个底部固定区）。内容不足一屏时按钮贴近表单，超屏滚动时按钮始终可见。

吸底栏真机适配：`padding-bottom: calc(12px + env(safe-area-inset-bottom))`，按钮宽度撑满减去左右 16px 页边距。
