当地址栏隐藏iOS / Android / Mobile Chrome时,背景图像跳转

我目前正在使用Twitter Bootstrap开发一个响应式网站。

该网站在手机/平板电脑/桌面上具有全屏幕背景图像。 这些图像旋转和淡入每个使用两个div。

除了一个问题,这几乎是完美的。 在Android上使用iOS Safari,Android Browser或Chrome时,当用户向下滚动页面并隐藏地址栏时,背景会略微跳跃。

该网站在这里: http : //lt2.daveclarke.me/

在移动设备上访问它并向下滚动,您应该看到图像resize/移动。

我用于背景DIV的代码如下所示:

#bg1 { background-color: #3d3d3f; background-repeat:no-repeat; background-attachment:fixed; background-position:center center; -webkit-background-size: cover; -moz-background-size: cover; -o-background-size: cover; background-size: cover; position:fixed; width:100%; height:100%; left:0px; top:0px; z-index:-1; display:none; } 

所有的build议欢迎 – 这一直在做我的头一阵子!

这个问题是由于URL的缩小/滑动以及改变#bg1和#bg2 div的大小,因为它们是100%的高度和“固定的”。 由于背景图像设置为“覆盖”,因为包含区域较大,所以会调整图像的大小/位置。

基于网站的响应性,背景必须扩大。 我接受了两个可能的解决scheme:

1)将#bg1,#bg2高度设置为100vh。 理论上这是一个优雅的解决scheme。 但是,iOS有一个vh的bug( http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/ )。 我试图使用最大高度来防止这个问题,但它仍然存在。

2)使用Javascript确定的视口大小不受URL栏的影响。 因此,可以使用Javascript根据视口大小在#bg1和#bg2上设置静态高度。 这不是最好的解决scheme,因为它不是纯粹的CSS,并且在页面加载时有轻微的图像跳转。 但是,考虑到iOS的“vh”错误(这在iOS 7中似乎没有修复),这是唯一可行的解​​决scheme。

 var bg = $("#bg1, #bg2"); function resizeBackground() { bg.height($(window).height()); } $(window).resize(resizeBackground); resizeBackground(); 

在一个侧面说明,我已经看到这些在iOS和Android的这些resize的URL栏的问题。 我理解这个目的,但是他们真的需要考虑到他们带给网站的奇怪的function和破坏。 最新的变化是,你不能再使用滚动技巧“隐藏”在iOS或Chrome上加载页面的URL栏。

编辑:虽然上面的脚本完美的保持背景resize,当用户向下滚动会导致明显的差距。 这是因为它将背景大小保持为屏幕高度的100%减去URL栏。 如果我们把高度增加60px,就像瑞士人所说的,这个问题就会消失。 这意味着,当URL栏存在时,我们不会看到背景图像的底部60px,但它可以防止用户看到一个空白。

 function resizeBackground() { bg.height( $(window).height() + 60); } 

我发现杰森的回答对我来说并不是很有效,我还是跳了起来。 Javascript保证页面顶部没有空隙,但是当地址栏消失/重现时,背景仍在跳动。 所以以及Javascript的修复,我申请transition: height 999999s的股利。 这会创build一个持续时间很长的转换,以致它实际上冻结元素。

我在网站的标题上有类似的问题。

 html, body { height:100%; } .header { height:100%; } 

这将最终在android chrome上产生一个跳动的滚动体验,因为在url-bar隐藏之后,.header-container将重新缩放,手指从屏幕上移除。

CSS-解决scheme:

添加以下两行,将防止url-bar隐藏和垂直滚动仍然可能:

 html { overflow: hidden; } body { overflow-y: scroll; -webkit-overflow-scrolling:touch; } 

这个问题可以通过媒体查询和一些math来解决。 这是一个面向portait方向的解决scheme:

 @media (max-device-aspect-ratio: 3/4) { height: calc(100vw * 1.333 - 9%); } @media (max-device-aspect-ratio: 2/3) { height: calc(100vw * 1.5 - 9%); } @media (max-device-aspect-ratio: 10/16) { height: calc(100vw * 1.6 - 9%); } @media (max-device-aspect-ratio: 9/16) { height: calc(100vw * 1.778 - 9%); } 

