iOS 手机元素样式依赖 vh,滚动时页面高度变化导致页面展示异常
问题:iOS 手机 safari 浏览器打开页面,又或微信内打开页面时,在页面滚动时,若有元素的样式是根据 vh 进行设置时,由于底部的状态栏的出现与隐藏,会导致 vh 发生变化,从而导致页面布局出现错乱;
解决方法:
a. 修改样式,vh改为固定高度或通过 vw, rem 等进行设置;缺点是部分展示效果无法完美通过此种方式实现;不推荐,要求不高可用;
b. 在页面加载时,通过style
标签提前设置,将对应的样式提前转化为 px 单位,并设置为 !important,避免后面滚动过程中页面布局会出现错乱;完美解决所有问题,推荐。
b 的解决原理是通过在页面的 head
标签中,通过 script
标签执行js
,动态生成 style
,将样式中存在 vh
有关的元素的样式,提前转化为 px!import。主要的实现,重点在于两个逻辑,vh
转化 px
与动态生成 style
标签。
vh
转化为 px
:
function vhToPx (val) {
const h = Math.max(document.documentElement.clientHeight,window.innerHeight);
return parseFloat(h * val).toFixed(2); // 设置 px 时保留到小数点后两位
}
动态生成并写入 style
:
const cssText = '';
cssText += '.className {height:' + vhToPx(0.477216) + 'px!important;}.className {width: ' + vhToPx(0.357142) + 'px!important;height: ' + vhToPx(0.477216) + 'px!important;}';
const cssBlock = document.createElement('style');
cssBlock.innerHTML=cssText;
document.head.insertBefore(cssBlock, document.head.childNodes[document.head.childNodes.length - 1].nextSibling);
使用:
<script
//获取视口高度设置元素的固定宽高,避免 iOS 手机页面滚动高度变化时样式会乱
dangerouslySetInnerHTML={{
__html: `function vhToPx (val) {var h = Math.max(document.documentElement.clientHeight,window.innerHeight);return parseFloat(h * val).toFixed(2);}var cssText = '';cssText += '.className{height:' + vhToPx(0.477216) + 'px!important;}.className {width: ' + vhToPx(0.357142) + 'px!important;height: ' + vhToPx(0.477216) + 'px!important;}';var cssBlock = document.createElement('style');cssBlock.innerHTML=cssText;document.head.insertBefore(cssBlock, document.head.childNodes[document.head.childNodes.length - 1].nextSibling);`,
}}
/>
同理,该方法也可解决 hybrid
应用的 webview
设置通顶的问题。 hybrid
应用的 webview
设置通顶时,有些应用会使整个 title
透明,这个时候就需要我们给原本的 title
位置添加个元素进行占位,同时,页面元素如果有做吸顶等效果,也需要添加 title
对应高度的偏移。为了适应不同机型,我们可以可以用上面同样的方式,在 head
中设置上面说的这些元素的样式。
Q.E.D.