地址栏隐藏 iOS/Android/Mobile Chrome 时背景图片跳转
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24944925/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Background image jumps when address bar hides iOS/Android/Mobile Chrome
提问by Dave Clarke
I'm currently developing a responsive site using Twitter Bootstrap.
我目前正在使用 Twitter Bootstrap 开发一个响应式网站。
The site has a full screen background image across mobile/tablet/desktop. These images rotate and fade through each, using two divs.
该网站在移动/平板电脑/桌面上有一个全屏背景图像。这些图像使用两个 div 旋转并淡入淡出。
It's nearly perfect, except one issue. Using iOS Safari, Android Browser or Chrome on Android the background jumps slightly when a user scrolls down the page and causes the address bar to hide.
除了一个问题,它几乎是完美的。在 Android 上使用 iOS Safari、Android 浏览器或 Chrome 时,当用户向下滚动页面并导致地址栏隐藏时,背景会轻微跳跃。
The site is here: http://lt2.daveclarke.me/
该网站在这里:http: //lt2.daveclarke.me/
Visit it on a mobile device and scroll down and you should see the image resize/move.
在移动设备上访问它并向下滚动,您应该会看到图像调整大小/移动。
The code I'm using for the background DIV is as follows:
我用于后台 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;
}
All suggestions welcome - this has been doing my head in for a while!!
欢迎所有建议 - 这已经让我思考了一段时间!!
采纳答案by Jason
This issue is caused by the URL bars shrinking/sliding out of the way and changing the size of the #bg1 and #bg2 divs since they are 100% height and "fixed". Since the background image is set to "cover" it will adjust the image size/position as the containing area is larger.
此问题是由 URL 栏缩小/滑开并更改 #bg1 和 #bg2 div 的大小引起的,因为它们是 100% 高度且“固定”。由于背景图像设置为“覆盖”,它将随着包含区域的增大而调整图像大小/位置。
Based on the responsive nature of the site, the background must scale. I entertain two possible solutions:
根据站点的响应性质,背景必须缩放。我有两种可能的解决方案:
1) Set the #bg1, #bg2 height to 100vh. In theory, this an elegant solution. However, iOS has a vh bug (http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/). I attempted using a max-height to prevent the issue, but it remained.
1) 将#bg1、#bg2 高度设置为 100vh。理论上,这是一个优雅的解决方案。但是,iOS 有一个 vh 错误(http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/)。我尝试使用 max-height 来防止这个问题,但它仍然存在。
2) The viewport size, when determined by Javascript, is not affected by the URL bar. Therefore, Javascript can be used to set a static height on the #bg1 and #bg2 based on the viewport size. This is not the best solution as it isn't pure CSS and there is a slight image jump on page load. However, it is the only viable solution I see considering iOS's "vh" bugs (which do not appear to be fixed in iOS 7).
2) 由 Javascript 确定的视口大小不受 URL 栏的影响。因此,可以使用 Javascript 根据视口大小在 #bg1 和 #bg2 上设置静态高度。这不是最好的解决方案,因为它不是纯 CSS 并且页面加载时有轻微的图像跳转。但是,考虑到 iOS 的“vh”错误(在 iOS 7 中似乎没有修复),这是我看到的唯一可行的解决方案。
var bg = $("#bg1, #bg2");
function resizeBackground() {
bg.height($(window).height());
}
$(window).resize(resizeBackground);
resizeBackground();
On a side note, I've seen so many issues with these resizing URL bars in iOS and Android. I understand the purpose, but they really need to think through the strange functionality and havoc they bring to websites. The latest change, is you can no longer "hide" the URL bar on page load on iOS or Chrome using scroll tricks.
顺便提一下,我在 iOS 和 Android 中看到了这些调整 URL 栏大小的问题。我理解其目的,但他们确实需要仔细考虑它们给网站带来的奇怪功能和破坏。最新的变化是,您不能再使用滚动技巧在 iOS 或 Chrome 上的页面加载时“隐藏”URL 栏。
EDIT: While the above script works perfectly for keeping the background from resizing, it causes a noticeable gap when users scroll down. This is because it is keeping the background sized to 100% of the screen height minus the URL bar. If we add 60px to the height, as swiss suggests, this problem goes away. It does mean we don't get to see the bottom 60px of the background image when the URL bar is present, but it prevents users from ever seeing a gap.
编辑:虽然上面的脚本可以完美地防止背景调整大小,但当用户向下滚动时,它会导致明显的差距。这是因为它将背景大小保持为屏幕高度减去 URL 栏的 100%。如果我们将高度增加 60 像素,就像瑞士人建议的那样,这个问题就会消失。这确实意味着当 URL 栏存在时我们看不到背景图像底部 60 像素,但它可以防止用户看到间隙。
function resizeBackground() {
bg.height( $(window).height() + 60);
}
回答by AlexKempton
I found that Jason's answer wasn't quite working for me and I was still getting a jump. The Javascript ensured there was no gap at the top of the page but the background was still jumping whenever the address bar disappeared/reappeared. So as well as the Javascript fix, I applied transition: height 999999s
to the div. This creates a transition with a duration so long that it virtually freezes the element.
我发现杰森的回答对我来说不太奏效,我仍然在跳跃。Javascript 确保页面顶部没有间隙,但每当地址栏消失/重新出现时,背景仍在跳跃。因此,除了 Javascript 修复之外,我还应用transition: height 999999s
到了 div。这会创建一个持续时间很长的过渡,它实际上冻结了元素。
回答by mat
I've got a similar issue on a header of our website.
我在我们网站的标题上遇到了类似的问题。
html, body {
height:100%;
}
.header {
height:100%;
}
This will end up in a jumpy scrolling experience on android chrome, because the .header-container will rescale after the url-bar hides and the finger is removed from screen.
这最终会在 android chrome 上出现跳跃的滚动体验,因为 .header-container 将在 url-bar 隐藏并且手指从屏幕上移开后重新缩放。
CSS-Solution:
CSS-解决方案:
Adding the following two lines, will prevent that the url-bar hides and vertical scrolling is still possible:
添加以下两行,将防止 url-bar 隐藏并且仍然可以垂直滚动:
html {
overflow: hidden;
}
body {
overflow-y: scroll;
-webkit-overflow-scrolling:touch;
}
回答by Jordan Los
The problem can be solved with a media query and some math. Here's a solution for a portait orientation:
这个问题可以通过媒体查询和一些数学来解决。这是肖像方向的解决方案:
@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%);
}
Since vh will change when the url bar dissapears, you need to determine the height another way. Thankfully, the width of the viewport is constant and mobile devices only come in a few different aspect ratios; if you can determine the width and the aspect ratio, a little math will give you the viewport height exactly as vh shouldwork. Here's the process
由于当 url bar 消失时 vh 会发生变化,因此您需要以另一种方式确定高度。值得庆幸的是,视口的宽度是恒定的,移动设备只有几种不同的纵横比;如果你能确定宽度和高宽比,一点数学会给你的视口的高度完全一样VH应该工作。这是过程
1) Create a series of media queries for aspect ratios you want to target.
1) 为您想要定位的纵横比创建一系列媒体查询。
use device-aspect-ratio instead of aspect-ratio because the latter will resize when the url bar dissapears
I added 'max' to the device-aspect-ratio to target any aspect ratios that happen to follow in between the most popular. THey won't be as precise, but they will be only for a minority of users and will still be pretty close to the proper vh.
remember the media query using horizontal/vertical , so for portait you'll need to flip the numbers
使用设备纵横比而不是纵横比,因为后者会在网址栏消失时调整大小
我在 device-aspect-ratio 中添加了“max”,以定位最流行的任何纵横比。它们不会那么精确,但它们仅适用于少数用户,并且仍然非常接近正确的 vh。
记住使用水平/垂直的媒体查询,因此对于肖像,您需要翻转数字
2) for each media query multiply whatever percentage of vertical height you want the element to be in vw by the reverse of the aspect ratio.
2)对于每个媒体查询,将您希望元素在 vw 中的垂直高度百分比乘以纵横比的倒数。
- Since you know the width and the ratio of width to height, you just multiply the % you want (100% in your case) by the ratio of height/width.
- 由于您知道宽度和宽度与高度的比率,因此您只需将所需的百分比(在您的情况下为 100%)乘以高度/宽度的比率。
3) You have to determine the url bar height, and then minus that from the height. I haven't found exact measurements, but I use 9% for mobile devices in landscape and that seems to work fairly well.
3)您必须确定网址栏的高度,然后从高度中减去该高度。我还没有找到确切的测量值,但我在横向移动设备上使用了 9%,这似乎效果很好。
This isn't a very elegant solution, but the other options aren't very good either, considering they are:
这不是一个非常优雅的解决方案,但其他选项也不是很好,考虑到它们是:
Having your website seem buggy to the user,
having improperly sized elements, or
Using javascript for some basicstyling,
让您的网站在用户看来有问题,
元素大小不合适,或
使用 javascript 进行一些基本的样式设置,
The drawback is some devices may have different url bar heights or aspect ratios than the most popular. However, using this method if only a small number of devices suffer the addition/subtraction of a few pixels, that seems much better to me than everyone having a website resize when swiping.
缺点是某些设备的 url 栏高度或纵横比可能与最流行的设备不同。但是,如果只有少数设备会添加/减去几个像素,则使用这种方法,对我来说,这比每个人都在滑动时调整网站大小要好得多。
To make it easier, I also created a SASS mixin:
为了方便起见,我还创建了一个 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%);
}
}
回答by cr0ybot
All of the answers here are using window
height, which is affected by the URL bar. Has everyone forgotten about screen
height?
这里的所有答案都使用window
高度,它受 URL 栏的影响。大家都忘记screen
身高了吗?
Here's my jQuery solution:
这是我的 jQuery 解决方案:
$(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);
}
});
Adding the .css()
part is changing the inevitably top-aligned absolute positioned element to bottom aligned, so there is no jump at all. Although, I suppose there's no reason not to just add that directly to the normal CSS.
添加.css()
部分是将不可避免的顶部对齐的绝对定位元素更改为底部对齐,因此根本没有跳转。虽然,我认为没有理由不直接将其添加到普通 CSS 中。
We need the user agent sniffer because screen height on desktops would not be helpful.
我们需要用户代理嗅探器,因为桌面上的屏幕高度没有帮助。
Also, this is all assuming #background
is a fixed-position element filling the window.
此外,这一切都假设#background
是填充窗口的固定位置元素。
For the JavaScript purists (warning--untested):
对于 JavaScript 纯粹主义者(警告 - 未经测试):
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;
}
EDIT: Sorry that this does not directly answer your specific problem with more than one background. But this is one of the first results when searching for this problem of fixed backgrounds jumping on mobile.
编辑:抱歉,这并不能直接回答具有多个背景的特定问题。但这是搜索固定背景在移动设备上跳跃的第一个结果之一。
回答by tobik
I ran into this issue as well when I was trying to create an entrance screen that would cover the whole viewport. Unfortunately, the accepted answer no longer works.
当我尝试创建一个覆盖整个视口的入口屏幕时,我也遇到了这个问题。不幸的是,接受的答案不再有效。
1) Elements with the height set to 100vh
get resized every time the viewport size changes, including those cases when it is caused by (dis)appearing URL bar.
1) 高度设置为100vh
每次视口大小变化时调整大小的元素,包括由(不)出现的 URL 栏引起的情况。
2) $(window).height()
returns values also affected by the size of the URL bar.
2)$(window).height()
返回值也受 URL 栏大小的影响。
One solution is to "freeze" the element using transition: height 999999s
as suggested in the answer by AlexKempton. The disadvantage is that this effectively disables adaptation to all viewport size changes, including those caused by screen rotation.
一种解决方案是按照AlexKempton 的回答中的transition: height 999999s
建议使用“冻结”元素。缺点是这有效地禁用了对所有视口尺寸变化的适应,包括由屏幕旋转引起的变化。
So my solution is to manage viewport changes manually using JavaScript. That enables me to ignore the small changes that are likely to be caused by the URL bar and react only on the big ones.
所以我的解决方案是使用 JavaScript 手动管理视口更改。这使我能够忽略可能由 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);
EDIT: I actually use this technique together with height: 100vh
. The page is rendered properly from the very beginning and then the javascript kicks in and starts managing the height manually. This way there is no flickering at all while the page is loading (or even afterwards).
编辑:我实际上将这种技术与height: 100vh
. 该页面从一开始就正确呈现,然后 javascript 开始并开始手动管理高度。这样在页面加载时(甚至之后)根本没有闪烁。
回答by m-p
The solution I'm currently using is to check the userAgent
on $(document).ready
to see if it's one of the offending browsers. If it is, follow these steps:
目前我使用的解决方案是检查userAgent
上$(document).ready
,看它是否是有问题的浏览器之一。如果是,请执行以下步骤:
- Set the relevant heights to the current viewport height rather than '100%'
- Store the current viewport horizontal value
- Then, on
$(window).resize
, only update the relevant height values if the new horizontalviewport dimension is different from it's initial value - Store the new horizontal & vertical values
- 将相关高度设置为当前视口高度而不是“100%”
- 存储当前视口水平值
- 然后,
$(window).resize
如果新的水平视口尺寸与其初始值不同,则仅更新相关的高度值 - 存储新的水平和垂直值
Optionally, you could also test permitting vertical resizes only when they are beyond the height of the address bar(s).
或者,您还可以测试仅当超出地址栏的高度时才允许垂直调整大小。
Oh, and the address bar does affect $(window).height
. See: Mobile Webkit browser (chrome) address bar changes $(window).height(); making background-size:cover rescale every timeJS "Window" width-height vs "screen" width-height?
哦,地址栏确实会影响$(window).height
. 请参阅:移动 Webkit 浏览器 (chrome) 地址栏更改 $(window).height(); 每次JS“窗口”宽高与“屏幕”宽高时都使背景大小:覆盖重新缩放?
回答by Pav Sidhu
I found a really easy solution without the use of Javascript:
我找到了一个非常简单的解决方案,无需使用 Javascript:
transition: height 1000000s ease;
-webkit-transition: height 1000000s ease;
-moz-transition: height 1000000s ease;
-o-transition: height 1000000s ease;
All this does is delay the movement so that it's incredibly slow that it's not noticeable.
所有这些都是延迟运动,使其慢得令人难以置信。
回答by Todd Miller
My solution involved a bit of javascript. Keep the 100% or 100vh on the div (this will avoid the div not appearing on initial page load). Then when the page loads, grab the window height and apply it to the element in question. Avoids the jump because now you have a static height on your div.
我的解决方案涉及一些 javascript。在 div 上保持 100% 或 100vh(这将避免 div 在初始页面加载时不出现)。然后当页面加载时,获取窗口高度并将其应用于相关元素。避免跳跃,因为现在你的 div 上有一个静态高度。
var $hero = $('#hero-wrapper'),
h = window.innerHeight;
$hero.css('height', h);
回答by Geek Devigner
I created a vanilla javascript solution to using VH units. Using VH pretty much anywhere is effected by address bars minimizing on scroll. To fix the jank that shows when the page redraws, I've got this js here that will grab all your elements using VH units (if you give them the class .vh-fix
), and give them inlined pixel heights. Essentially freezing them at the height we want. You could do this on rotation or on viewport size change to stay responsive.
我创建了一个使用 VH 单位的 vanilla javascript 解决方案。在几乎任何地方使用 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'
}
}
This has solved all my use cases, hope it helps.
这已经解决了我所有的用例,希望它有所帮助。