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 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰3 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万3 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝3 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端