由于vh会在url栏消失时发生变化,所以需要另外确定高度。 值得庆幸的是,视口的宽度是不变的,移动设备只有几个不同的长宽比。 如果你可以确定宽度和宽高比,一个小math会给你的视口高度完全一样, 应该工作。 这是过程

1)创build一系列媒体查询您想要的纵横比。

  • 使用设备宽高比代替纵横比,因为后者将在url栏消失时resize

  • 我在设备宽高比中添加了“最大值”,以定位最受欢迎的任何宽高比。 THey不会那么精确,但他们将只为less数用户,并将仍然非常接近正确的vh。

  • 记住媒体查询使用水平/垂直,所以为了portait你需要翻转数字

2)对于每个媒体查询,乘以垂直高度的任何百分比,您希望该元素以纵横比相反。

  • 既然你知道宽度和宽高的比例,你只需要乘以你想要的百分比(在你的情况下为100%)乘以高度/宽度的比例。

3)你必须确定url的高度,然后减去高度。 我还没有find确切的测量结果,但是我使用9%的移动设备进行景观testing,而且效果相当不错。

这不是一个非常优雅的解决scheme,但其他选项也不是很好,考虑到他们是:

  • 让您的网站似乎对用户来说是错误的,

  • 不适当的大小元素,或

  • 使用JavaScript的一些基本的样式,

缺点是有些设备可能会有不同的网吧高度或长宽比比最受欢迎。 但是,如果只有less数几个设备遭受增加/减less几个像素的影响,那么使用这种方法对于我来说似乎比每个人在刷卡时resize都要好。

为了方便起见,我还创build了一个SASS mixin:

 @mixin vh-fix { @media (max-device-aspect-ratio: 3/4) { height: calc(100vw * 1.333 - 9%); } @media (max-device-aspect-ratio: 2/3) { height: calc(100vw * 1.5 - 9%); } @media (max-device-aspect-ratio: 10/16) { height: calc(100vw * 1.6 - 9%); } @media (max-device-aspect-ratio: 9/16) { height: calc(100vw * 1.778 - 9%); } } 

这里的所有答案都是使用window高度,这受到URL栏的影响。 大家都忘记了screen高度?

这是我的jQuery解决scheme:

 $(function(){ var $w = $(window), $background = $('#background'); // Fix background image jump on mobile if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) { $background.css({'top': 'auto', 'bottom': 0}); $w.resize(sizeBackground); sizeBackground(); } function sizeBackground() { $background.height(screen.height); } }); 

添加.css()部分将不可避免地将顶部alignment的绝对定位元素更改为底部alignment,因此根本没有跳转。 虽然,我想没有理由不直接添加到正常的CSS。

我们需要用户代理嗅探器,因为桌面上的屏幕高度不会有帮助。

此外,这是所有假设#background是填充窗口的固定位置元素。

对于JavaScript纯粹主义者(警告 – 未经testing):

 var background = document.getElementById('background'); // Fix background image jump on mobile if ((/Android|iPhone|iPad|iPod|BlackBerry/i).test(navigator.userAgent || navigator.vendor || window.opera)) { background.style.top = 'auto'; background.style.bottom = 0; window.onresize = sizeBackground; sizeBackground(); } function sizeBackground() { background.style.height = screen.height; } 

编辑:对不起,这不会直接回答您的具体问题与多个背景。 但是,这是search这个固定背景在移动设备上跳跃的问题的首要结果之一。

我目前使用的解决scheme是检查$(document).ready上的userAgent ,看看它是不是有问题的浏览器之一。 如果是,请按照下列步骤操作:

  1. 将相关高度设置为当前视口高度而不是“100%”
  2. 存储当前视口的水平值
  3. 然后,在$(window).resize ,如果新的水平视口尺寸与初始值不同,则只更新相关的高度值
  4. 存储新的水平和垂直值

或者,也可以只在超出地址栏高度的情况下testing是否允许垂直resize。

哦,地址栏确实会影响$(window).height 。 请参阅: Mobile Webkit浏览器(chrome)地址栏更改$(window).height(); 制作背景大小:每次封面重新调整 JS“Window”width-height vs“screen”width-height?

我碰到这个问题,当我试图创build一个将覆盖整个视口的入口屏幕。 不幸的是,接受的答案不再有效。

1)高度设置为100hv元素在每次视口大小发生变化时都会resize,包括由于(不显示)URL栏引起的情况。

2) $(window).height()返回受URL地址栏大小影响的值。

