当地址栏隐藏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
,看看它是不是有问题的浏览器之一。 如果是,请按照下列步骤操作:
- 将相关高度设置为当前视口高度而不是“100%”
- 存储当前视口的水平值
- 然后,在
$(window).resize
,如果新的水平视口尺寸与初始值不同,则只更新相关的高度值 - 存储新的水平和垂直值
或者,也可以只在超出地址栏高度的情况下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
并重置高度。