问题描述
我正在使用 Twitter Bootstrap 开发一个响应式站点。
该网站在移动/平板电脑/桌面上拥有全屏背景图像。这些图像使用两个 div 旋转并逐渐变暗。
这几乎是完美的,除了一个问题。在 Android 上使用 iOS Safari,Android 浏览器或 Chrome 时,当用户向下滚动页面并导致地址栏被隐藏时,背景略微跳转。
该网站在这里:http://lt2.daveclarke.me/
在移动设备上访问它并向下滚动,您应该看到图像调整大小/移动。
我用于背景 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;
}
所有的建议欢迎 – 这已经做了我的头一段时间!
最佳解决方案
这个问题是由于 URL 栏缩小/滑动导致的,因为它们是 100%的高度,而且改变了#bg2 和#bg2 div 的大小,而且”fixed” 。由于背景图像设置为”cover”,因为包含区域较大,所以将调整图像尺寸/位置。
根据网站的反应性质,背景必须扩大。我接受两种可能的解决方案:
1) 将#bg1,#bg2 的高度设置为 100vh 。在理论上,这是一个优雅的解决方案。但是,iOS 有一个 vh bug(http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/) 。我尝试使用 max-height 来防止问题,但仍然存在。
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();
在旁注中,我在 iOS 和 Android 中看到了这些调整大小的网址栏的许多问题。我明白目的,但他们真的需要考虑到他们带给网站的奇怪的功能和破坏。最新的变化是,您不能再在”hide” 上使用滚动技巧在 iOS 或 Chrome 上加载网页栏。
编辑:虽然上述脚本非常适合保持背景调整大小,但当用户向下滚动时,会导致明显的差距。这是因为它将背景大小保留到屏幕高度的 100%减去 URL 栏。如果我们添加 60px 的高度,如瑞士所说,这个问题消失了。这意味着当 URL 栏存在时,我们不会看到背景图片的底部 60px,但它阻止用户看到差距。
function resizeBackground() {
bg.height( $(window).height() + 60);
}
次佳解决方案
我发现杰森的回答对我来说不是很有效,而且我还是跳起来。 Javascript 确保页面顶部没有间隙,但是当地址栏消失/重新出现时,背景仍然跳动。所以以及 Javascript 修复,我将 transition: height 999999s
应用到 div 。这将创建一个持续时间过长的转换,以使其几乎冻结该元素。
第三种解决方案
我在网站的标题上有类似的问题。
html, body {
height:100%;
}
.header {
height:100%;
}
这将导致 Android Chrome 上的滚动滚动体验,因为.header-container 将在 url-bar 隐藏后重新缩放,手指从屏幕上移除。
CSS-Solution:
添加以下两行,将防止 url-bar 隐藏,并且垂直滚动仍然可能:
html {
overflow: hidden;
}
body {
overflow-y: scroll;
-webkit-overflow-scrolling:touch;
}
第四种方案
这个问题可以通过媒体查询和一些数学来解决。这是一个 portait 方向的解决方案:
@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 栏消失时发生变化,您需要以另一种方式确定高度。幸运的是,视口的宽度是恒定的,移动设备只有几种不同的宽高比; 如果您可以确定宽度和宽高比,一点点数学就会使您的视口高度正好与 vh 一样工作。这是这个过程
1) 创建一系列要定位的宽高比的媒体查询。
-
使用 device-aspect-ratio 而不是 aspect-ratio,因为后者将在 url bar 消失时调整大小
-
我将’max’ 添加到 device-aspect-ratio 中,以便将最受欢迎的任何纵横比定位到最接近的位置。这不会那么精确,但是他们只会为少数用户使用,并且仍然会非常接近正确的呃。
-
记住使用水平/垂直的媒体查询,因此对于 portait,您需要翻转数字
2) 对于每个媒体查询乘以垂直高度的任何百分比,您希望元素在 vw 中与宽高比相反。
-
由于您知道宽度和宽度与高度的比例,因此您只需将所需的百分比 (您的情况下为 100%) 乘以高度/宽度的比例。
3) 你必须确定 URL 栏的高度,然后从该高度减去。我没有发现确切的测量,但是我在景观上使用 9%的移动设备,这似乎工作得很好。
这不是一个非常优雅的解决方案,但其他选项也不是很好,考虑到它们是:
-
让你的网站看起来很漂亮的用户,
-
或者
-
使用 javascript 进行一些基本样式,
缺点是一些设备可能具有与最受欢迎的不同的网址高度或宽高比。然而,如果只有少数设备遭受加法/减法的几个像素,那么使用这种方法,对于我来说,这显然比刷新网站大小的人都好。
为了更容易,我还创建了一个 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 解决方案:
$(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()
部件正在将 top-aligned 绝对定位元件不可避免地改变为底部对齐,所以根本没有跳转。虽然,我想没有理由不直接添加到正常的 CSS 。
我们需要用户代理嗅探器,因为桌面上的屏幕高度不会有所帮助。
此外,这是假设 #background
是填充窗口的 fixed-position 元素。
对于 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;
}
编辑:对不起,这不直接回答您的具体问题与多个背景。但是,这是搜索固定背景在手机上跳跃的问题的第一个结果之一。
第六种方案
我目前使用的解决方案是检查 $(document).ready
上的 userAgent
,看看它是否是一个违规的浏览器。如果是,请按照下列步骤操作:
-
将相关高度设置为当前视口高度而不是’100%’
-
存储当前视口水平值
-
然后,在
$(window).resize
上,如果新的水平视口尺寸与初始值不同,则仅更新相关的高度值 -
存储新的水平& 垂直值
或者,您还可以测试允许垂直调整大小,只有当它们超出地址栏的高度时。
哦,地址栏确实影响 $(window).height
。参见:Mobile Webkit browser (chrome) address bar changes $(window).height(); making background-size:cover rescale every time JS “Window” width-height vs “screen” width-height?
第七种方案
当我尝试创建一个覆盖整个视口的入口屏幕时,我遇到了这个问题。不幸的是,接受的答案不再有效。
1) 高度设置为 100hv
的元素在每次视口大小更改时都被调整大小,包括由 (dis) 出现的 URL 栏引起的情况。
2)$(window).height()
返回值也受到 URL 栏大小的影响。
一个解决方案是”freeze” 的元素使用 transition: height 999999s
建议在 the answer by AlexKempton 。缺点是,这有效地禁用了适应所有视口大小的变化,包括由屏幕旋转引起的变化。
所以我的解决方案是使用 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);
编辑:我实际上和 height: 100hv
一起使用这种技术。该页面从一开始就可以正常渲染,然后 JavaScript 会手动启动并开始管理高度。这样,页面正在加载 (甚至之后) 就完全没有闪烁。
第八种方案
我发现一个非常简单的解决方案,而不使用 Javascript:
transition: height 1000000s ease;
-webkit-transition: height 1000000s ease;
-moz-transition: height 1000000s ease;
-o-transition: height 1000000s ease;
所有这一切都是延迟运动,所以它是非常缓慢,这是不明显的。
第九种方案
我的解决方案涉及到一些 javascript 。保持 100%或 100vh 在 div(这将避免 div 不出现在初始页面加载) 。然后当页面加载时,抓住窗口高度并将其应用到相关元素。避免跳跃,因为现在你的 div 上有一个静态高度。
var $hero = $('#hero-wrapper'),
h = window.innerHeight;
$hero.css('height', h);
参考文献
注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。