一种解决scheme是按照transition: height 999999s 的回答build议,使用transition: height 999999s “冻结”元素。 缺点是,这会有效地禁用适应所有视口大小的变化,包括由屏幕旋转引起的变化。

所以我的解决scheme是使用JavaScript手动pipe理视口更改。 这使我能够忽略可能由URL栏引起的小变化,只对大变化做出反应。

 function greedyJumbotron() { var HEIGHT_CHANGE_TOLERANCE = 100; // Approximately URL bar height in Chrome on tablet var jumbotron = $(this); var viewportHeight = $(window).height(); $(window).resize(function () { if (Math.abs(viewportHeight - $(window).height()) > HEIGHT_CHANGE_TOLERANCE) { viewportHeight = $(window).height(); update(); } }); function update() { jumbotron.css('height', viewportHeight + 'px'); } update(); } $('.greedy-jumbotron').each(greedyJumbotron); 

编辑:我实际上使用这种技术与height: 100hv一起height: 100hv 。 页面从一开始就被正确渲染,然后JavaScript开始,并开始手动pipe理高度。 这样,页面加载时(甚至之后)就不会闪烁。

我发现一个非常简单的解决scheme,而不使用Javascript:

 transition: height 1000000s ease; -webkit-transition: height 1000000s ease; -moz-transition: height 1000000s ease; -o-transition: height 1000000s ease; 

所有这一切都是推迟运动,所以它是不可思议的慢,它不明显。

我的解决scheme涉及到一些JavaScript。 保持div的100%或100vh(这将避免div不出现在初始页面加载)。 然后,当页面加载时,抓住窗口的高度,并将其应用到有问题的元素。 避免跳,因为现在你的div上有一个静态的高度。

 var $hero = $('#hero-wrapper'), h = window.innerHeight; $hero.css('height', h); 

我创build了一个使用VH单位的香草javascript解决scheme。 使用VH几乎任何地方都受地址栏的影响最小化滚动。 为了修复显示页面重新绘制时的焦点,我已经得到了这个js,它将使用VH单位抓取所有的元素(如果你给他们类的.vh-fix ),并给他们内联的像素高度。 基本上冻结在我们想要的高度。 您可以在轮换或视口大小更改时进行此操作以保持响应。

 var els = document.querySelectorAll('.vh-fix') if (!els.length) return for (var i = 0; i < els.length; i++) { var el = els[i] if (el.nodeName === 'IMG') { el.onload = function() { this.style.height = this.clientHeight + 'px' } } else { el.style.height = el.clientHeight + 'px' } } 

这已经解决了我所有的使用案例,希望有所帮助。

这是我解决这个问题的解决scheme,我直接在代码上添加了评论。 我已经testing了这个解决scheme,工作正常。 希望我们会对大家有用,有同样的问题。

 //remove height property from file css because we will set it to first run of page //insert this snippet in a script after declarations of your scripts in your index var setHeight = function() { var h = $(window).height(); $('#bg1, #bg2').css('height', h); }; setHeight(); // at first run of webpage we set css height with a fixed value if(typeof window.orientation !== 'undefined') { // this is more smart to detect mobile devices because desktop doesn't support this property var query = window.matchMedia("(orientation:landscape)"); //this is is important to verify if we put var changeHeight = function(query) { //mobile device in landscape mode if (query.matches) { // if yes we set again height to occupy 100% setHeight(); // landscape mode } else { //if we go back to portrait we set again setHeight(); // portrait mode } } query.addListener(changeHeight); //add a listner too this event } else { //desktop mode //this last part is only for non mobile $( window ).resize(function() { // so in this case we use resize to have setHeight(); // responsivity resisizing browser window }); }; 

这是我尝试过的最好的解决scheme(最简单)。

…这并不能保持地址栏的本地体验

例如,你可以用CSS设置高度为100%,然后在装载文档的时候用javascript设置高度为px窗口高度的0.9 *。

例如使用jQuery:

$("#element").css("height", 0.9*$(window).height());

不幸的是,没有什么与纯粹的CSS工作:P,但也是最简单的,VH和VW是在iPhone上的越野车 – 使用百分比。

我用javascript设置了我的宽度元素。 在我设置了de vh之后。

HTML

 <div id="gifimage"><img src="back_phone_back.png" style="width: 100%"></div> 

CSS

 #gifimage { position: absolute; height: 70vh; } 

JavaScript的

 imageHeight = document.getElementById('gifimage').clientHeight; // if (isMobile) document.getElementById('gifimage').setAttribute("style","height:" + imageHeight + "px"); 

这对我有用。 我不使用jquery ect。 因为我希望它尽快加载。

花了几个小时了解这个问题的所有细节,并找出最佳实施。 原来2016年4月份只有iOS Chrome有这个问题。 我尝试过使用Android Chrome和iOS Safari,但都没有问题。 所以我使用的iOS Chrome的修复程序是:

 $(document).ready(function() { var screenHeight = $(window).height(); $('div-with-background-image').css('height', screenHeight + 'px'); }); 

我正在使用此解决方法:通过以下方式修复页面加载bg1的高度:

 var BG = document.getElementById('bg1'); BG.style.height = BG.parentElement.clientHeight; 

然后附加一个resize的事件监听器到窗口这是这样的:如果调整后的高度差异小于60px(超过url栏高度)然后什么都不做,如果它大于60px,然后再次设置bg1的高度,以其父母的身高! 完整的代码:

 window.addEventListener("resize", onResize, false); var BG = document.getElementById('bg1'); BG.style.height = BG.parentElement.clientHeight; var oldH = BG.parentElement.clientHeight; function onResize() { if(Math.abs(oldH - BG.parentElement.clientHeight) > 60){ BG.style.height = BG.parentElement.clientHeight + 'px'; oldH = BG.parentElement.clientHeight; } } 

PS:这个bug太刺激了!

对于那些想要倾听窗口的实际内部高度和垂直滚动,而Chrome移动浏览器正在转换的url栏从显示到隐藏,反之亦然,我发现的唯一的解决办法是设置一个间隔函数,测量window.innerHeight与之前的值的差异。

这介绍了这个代码:

 var innerHeight = window.innerHeight; window.setInterval(function () { var newInnerHeight = window.innerHeight; if (newInnerHeight !== innerHeight) { var newScrollY = window.scrollY + newInnerHeight - innerHeight; // ... do whatever you want with this new scrollY innerHeight = newInnerHeight; } }, 1000 / 60); 

我遇到过类似问题的解决方法是在每次touchmove事件被触发时将元素的高度设置为window.innerHeight

 var lastHeight = ''; $(window).on('resize', function () { // remove height when normal resize event is fired and content redrawn if (lastHeight) { $('#bg1').height(lastHeight = ''); } }).on('touchmove', function () { // when window height changes adjust height of the div if (lastHeight != window.innerHeight) { $('#bg1').height(lastHeight = window.innerHeight); } }); 

这使得元素始终跨越可用屏幕的100%,不多也不less。 即使在地址栏隐藏或显示。

不过可惜的是,我们必须拿出这样的补丁,简单的position: fixed应该工作。

类似@AlexKempton的答案。 (不能评论遗憾)

我一直在使用长转换延迟来防止元素大小调整。

例如:

 transition: height 250ms 600s; /*10min delay*/ 

这样做的好处是可以防止包括设备旋转在内的元素的大小调整,但是,如果这是一个问题,则可以使用一些JS检测orientationchange并重置高度。