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();
相关推荐
爱丶不疚几秒前
搞不清 CommonJS 与 ESM,你是否也有这些疑问🤔
前端·node.js
YIAN5 分钟前
http无状态?State来展示!从基础路由到鉴权守卫,吃透 SPA 前端路由核心
前端·react.js
__zRainy__18 分钟前
Node系列 · Node基础:全局变量与全局对象
开发语言·前端·javascript
码云骑士23 分钟前
104-实战论文搜索引擎-ArXiv爬取-Milvus存储-RAG问答-Gradio前端
前端·python·搜索引擎·milvus
sunly_34 分钟前
TypeScript总结:15、类型速查
前端·javascript·typescript
Brown.alexis35 分钟前
es6知识点3-自备使用
前端·javascript·es6
2601_9539880737 分钟前
Ricon组态系统vs传统组态软件:为什么选择新一代Web组态平台
前端·后端·物联网·tcp/ip·数学建模·前端框架
天空之城--42 分钟前
Claude Code 高效开发 Web 2D/3D 完全指南:心法、自定义 Skill 体系与社区技能包实战
前端·3d
IT_陈寒1 小时前
SpringBoot自动配置坑了我三天,原来漏了这个注解
前端·人工智能·后端
逝水无殇1 小时前
HTML 文本格式化详解:掌握 <strong>、<em>、<mark>、<del> 等常用标签
前端·javascript·html