iphone(普通屏、刘海屏)、android(奇形怪状屏)H5页面适配

混合开发中H5状态栏+顶部标题栏高度适配方案(Android+全系列iPhone)

在混合开发场景下,当状态栏+顶部标题栏由H5页面实现时,需针对Android机型动态获取真实高度、针对iPhone(含最新灵动岛机型)做机型适配,以保证H5端与APP原生端视觉高度完全一致。本文梳理完整适配逻辑,覆盖Android桥接获取、iPhone全机型(含15/14/13系列)适配。

一、基础高度定义

场景 状态栏高度 顶部标题栏高度 总高度 适用机型
普通机型(非刘海屏) 20px 44px 64px 非刘海屏iPhone/普通Android
特殊机型(刘海屏/灵动岛) 44px 44px 88px 全系列刘海屏iPhone/Android高状态栏机型

二、Android机型适配:动态获取真实高度

Android机型碎片化严重,状态栏高度因系统版本、厂商定制差异较大,禁止硬编码,需通过APP提供的桥接JS-SDK动态获取真实高度。

1. 适配逻辑

通过桥接SDK的getTitleHeight方法,获取APP原生端的状态栏、标题栏真实高度,覆盖H5硬编码值,保证视觉对齐。

2. 完整代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 确保桥接SDK已加载完成(YT为APP提供的全局桥接对象)
if (YT?.isAndroid) {
// 等待SDK初始化完成
YT.ready.then(async () => {
try {
// 获取标题栏+状态栏的完整高度信息
const res = await YT.getTitleHeight();
/**
* res参数说明(APP桥接返回)
* - res.status: 顶部系统状态栏高度(px)
* - res.height: 标题栏内容区域高度(px)
* - res.total: 状态栏+标题栏总高度(px,核心使用)
* - res.fontSize: 标题栏文字推荐字号(px,可选)
* - res.version: Android系统版本号(如18/19/30)
*/
// 动态设置H5标题栏容器高度
const headerDom = document.querySelector('.header');
const contentDom = document.querySelector('.has-header');
if (headerDom && res.total) {
headerDom.style.height = `${res.total}px`;
headerDom.style.paddingTop = `${res.status}px`; // 给标题栏内容预留状态栏高度
contentDom.style.paddingTop = `${res.total}px`; // 页面内容避开标题栏
}
} catch (err) {
// 异常降级:使用默认高度64px
console.error('Android获取标题栏高度失败,降级为默认值', err);
document.querySelector('.header').style.height = '64px';
document.querySelector('.has-header').style.paddingTop = '64px';
}
});
}

3. 注意事项

  • 必须等待YT.ready完成后调用,避免SDK未初始化导致报错;
  • 增加异常降级逻辑,防止桥接调用失败时页面布局错乱;
  • 优先使用res.total(总高度),避免单独拼接status+height出现误差。

三、iPhone机型适配:全系列机型覆盖(含灵动岛)

iPhone机型适配核心是区分「非刘海屏」「刘海屏」「灵动岛机型」,其中灵动岛(14 Pro/15 Pro系列)不影响顶部标题栏高度,仍按刘海屏逻辑适配(总高度88px)。

1. iPhone全机型尺寸参数(适配依据)

机型系列 设备宽(px) 设备高(px) 设备像素比(DPR) 顶部总高度 备注
非刘海屏(8/8P/SE系列) 320~414 568~736 2/3 64px 状态栏20px+标题栏44px
X/XS/12 mini 375/360 812/780 3 88px 状态栏44px+标题栏44px
XR/XS Max 414 896 2/3 88px 同上
12/13/14(非Pro) 390 844 3 88px 同上
12/13 Pro Max 428 926 3 88px 同上
14/15 Pro/Pro Max(灵动岛) 393/430 852/932 3 88px 灵动岛不影响顶部高度,仅需避开灵动岛区域(标题栏仍88px)
15/15 Plus 414/428 896/926 3 88px 同上

2. 完整适配方案

步骤1:配置viewport-fit(核心前置)

<head>标签中配置viewport-fit=contain,确保H5内容仅展示在安全区域内,避免被刘海/灵动岛遮挡:

1
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=contain">
  • contain:H5展示区域限定在设备安全区(不包含刘海/灵动岛/底部手势栏),无需手动计算遮挡区域;
  • 若需全屏展示(如沉浸式页面),可改用cover,但需通过safe-area-inset-top补充顶部内边距。

步骤2:CSS媒体查询(覆盖全系列iPhone)

通过媒体查询匹配不同机型,设置标题栏高度,兼容最新灵动岛机型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/* 基础样式:非刘海屏iPhone/默认样式(64px总高度) */
.header {
height: 64px;
padding-top: 20px; /* 状态栏高度 */
box-sizing: border-box;
}
.has-header {
padding-top: 64px; /* 页面内容避开标题栏 */
}

