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();
相关推荐
irises8 分钟前
从零实现2D绘图引擎:6.动画系统的实现
前端·数据可视化
_Jyann_10 分钟前
uniapp两种方式实现自定义tabbar
前端·javascript·uni-app
一 乐14 分钟前
数码商城系统|电子|基于SprinBoot+vue的数码商城系统(源码+数据库+文档)
java·前端·javascript·数据库·vue.js·springboot
盛夏绽放16 分钟前
新手入门:实现聚焦式主题切换动效(Vue3 + Pinia + View Transitions)
前端·vue3·pinia·聚焦式主题切换
Howie Zphile17 分钟前
NEXTJS/REACT有哪些主流的UI可选
前端·react.js·ui
fruge18 分钟前
React Server Components 实战:下一代 SSR 开发指南
前端·javascript·react.js
lichong95119 分钟前
harmonyos 大屏设备怎么弹出 u 盘
前端·macos·华为·typescript·android studio·harmonyos·大前端
irises19 分钟前
从零实现2D绘图引擎:5.5.简单图表demo
前端·数据可视化
irises20 分钟前
从零实现2D绘图引擎:5.鼠标悬停事件
前端·数据可视化
青莲84320 分钟前
Android Lifecycle 完全指南:从设计原理到生产实践
android·前端