加载页面时,所有浏览器都有一个顶层菜单(显示例如),当您开始滚动页面时会向上滑动。
有时仅在视口的可见部分计算100vh,因此当浏览器栏向上滑动100vh时(以像素为单位)会增加
所有布局由于尺寸已更改,因此需要重新绘画和重新调整
对于用户体验而言,跳动效果很差
如何避免此问题?当我第一次听说viewport-height时,我很兴奋,我认为我可以将其用于固定高度块而不是使用javascript,但是现在我认为唯一的方法实际上是带有一些resize事件的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>
#1 楼
不幸的是,这是故意的...这是一个众所周知的问题(至少在safari mobile中),这是故意的,因为它可以防止其他问题。 Benjamin Poulain回复了一个webkit错误:
这完全是故意的。为了达到这种效果,我们付出了很多工作。 :)
基本问题是:滚动时可见区域会动态变化。如果我们相应地更新CSS视口高度,则需要在滚动过程中更新布局。不仅看起来像狗屎一样,而且大多数页面几乎不可能做到60 FPS(iOS上的60 FPS是基准帧速率)。
很难向您展示“看起来像狗屎”部分,但是可以想象当您滚动时,内容在移动,屏幕上您想要的内容也在不断变化。
动态更新高度无法正常工作,我们有几种选择:在iOS上放下视口单位,像在iOS 8之前一样匹配文档大小,使用较小的视图大小,使用较大的视图大小。
根据我们的数据,使用较大的视图大小是最好的折衷方案。大多数使用视口单位的网站在大多数时候看起来都很不错。
Nicolas Hoizey对此进行了大量研究:https://nicolas-hoizey.com/2015/02/viewport-height-is-高于某个移动浏览器中文档的可见部分。html
没有计划中的修复程序
目前,除了避免在移动设备上使用视口高度。 Chrome在2016年也更改为此:
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
https: //developers.google.com/web/updates/2016/12/url-bar-resizing
评论
是的,正如我所想。唯一可行的解决方案是脚本解决方案。据我所知,$(window).height()不受此错误的影响,所以我将采用这种方式。谢谢!
–Nereo Costacurta
16年5月9日在10:52
脚本是我的唯一途径,并且效果很好。
– captDaylight
16年8月23日在17:08
有史以来最令人沮丧的答案。
– Winnemucca
17年11月17日在16:31
从Chrome版本56开始,vh始终像隐藏了URL栏一样进行计算,因此vh在滚动时不会增加,除非position:fixed。这类似于Safari上的实现。了解更多:developers.google.com/web/updates/2016/12/url-bar-resizing
–凯文·法鲁吉亚(Kevin Farrugia)
18年1月10日在23:16
初始加载后,最新版的Chrome不会更改vh或 100%的高度。这实际上很棒-因为URL栏隐藏时布局颠簸/重排看起来很可怕。 Firefox和Edge Mobile仍会动态更新vh和高度,从而在滚动时会导致所有组件的大量撕裂和调整大小,如果将SVG用于背景图像,则尤其糟糕
–德雷奈
18年5月11日在9:50
#2 楼
您可以在CSS中尝试min-height: -webkit-fill-available;
而不是100vh
。应该解决评论
我要离开最低高度:100vh;作为不支持-webkit-fill-available的后备。
– Tammy T恤
19年4月3日,下午3:02
哇谢谢你!!有了这个,我不再需要“ react-div-100vh”了!
– Andres Elizondo
19年6月23日19:10
最有帮助的答案!
–Gauthier
19年7月22日在12:48
这是一个非常不错的解决方案,但在iOS 13中似乎有所更改—我在第一部分的底部看到了额外的空间,但是它完全可以在Safari中用于iOS 12.x来工作。codepen.io/RwwL/pen / PowjvPq(您必须对此进行分叉,然后在iOS上的CodePen调试模式下查看它才能真正理解我的意思)。
– RwwL
19/12/26在23:00
从Chrome v84开始,不再支持-webkit-fill-available。 :/
–TheCat
20年7月21日在11:14
#3 楼
在我的应用中,我这样做(打字稿和嵌套的postcss,所以要相应地更改代码):const appHeight = () => {
const doc = document.documentElement
doc.style.setProperty('--app-height', `${window.innerHeight}px`)
}
window.addEventListener('resize', appHeight)
appHeight()
它至少在chrome mobile和ipad上有效。什么都行不通,是当您将应用程序添加到iOS的主屏幕上并更改方向几次后-缩放级别与innerHeight值混淆了,如果找到解决方案,我可能会发布更新。
演示
评论
这实际上是解决一个非常烦人的问题的绝佳方法。
– Michael Giovanni Pumo
19年3月14日在11:26
我想添加一个警告,“ @ media not all and(hover:hover){”不是检测移动浏览器的防弹方法。随意使用其他东西。
–安德烈亚斯牧群
19年7月11日在15:07
我非常喜欢这种方法。我要发表的一则评论是关于事件监听器的使用。这会导致页面重新绘制,并且我只在某些情况下才使用它,这对于用户查看正确的视口(即首页初始视图)绝对至关重要
– Zach Gollwitzer
20年4月3日,14:55
#4 楼
看这个答案:https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ // First we get the viewport height and we multiple it by 1% to get a value for a vh unit
let vh = window.innerHeight * 0.01;
// Then we set the value in the --vh custom property to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`);
// We listen to the resize event
window.addEventListener('resize', () => {
// We execute the same script as before
let vh = window.innerHeight * 0.01;
document.documentElement.style.setProperty('--vh', `${vh}px`);
});
body {
background-color: #333;
}
.module {
height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */
height: calc(var(--vh, 1vh) * 100);
margin: 0 auto;
max-width: 30%;
}
.module__item {
align-items: center;
display: flex;
height: 20%;
justify-content: center;
}
.module__item:nth-child(odd) {
background-color: #fff;
color: #F73859;
}
.module__item:nth-child(even) {
background-color: #F73859;
color: #F1D08A;
}
<div class="module">
<div class="module__item">20%</div>
<div class="module__item">40%</div>
<div class="module__item">60%</div>
<div class="module__item">80%</div>
<div class="module__item">100%</div>
</div>
评论
聪明的解决方案,我正面临着移动设备上的视口高度问题,这也应被视为解决方案(特别是对于移动设备)
–朱利奥·韦多瓦托(Julio Vedovatto)
19年5月1日在21:27
非常好的解决方案。就我而言,我没有使用ponyfill,而是逻辑上,对于所有桌面站点我都使用100vh,而对于移动设备,我使用var(移动世界中没有IE11)。
– Frekaman
20-2-4在14:16
唯一适用于嵌套元素的解决方案。在必须替换数百个实例的其他任何人中,您可以(至少在大多数情况下)匹配正则表达式(-)?([\ d。] +)vh并将其替换为calc(var(-vh)* $ 1 $ 2)
– ecc521
20-4-4在18:09
#5 楼
对于我建立的许多网站,客户端都会要求提供100vh的横幅广告,正如您所发现的那样,当您开始滚动浏览时,这会导致在移动设备上出现糟糕的“跳跃”体验。这是我为在所有设备上获得平稳一致的体验而解决问题的方法:我首先将横幅元素CSS设置为
height:100vh
,然后使用jQuery来获取高度横幅元素的像素并使用此高度应用内联样式。
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
这样做可以解决移动设备上的问题,因为页面加载时设置了横幅元素到100vh(使用CSS),然后jQuery通过将内联CSS放在我的banner元素上来覆盖它,这会阻止它在用户开始滚动时重新调整大小。元素不会调整大小,因为由于上述jQuery,它现在具有以像素为单位设置的固定高度。为了解决这个问题,我使用“移动检测”在文档正文中添加了“移动”类。然后,我将上述jQuery包装为if语句:
if ($('body').hasClass('mobile')) {
var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });
}
结果,如果用户在移动设备上,则在页面的主体和上面的jQuery被执行。因此,我的banner元素只会将内联CSS应用于移动设备,而在台式机上,原始的100vh CSS规则仍然存在。
评论
我将它调整为使用$('。banner')。css({height:window.innerHeight});而是视口的“实际”高度。 innerHeight如何工作的示例
–马丁
17年7月13日在9:17
这是document.querySelector('。banner')。style.height = window.innerHeight;适用于编写实际JavaScript的人。
–法比安·冯·埃勒兹(Fabian von Ellerts)
19年3月12日在18:14
#6 楼
对我来说,这样的把戏很成功:height: calc(100vh - calc(100vh - 100%))
评论
它与高度不同吗:100%?
–FF_Dev
20年5月30日12:00
是的,当纯100%仅填充所有可用的父区域时,100vh是视口高度(您的设备)的100%(父块可以具有例如50px的高度,并且只会填充到该父高度)。简而言之。
–Patryk Janik
20年6月4日在12:05
尽管地址栏没有隐藏,但这种简单的技巧确实确实有效,但是比其他解决方案要好。不赞成我。
– Eli
20年7月3日在8:34
#7 楼
我想出了一个React组件–检查您是否使用React或不使用它来浏览源代码,以便可以使其适应环境。它将全屏div的高度设置为
window.innerHeight
,然后在窗口调整大小时对其进行更新。评论
并非所有英雄都戴帽子。例如,你很好。非常感谢你。节省了数小时的时间。
– NarayaN
18年8月21日在9:16
对于Vue爱好者... github.com/razumnyak/vue-div-100vh
–托尼·奥哈根(Tony O'Hagan)
19/12/26在4:40
好的代码。谢谢你,先生。
–帕特里克·费舍尔(Patrick Fisher)
20 Dec 9'在21:08
#8 楼
几天来我一直在寻找解决方案,这是将VueJS与Vuetify一起使用的每个人(我的解决方案使用v-app-bar,v-navigation-drawer和v-footer):在App.vue中使用)具有以下内容: .v-application {
height: 100vh;
height: -webkit-fill-available;
}
.v-application--wrap {
min-height: 100vh !important;
min-height: -webkit-fill-available !important;
}
评论
这很好用,并且可以在Vue / Vuetify世界之外推广。
–leo
20-05-30在14:49
起初,这似乎对我有用,但是后来我注意到,它不会根据移动设备上方向的改变来调整容器的大小。
–mediafreakch
20-6-26在12:32
html {高度:100vh;高度:-webkit-fill-available; } body,body> div,.v-application,.v-application--wrap {height:100vh;高度:-webkit-fill-available;最低高度:100vh;最小高度:-webkit-fill-available;为我节省了两个问题。最后
–mediafreakch
20 Jun 26'13:04
#9 楼
您可以通过添加以下脚本和样式来做到这一点 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);
}
评论
谢谢你,先生。这有帮助
–rufatZZ
20-10-20在21:13
此处对此进行了全面描述:css-tricks.com/the-trick-to-viewport-units-on-mobile / ...
– stauross
20 Nov 26 '14:27
这就像一个魅力。对我来说,我想要的完美解决方案。非常感谢你。
– Amar Shakya
20-12-28 at 11:33
#10 楼
@nils清楚地解释了这一点。接下来是什么?
我只是回过头来在CSS中使用相对的“经典”
%
(百分比)。通常要花更多的精力实现的功能比使用
vh
的功能要好,但是至少,您有一个相当稳定的解决方案,它可以在不同的设备和浏览器上运行,而不会出现奇怪的UI故障。评论
高度:横幅广告的100%仍然在移动浏览器上跳跃。我已经在Android上对其进行了测试,到目前为止,Chrome和Opera Mini的可见VP高度为100%,并且在滚动时不会改变。 Edge和Firefox更改100%的高度,然后重新绘制视图。 Firefox尤其糟糕,它会撕裂,重新渲染文本,并且显然会重新布局
–德雷奈
18年5月2日,9:16
@Drenai您确定正确实现了吗?您能在jsfiddle.net上的一个小例子中证明这一点吗?
– klimat
18年11月28日在8:52
是,我确定:-)
–德雷奈
18年11月28日在16:21
#11 楼
以下代码(使用jQuery)解决了该问题。var vhHeight = $("body").height();
var chromeNavbarHeight = vhHeight - window.innerHeight;
$('body').css({ height: window.innerHeight, marginTop: chromeNavbarHeight });
其他元素以
%
为单位代替vh
。 #12 楼
我刚刚发现我设计的Web应用程序在iPhone和iPad上存在此问题,并且发现了一篇文章,建议使用针对特定Apple设备的媒体查询来解决此问题。该文章中的代码在这里,但地址是这样的:http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug引用该文章:“使用针对旧版iPhone和iPad分辨率的媒体查询将元素高度与设备高度匹配。“
他们仅添加了6个媒体查询来适应全高度元素,它应该可以正常工作完全实现了CSS。
编辑中:我现在无法测试,但是我会回来报告结果。
评论
还在等待那些结果results
– gman
18年1月8日在6:58
对不起,我没有按承诺回来。但是在摆弄HTML和CSS的时间长于我想要的时间之后,我更改了布局的设计,发现了一种可以满足我的需求的方法,但不是通用解决方案。
–贾哈齐尔
18年8月28日在18:01
#13 楼
刚接触我时,我无法对其他答案发表评论。如果有人正在寻找答案来完成这项工作(并且可以使用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");
}
-设置超时以便设备会在方向更改时正确计算新高度。如果没有超时,以我的经验,高度将不正确。 500ms可能过大,但对我有用。
如果浏览器覆盖CSS 100vh,则悬停设备上的100vh属于后备状态。
评论
并非所有浏览器都支持Touchstart,某些非移动设备也支持它。developer.mozilla.org/en-US/docs/Web/Events/touchstart
–德雷奈
18年5月2日在9:19
大多数移动浏览器都支持@Drenai Touchstart。在台式机上支持较少,IE,Opera和Safari不支持。但是,最初的问题是针对移动设备而非台式机的。这使之成为有效答案。
– Paul
18年8月11日在19:18
感谢您的评论!我主要使用这种策略来克服某些移动浏览器上屏幕的调整和跳动。如果浏览器不支持touchstart,则回退将是CSS 100vh-如果不支持100vh,则是另一个主题。如果桌面设备碰巧具有触摸支持,则将使用javascript计算高度。然后,我们将失去对100vh提供的调整大小的重新计算,但这通常不是致命的问题,因为台式机上的方向没有变化。
–t.j.goodman
18年8月13日在6:35
同样,高度计算也可以附加到调整大小事件中,但随后我们可能会遇到相同的精确问题,即移动设备上的重新调整和跳跃性。因此,我发现这种策略是可行的。
–t.j.goodman
18年8月13日在6:38
@Paul如果Chrome和Firefox桌面浏览器具有touchstart,那么确定检测移动浏览器使用的功能肯定错误吗?我刚刚在Windows的Chrome和Firefox中对其进行了测试,并且都通过了此测试
–德雷奈
18年8月13日在21:16
#14 楼
以下对我有用: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%;
}
body
将占据可见视口高度,而#your-app-container
和height: 100%
将使该容器占据可见视口高度。#15 楼
这是我用于我的React应用程序的一种解决方法。 br />这是一个折衷方案,但修复相对简单
#16 楼
VH 100在移动设备上无法正常运行,因为它没有考虑iOS栏(或其他平台上的类似功能)。一种有效的解决方案是使用JavaScript“ window.innerHeight”。只需将元素的高度分配给该值,例如
$('。element-name')。height(window.innerHeight);
注意:在JS中创建函数可能很有用,因此调整屏幕大小时可以改变高度。但是,我建议仅在更改屏幕宽度时才调用该函数,这样当用户向下滚动页面时,iOS栏消失时,元素的高度将不会跳跃。
#17 楼
希望这将是一个UA定义的CSS环境变量,如下所示:https://github.com/w3c/csswg-drafts/issues/2630#issuecomment-397536046#18 楼
因为它不会被修复,所以您可以执行以下操作:# html
<body>
<div class="content">
<!-- Your stuff here -->
</div>
</body>
# css
.content {
height: 80vh;
}
对我来说,这是比使用JavaScript更快,更纯粹的解决方案,但无法正常工作在许多设备和浏览器上。
只使用适合您需要的
vh
值即可。#19 楼
在移动设备上使用vh不能与100vh一起使用,因为它们的设计选择是使用设备的整个高度,不包括任何地址栏等。如果要查找包含div高度的布局与真实视图高度成比例,我使用以下纯css解决方案:
:root {
--devHeight: 86vh; //*This value changes
}
.div{
height: calc(var(--devHeight)*0.10); //change multiplier to suit required height
}
您有两个选项来设置视口高度,手动将--devHeight设置为高度可以正常工作(但您需要为要编码的每种设备类型输入此值)
或
使用javascript获取窗口高度,然后更新-在加载和刷新视口时需要devheight(但是这确实需要使用javascript而不是纯CSS解决方案)
一旦您获得了正确的视口高度,就可以以总视口高度的确切百分比创建多个div只需在每个div中更改乘数,即可将高度分配给。
0.10 =视图高度的10%
0.57 =视图高度的57% ght
希望这可能对某人有所帮助;)
评论
那是一个很好的解决方案。您可以在这篇有关Css-tricks的文章上阅读更多有关此的内容。
–阿莫里·汉瑟(Amaury Hanser)
19-4-3在13:39
#20 楼
可以在此博客文章中找到有关该问题及其解决方案的不错的阅读:在100vh布局中寻址iOS地址栏我最终在React应用程序中使用的解决方案是利用上面的帖子。
#21 楼
您可以尝试将position: fixed; top: 0; bottom: 0;
属性赋予您的容器。评论
添加有关为什么这是问题的答案的更多信息。
– Pinaki Mondal
19年2月14日在12:35
#22 楼
尝试在移动设备上使用html, body { height: 100% }
达到100vh的效果。
评论
如果我很好地理解了这个问题,那么您所面临的问题是在移动浏览器中,高度是否超过可见的视口高度。对吗?有趣的是,以前从未注意到。其主要是明显跳动的背景图片。如何添加过渡(0.5秒左右)以使更改不那么突然?
@GauravAggarwal不,正好相反:实际的视口高度大于浏览器在其地址栏可见时提供的视口高度...
由于我的问题越来越流行,我想给我5美分:保持真正的窗口高度并仅向上滑动菜单栏会更聪明吗?似乎并不那么困难。实际上应该更容易...手指向上->菜单栏向上滑动直到不可见,手指向下->菜单栏向下滑动直到完全可见...全部与身体完全相同,没有任何重新调整和跳跃效果... br />
Google对此提供了一些很好的信息:developers.google.com/web/updates/2016/12/url-bar-resizing如果您已将身高更改为100%,则可以使用100%代替100vh