ios移动端浏览器,vh高度和页面实际高度不匹配的解决方案

最近写h5页面,在浏览器顶部和底部的功能栏,会动态隐藏,导致页面高度和可视高度不匹配,导致部分元素被遮挡。

原因

浏览器顶部和底部的功能栏,是占用100vh的高度的。导致页面部分底部被遮挡。

所以常规页面设置vh方式就有问题。

解决方案

我的一个方案就是,通过css的var变量,配合js,动态修改变量的值,以达到页面高度变化时,自动修改css变量。

页面使用的时候,同时使用css变量。

定义了2个变量,--vh和--svh。

--vh是当前页面可视窗口的高度。

--svh是可视窗口的高度 - 安全区域底部高度。也就是手机的底部bar。

使用方式:

  1. 页面全屏展示,不需要考虑安全区域底部高度

height: calc(var(--vh, 1vh) * 100);

  1. 页面考虑安全区域底部高度时

height: calc(var(--svh, 1vh) * 100);

完整的js文件如下:

javascript 复制代码
//使用场景:页面全屏展示,不需要考虑安全区域底部高度
// height: calc(var(--vh, 1vh) * 100);
//使用场景:页面有安全区域底部高度,需要考虑安全区域底部高度
// height: calc(var(--svh, 1vh) * 100);

export function updateVh(height: number) {
  // 容器高度
  const vh = window.innerHeight * 0.01;
  // 去除ios安全区域底部高度
  const svh = (window.innerHeight - getSafeAreaInsetBottom()) * 0.01;
  
  document.documentElement.style.setProperty('--vh', `${vh}px`);
  document.documentElement.style.setProperty('--svh', `${svh}px`);
}

/**
 * 获取安全区域底部高度(safe-area-inset-bottom)
 * @returns {number} 安全区域底部高度(单位:px,不支持时返回 0)
 */
export function getSafeAreaInsetBottom() {
  // 创建临时元素用于计算
  const tempElement = document.createElement('div');
  
  // 设置样式:利用 env() 函数获取安全区域值,默认值为 0px(兼容不支持的浏览器)
  Object.assign(tempElement.style, {
    position: 'fixed', // 脱离文档流,不影响布局
    visibility: 'hidden', // 隐藏元素,仅用于计算
    paddingBottom: 'env(safe-area-inset-bottom, 0px)', // 核心:应用安全区域值
    left: '0',
    bottom: '0'
  });
  
  // 将临时元素添加到页面
  document.body.appendChild(tempElement);
  
  // 获取计算后的样式值(如 "34px")
  const computedStyle = window.getComputedStyle(tempElement);
  const paddingBottomValue = computedStyle.paddingBottom;
  
  // 移除临时元素(清理痕迹)
  document.body.removeChild(tempElement);
  
  // 转换为数字(去除单位),确保返回数值类型
  return parseFloat(paddingBottomValue) || 0;
}

function initAndWatchVh() {
  // 初始化
  let availableHeight = window.innerHeight;
    console.log('load', availableHeight);

  updateVh(availableHeight);

  // IOS需要load以后再触发,不然获取不到安全区域底部高度
  window.addEventListener('load', () => {
    let availableHeight = window.innerHeight;
    updateVh(availableHeight);
  });

  // 监听窗口大小变化(工具栏隐藏/显示)
  window.addEventListener('resize', () => {
    availableHeight = window.innerHeight;
    console.log('resize', availableHeight);
    updateVh(availableHeight);
  });
}

initAndWatchVh();
相关推荐
烛阴3 小时前
为什么游戏开发者都爱 Lua?零基础快速上手指南
前端·lua
大猫会长3 小时前
tailwindcss出现could not determine executable to run
前端·tailwindcss
Moonbit3 小时前
MoonBit Pearls Vol.10:prettyprinter:使用函数组合解决结构化数据打印问题
前端·后端·程序员
533_3 小时前
[css] border 渐变
前端·css
云中雾丽4 小时前
flutter的dart语言和JavaScript的消息循环机制的异同
前端
地方地方4 小时前
Vue依赖注入:provide/inject 问题解析与最佳实践
前端·javascript·面试
云中雾丽4 小时前
dart的继承和消息循环机制
前端
世界哪有真情4 小时前
Trae 蓝屏问题
前端·后端·trae
Moment4 小时前
NestJS 在 2025 年:对于后端开发者仍然值得吗 😕😕😕
前端·后端·github