问题描述

我正在使用 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,看看它是否是一个违规的浏览器。如果是,请按照下列步骤操作:

  1. 将相关高度设置为当前视口高度而不是’100%’

  2. 存储当前视口水平值

  3. 然后,在 $(window).resize 上,如果新的水平视口尺寸与初始值不同,则仅更新相关的高度值

  4. 存储新的水平&垂直值

或者,您还可以测试允许垂直调整大小,只有当它们超出地址栏的高度时。

哦,地址栏确实影响 $(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 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