Html CSS3 100vh在移动浏览器中不是常量
我有一个很奇怪的问题。。。在每个浏览器和手机版本中,我都会遇到这种行为:Html CSS3 100vh在移动浏览器中不是常量,html,css,viewport-units,Html,Css,Viewport Units,我有一个很奇怪的问题。。。在每个浏览器和手机版本中,我都会遇到这种行为: 加载页面时,所有浏览器都有一个顶部菜单(例如显示地址栏),当您开始滚动页面时,该菜单会向上滑动 100vh有时仅在视口的可见部分计算,因此当浏览器栏向上滑动时,100vh增加(以像素为单位) 所有布局重新绘制和调整,因为尺寸已更改 对用户体验的不良跳跃效应 如何避免这个问题?当我第一次听说viewport height时,我很兴奋,我想我可以将它用于固定高度块,而不是使用javascript,但现在我认为唯一的方法是使
- 加载页面时,所有浏览器都有一个顶部菜单(例如显示地址栏),当您开始滚动页面时,该菜单会向上滑动
- 100vh有时仅在视口的可见部分计算,因此当浏览器栏向上滑动时,100vh增加(以像素为单位)
- 所有布局重新绘制和调整,因为尺寸已更改
- 对用户体验的不良跳跃效应
简单测试代码:
/*也许我可以跟踪问题发生的时间*/
$(函数(){
var resized=-1;
$(窗口)。调整大小(函数(){
$('.#currenth').val($('.vhbox').eq(1.height());
如果(++调整大小)$('#currenth').css('background:#00c');
})
.resize();
})
*{margin:0;padding:0;}
/*
这是一个保持高度不变的盒子。。。
最小高度,允许内容在文本过多时高于视口
*/
.vhbox{
最小高度:100vh;
位置:相对位置;
}
.vhbox.t{
显示:表格;
位置:相对位置;
宽度:100%;
高度:100vh;
}
.vhbox.c{
身高:100%;
显示:表格单元格;
垂直对齐:中间对齐;
文本对齐:居中;
}
此div高度应为视口的100%,并在滚动页面时保持此高度
此div高度应为视口的100%,并在滚动页面时保持此高度
不幸的是,这是故意的…
这是一个众所周知的问题(至少在safari mobile中),这是故意的,因为它可以防止其他问题:
这完全是故意的。我们花了不少功夫才达到这个效果
基本问题是:可见区域在滚动时会动态变化。如果我们相应地更新CSS视口高度,我们需要在滚动期间更新布局。这不仅看起来像狗屎,而且在大多数页面中,以60 FPS的速度这样做几乎是不可能的(60 FPS是iOS上的基准帧速率)
很难向你展示“看起来像狗屎”的部分,但想象一下,当你滚动时,屏幕上的内容在移动,你想要的东西在不断地移动
动态更新高度不起作用,我们有几个选择:在iOS上放置视口单位,像iOS 8之前那样匹配文档大小,使用小视图大小,使用大视图大小
从我们拥有的数据来看,使用较大的视图大小是最好的折衷方案。大多数使用视区单位的网站在大多数时候看起来都很棒
Nicolas Hoizey对此进行了大量研究:
未计划修复
此时,除了避免在移动设备上使用“视口高度”,您可以做的事情不多。2016年,Chrome也改为:
编辑挂起:我现在无法测试它,但我会回来报告我的结果。对于我创建的许多站点,客户端会要求提供100vh横幅,正如您所发现的,当您开始滚动时,它会在移动设备上造成糟糕的“跳跃”体验。这就是我如何解决问题,在所有设备上实现平稳一致的体验: 我首先将我的横幅元素CSS设置为
高度:100vh
然后,我使用jQuery获取banner元素的高度(以像素为单位),并使用此高度应用内联样式
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
这样做可以解决移动设备上的问题,因为当页面加载时,banner元素使用CSS设置为100vh,然后jQuery通过在我的banner元素上放置内联CSS来覆盖它,从而在用户开始滚动时阻止它调整大小
但是,在桌面上,如果用户调整浏览器窗口的大小,“我的横幅”元素将不会调整大小,因为由于上面的jQuery,它现在有一个以像素为单位的固定高度。为了解决这个问题,我在文档正文中添加了一个“mobile”类。然后我将上面的jQuery封装在if语句中:
if ($('body').hasClass('mobile')) {
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
}
因此,如果用户在移动设备上,则“mobile”类出现在我的页面主体上,并执行上面的jQuery。因此,我的banner元素将只在移动设备上应用内联CSS,而在桌面上,原来的100vh CSS规则仍然有效。由于我是新手,我无法对其他答案发表评论 如果有人正在寻找一个解决方案来实现这一点(并且可以使用javascript——目前看来这是实现这一点所必需的),那么这种方法对我来说非常有效,它也说明了移动定位的变化。我在示例代码中使用Jquery,但在vanillaJS中应该是可行的 -首先,我使用一个脚本来检测设备是触摸还是悬停。赤裸裸的例子:
if ("ontouchstart" in document.documentElement) {
document.body.classList.add('touch-device');
} else {
document.body.classList.add('hover-device');
}
这将根据稍后可用于高度脚本的设备类型(悬停或触摸)向body元素添加类
-接下来,使用此代码设置设备在负载和方向改变时的高度:
if (jQuery('body').hasClass("touch-device")) {
//Loading height on touch-device
function calcFullHeight() {
jQuery('.hero-section').css("height", $(window).height());
}
(function($) {
calcFullHeight();
jQuery(window).on('orientationchange', function() {
// 500ms timeout for getting the correct height after orientation change
setTimeout(function() {
calcFullHeight();
}, 500);
});
})(jQuery);
} else {
jQuery('.hero-section').css("height", "100vh");
}
-设置超时,以便设备在方向更改时正确计算新高度。如果有
var vhHeight = $("body").height();
var chromeNavbarHeight = vhHeight - window.innerHeight;
$('body').css({ height: window.innerHeight, marginTop: chromeNavbarHeight });
# html
<body>
<div class="content">
<!-- Your stuff here -->
</div>
</body>
# css
.content {
height: 80vh;
}
html { height: 100vh; }
body {
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
}
/* this is the container you want to take the visible viewport */
/* make sure this is top-level in body */
#your-app-container {
height: 100%;
}
:root {
--devHeight: 86vh; //*This value changes
}
.div{
height: calc(var(--devHeight)*0.10); //change multiplier to suit required height
}
max-height: calc(100vh - 120px);
function appHeight() {
const doc = document.documentElement
doc.style.setProperty('--vh', (window.innerHeight*.01) + 'px');
}
window.addEventListener('resize', appHeight);
appHeight();
.module {
height: 100vh; /* Fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
}
// 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;
}
.browser-has-chin {
@media screen and (max-device-width: 767px){
// offset with padding or something
}
}