说明
- 沉浸式(Immersive):状态栏/导航栏隐藏(或半隐),网页内容可延伸到屏幕四边/刘海/圆角区。适合做全屏体验,但网页需要自己做“安全区域”内边距处理。
- 非沉浸式:系统栏可见,应用内容布局在系统栏之下。默认更安全,网页通常无需特殊处理。
原理
- 沉浸式:Android 让 App 内容“铺满屏幕”,系统栏通过手势临时唤出。WebView 里的网页如果不处理,会“顶到”状态栏或被手势区遮挡。
- 非沉浸式:系统把可用区域“裁好”再交给 App,WebView 正常渲染,不会被遮挡。
android原生设置
// 开启沉浸式(推荐 sticky,允许滑动临时唤出系统栏)
WindowCompat.setDecorFitsSystemWindows(window, false)
val controller = WindowInsetsControllerCompat(window, window.decorView)
controller.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
controller.hide(WindowInsetsCompat.Type.systemBars())
// 关闭沉浸式(非沉浸式)
WindowCompat.setDecorFitsSystemWindows(window, true)
WindowInsetsControllerCompat(window, window.decorView)
.show(WindowInsetsCompat.Type.systemBars())
webview处理
A) 原生开了“沉浸式”
- HTML 头部加 viewport(允许内容延伸到屏幕边缘/刘海区)
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
- 使用安全区变量为页面或固定头/尾添加内边距(Chrome/Android、iOS 都兼容,未全屏时值为 0)
/* 页面整体安全区 */
html, body {
height: 100%;
/* 兼容动态地址栏推荐用 dvh/svh,WebView 通常稳定,但写上更稳 */
min-height: 100dvh;
padding-top: env(safe-area-inset-top);
padding-bottom: env(safe-area-inset-bottom);
background: #fff; /* 避免系统栏下白闪 */
}
/* 有固定头部时,避免被状态栏/刘海压住 */
.header-fixed {
position: fixed;
top: 0;
left: 0; right: 0;
padding-top: env(safe-area-inset-top);
}
/* 有底部 Tab/操作条时,避免被手势区遮挡 */
.footer-fixed {
position: fixed;
bottom: 0;
left: 0; right: 0;
padding-bottom: env(safe-area-inset-bottom);
}
- 可选:原生把状态栏高度/Insets同步给网页,做更细控制
// Kotlin:测量 insets 并注入 CSS 变量
val insets = ViewCompat.getRootWindowInsets(window.decorView)
val top = insets?.getInsets(WindowInsetsCompat.Type.statusBars())?.top ?: 0
webView.evaluateJavascript(
"document.documentElement.style.setProperty('--status-bar-height', '${top}px')",
null
)
/* 网页使用注入的变量(与 env 并用,谁有值用谁) */
.header-fixed {
padding-top: max(env(safe-area-inset-top), var(--status-bar-height, 0px));
}
B) 原生是“非沉浸式”
- 通常无需额外适配,WebView 可用区域已避开系统栏。
-
仍建议使用现代视窗单位,避免 100vh 在移动端的历史问题:
.app {
min-height: 100dvh; /* 优先 */
/* 回退 */
min-height: 100vh;
}
常见坑与建议
- 不要写死 20/24px 当状态栏高度:刘海/圆角设备会不准,统一用 env(safe-area-inset-*) 或注入变量。
- 固定头/尾必须处理安全区:尤其沉浸式下的 position: fixed 元素。
- 背景色要填满:body/html 设置背景,避免系统栏区域露出黑/白。
- Keyboard/输入法:表单页面尽量避免将输入框固定在最底部;如需固定,结合 visualViewport 或在原生侧开启 adjustResize。
一套通用最小改动方案(同时兼容两种模式)
- 原生:需要沉浸式时用 decorFitsSystemWindows(false) + hide(systemBars);不需要就开 true。
- 网页:统一加 viewport-fit=cover,全局/头/尾使用 env(safe-area-inset-*) 做内边距;页面容器用 min-height: 100dvh。
- 如需像素级一致:原生注入 --status-bar-height 作为兜底,CSS 用 max(env(...), var(--...))。
capacitor设置
import { Capacitor } from '@capacitor/core';
import { StatusBar, Style } from '@capacitor/status-bar';
const canUseStatusBar = Capacitor.isPluginAvailable?.('StatusBar')
if(!canUseStatusBar) return
await StatusBar.setOverlaysWebView({ overlay: true });
await StatusBar.setBackgroundColor({ color: '#008F91FF' });
await StatusBar.setStyle({ style: Style.Light });