我有一个很奇怪的问题…在每个浏览器和手机版本中,我都遇到了这种行为:
当你加载页面时,所有的浏览器都有一个顶部菜单(例如显示地址栏),当你开始滚动页面时,它会向上滑动。
100vh有时只在视口的可见部分计算,所以当浏览器栏向上滑动时,100vh增加(以像素计算)。
所有布局重新油漆和重新调整,因为尺寸已经改变
对用户体验有不好的跳跃效果
如何避免这个问题?当我第一次听说viewport-height时,我很兴奋,我认为我可以使用它来固定高度块,而不是使用javascript,但现在我认为唯一的方法实际上是javascript与一些调整大小事件…
您可以在:示例站点看到问题
有人能帮助我/建议一个CSS解决方案吗?
简单测试代码:
/* maybe i can track the issue whe it occours... */
$(function(){
var resized = -1;
$(window).resize(function(){
$('#currenth').val( $('.vhbox').eq(1).height() );
if (++resized) $('#currenth').css('background:#00c');
})
.resize();
})
*{ margin:0; padding:0; }
/*
this is the box which should keep constant the height...
min-height to allow content to be taller than viewport if too much text
*/
.vhbox{
min-height:100vh;
position:relative;
}
.vhbox .t{
display:table;
position:relative;
width:100%;
height:100vh;
}
.vhbox .c{
height:100%;
display:table-cell;
vertical-align:middle;
text-align:center;
}
<div class="vhbox" style="background-color:#c00">
<div class="t"><div class="c">
this div height should be 100% of viewport and keep this height when scrolling page
<br>
<!-- this input highlight if resize event is fired -->
<input type="text" id="currenth">
</div></div>
</div>
<div class="vhbox" style="background-color:#0c0">
<div class="t"><div class="c">
this div height should be 100% of viewport and keep this height when scrolling page
</div></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
我在下面创建了两个例子:
要展示如何高度:100vh的高度可以导致滚动在移动chrome浏览器:
代码:https://codesandbox.io/embed/mobile-viewport-100vh-issue-nxx8z?fontsize=14&hidenavigation=1&theme=dark
演示:https://nxx8z.csb.app/
解决方案使用位置:固定解决问题和纯CSS:
代码:https://codesandbox.io/s/mobile-viewport-100vh-issue-fix-forked-ypx5x?file=/index.html
演示:https://ypx5x.csb.app/
问题:
if ( refDOM.clientHeight != window.innerHeight )
解决方案:
refDOM.style.setProperty('--MYvh', window.innerHeight + 'px' ) ;
完成:
const mobileShit = function ( refDOM ) {
console.log ( `refDOM.clientHeight : ${refDOM.clientHeight}` ) ;
console.log ( `window.innerHeight : ${window.innerHeight}` ) ;
if ( refDOM.clientHeight != window.innerHeight ) { // accounting for mobile
refDOM.style.setProperty('--MYvh', window.innerHeight + 'px' ) ;
}
} ;
CSS(通过脚本修改,是的,当任何事情发生变化时,你必须处理事件):
:root {
--MYvh : 100vh ;
}
不要使用推荐的方法,如-webkit-fill-available。
我花了一整天的时间来修复这个“bug”。
当你的应用程序被一个带有“下巴”的浏览器加载时,添加一个类。
JavaScript
// Angular example but applicable for any JS solution
@HostBinding('class.browser-has-chin') browserHasChin: boolean = false;
public ngOnInit(): void {
this.browserHasChin = this._isMobileSafari();
}
private _isMobileSafari() {
return navigator.userAgent.match(/(iPod|iPhone|iPad)/) && navigator.userAgent.match(/AppleWebKit/) ? true : false;
}
CSS
.browser-has-chin {
@media screen and (max-device-width: 767px){
// offset with padding or something
}
}
注:
在跨浏览器兼容性方面,-webkit-fill-available道具存在一些重大问题。
我能够让它在Chrome和iOS Safari中工作,以修复下巴/高度计算问题。然而,它破坏了Android Chrome和Firefox也有bug。
似乎-webkit-fill-available在某种程度上是匆忙加入webkit的,也许是苹果偶然采用的,作为下巴/高度计算的修复?
它依赖于内在的大小,这是不安全的使用。
React用useEffect和useState挂钩解决方案
function App() {
const [vh, setVh] = useState(window.innerHeight);
useEffect(() => {
const updateVh = () => {
setVh(window.innerHeight);
};
window.addEventListener('resize', updateVh);
return () => window.removeEventListener('resize', updateVh);
}, []);
return (
<div style={{ height: vh }}>
{vh} px
</div>
);
}
演示:https://jsfiddle.net/poooow/k570nfd9/