問題描述

我正在使用 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 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