/* ========== 刘海屏/灵动岛iPhone适配 ========== */
/* iPhone X/XS/12 mini */
@media only screen and (device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3),
only screen and (device-width: 360px) and (device-height: 780px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

/* iPhone XR/XS Max */
@media only screen and (device-width: 414px) and (device-height: 896px) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

/* iPhone 12/13/14(非Pro) */
@media only screen and (device-width: 390px) and (device-height: 844px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

/* iPhone 12/13 Pro Max */
@media only screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

/* iPhone 14/15 Pro(灵动岛) */
@media only screen and (device-width: 393px) and (device-height: 852px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
/* 可选:灵动岛区域避开(若标题栏内容需居中) */
/* padding-left: 30px;
padding-right: 30px; */
}
.has-header {
padding-top: 88px;
}
}

/* iPhone 14/15 Pro Max(灵动岛) */
@media only screen and (device-width: 430px) and (device-height: 932px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

/* iPhone 15/15 Plus */
@media only screen and (device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3),
only screen and (device-width: 428px) and (device-height: 926px) and (-webkit-device-pixel-ratio: 3) {
.header {
height: 88px;
padding-top: 44px;
}
.has-header {
padding-top: 88px;
}
}

步骤3:JS判断机型(动态控制样式/逻辑)

通过userAgent+屏幕尺寸+DPR判断iPhone机型,可用于动态添加类名、特殊逻辑处理(如灵动岛机型的内容避开):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// 封装iPhone机型判断工具函数
const IPhoneDetector = {
// 是否为iPhone设备
isIphone: () => /iphone/gi.test(window.navigator.userAgent),
// 是否为刘海屏/灵动岛iPhone(含全系列新款)
isSpecialIphone: () => {
if (!IPhoneDetector.isIphone()) return false;
const ratio = window.devicePixelRatio || 0;
const width = window.screen.width;
const height = window.screen.height;

// 定义所有特殊机型的尺寸规则
const specialModels = [
// X/XS
{ ratio: 3, width: 375, height: 812 },
// XS Max/XR
{ ratio: 3, width: 414, height: 896 },
{ ratio: 2, width: 414, height: 896 },
// 12 mini
{ ratio: 3, width: 360, height: 780 },
// 12/13/14(非Pro)
{ ratio: 3, width: 390, height: 844 },
// 12/13 Pro Max
{ ratio: 3, width: 428, height: 926 },
// 14/15 Pro(灵动岛)
{ ratio: 3, width: 393, height: 852 },
// 14/15 Pro Max(灵动岛)
{ ratio: 3, width: 430, height: 932 },
// 15/15 Plus
{ ratio: 3, width: 414, height: 896 },
{ ratio: 3, width: 428, height: 926 }
];

// 匹配是否为特殊机型
const isMatch = specialModels.some(model =>
model.ratio === ratio && model.width === width && model.height === height
);

// 为根元素添加类名,方便CSS适配
if (isMatch) {
document.documentElement.classList.add('iphone-special'); // 刘海屏/灵动岛机型
// 可选:区分灵动岛机型
if ((width === 393 && height === 852) || (width === 430 && height === 932)) {
document.documentElement.classList.add('iphone-dynamic-island');
}
} else {
document.documentElement.classList.add('iphone-normal'); // 普通非刘海屏机型
}
return isMatch;
}
};

// 初始化判断
IPhoneDetector.isSpecialIphone();

// 示例:动态设置标题栏高度
if (IPhoneDetector.isIphone()) {
const headerDom = document.querySelector('.header');
if (IPhoneDetector.isSpecialIphone()) {
headerDom.style.height = '88px';
headerDom.style.paddingTop = '44px';
} else {
headerDom.style.height = '64px';
headerDom.style.paddingTop = '20px';
}
}

三、完整适配流程总结

  1. 前置配置:在<head>中添加viewport-fit=contain的meta标签,确保安全区展示;
  2. Android适配:通过桥接SDK动态获取状态栏+标题栏总高度,覆盖默认样式,增加异常降级;
  3. iPhone适配
    • 基础样式设置非刘海屏高度(64px);
    • CSS媒体查询覆盖全系列刘海屏/灵动岛机型(88px);
    • 可选:JS判断机型,动态控制样式或特殊逻辑(如灵动岛内容避开);
  4. 测试验证:覆盖Android多厂商机型、iPhone全系列(含15 Pro灵动岛),确保H5与APP原生端高度完全一致。

关键注意事项

  • 灵动岛机型(14/15 Pro系列):顶部标题栏高度仍为88px,仅需注意标题栏内的内容不要覆盖灵动岛区域(可通过左右内边距避开);
  • 避免硬编码:Android必须通过桥接获取真实高度,iPhone可通过媒体查询/JS适配,但需及时更新新机型尺寸;
  • 兼容性:-webkit-device-pixel-ratio是iOS浏览器兼容属性,无需额外兼容。

总结

  1. Android机型适配核心是「动态获取」:通过APP桥接SDK拿到真实高度,避免碎片化导致的高度偏差;
  2. iPhone机型适配核心是「机型匹配」:覆盖全系列(含灵动岛),通过viewport+CSS+JS组合适配,总高度统一为88px(特殊机型)/64px(普通机型);
  3. 全流程需增加降级逻辑,确保桥接失败/机型未匹配时页面布局不崩溃。

iphone(普通屏、刘海屏)、android(奇形怪状屏)H5页面适配
https://cszy.top/20201103-h5-2/
作者
csorz
发布于
2020年11月3日
许可协议