web-dev-qa-db-ja.com

アドレスバーがiOS / Android / Mobile Chromeを非表示にすると背景画像がジャンプする

私は現在Twitter Bootstrapを使用してレスポンシブサイトを開発しています。

このサイトは、モバイル/タブレット/デスクトップ上にフルスクリーンの背景画像があります。これらの画像は、2つのdivを使用してそれぞれ回転しながらフェードインします。

1つの問題を除いて、それはほぼ完璧です。 iOS Safari、Androidブラウザ、または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;
}

すべての提案を歓迎します - これはしばらくの間私の頭の中をやっています!

160
Dave Clarke

この問題は、URLバーが縮み/スライドして邪魔にならず、#bg1および#bg2 divのサイズが100%の高さで固定されているために変更されることが原因で発生します。背景画像は「表紙」に設定されているので、包含領域が大きいほど画像のサイズ/位置を調整します。

サイトのレスポンシブな性質に基づいて、背景は拡大縮小する必要があります。私は2つの可能な解決策を楽しませます:

1)#bg1、#bg2の高さを100vhに設定します。理論的には、これはエレガントな解決策です。しかし、iOSにはvhバグがあります( http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/ )。私はこの問題を防ぐために最大の高さを使用しようとしました、しかしそれは残りました。

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でこれらのサイズ変更URLバーに関する非常に多くの問題を見ました。私はその目的を理解していますが、彼らは本当に彼らがウェブサイトにもたらす奇妙な機能性と混乱を通して考える必要があります。最新の変更は、スクロールトリックを使用してiOSまたはChromeでページロード時にURLバーを「隠す」ことができなくなったことです。

編集:上記のスクリプトは背景がリサイズされないようにするためには完璧に機能しますが、ユーザーが下にスクロールすると顕著なギャップが生じます。これは、背景のサイズを画面の高さの100%からURLバーを引いたものにしているためです。スイスが示唆しているように高さに60pxを加えると、この問題は解決します。これは、URLバーが表示されているときに背景画像の下部60ピクセルが表示されないことを意味しますが、ユーザーにギャップが表示されるのを防ぎます。

function resizeBackground() {
    bg.height( $(window).height() + 60);
}
99
Jason

私はJasonの答えがあまりうまくいかなかったことに気付きました、そして私はまだ急上昇していました。 Javascriptはページの上部に隙間がないことを確認しましたが、アドレスバーが消えたり再表示されたりしたときはいつでも背景がジャンプしていました。 Javascriptの修正と同様に、私はdivにtransition: height 999999sを適用しました。これにより、要素が事実上フリーズするほどの長さのトランジションが作成されます。

59
AlexKempton

私たちのウェブサイトのヘッダーにも同様の問題があります。

html, body {
    height:100%;
}
.header {
    height:100%;
}

URLバーが非表示になり、指が画面から削除された後に.header-containerのサイズが変更されるため、これはAndroidクロムでの飛び跳ねるスクロール操作になります。

CSS-Solution:

次の2行を追加すると、URLバーの非表示と垂直スクロールが可能になることを防ぐことができます。

html {
    overflow: hidden;
}
body {
    overflow-y: scroll;
    -webkit-overflow-scrolling:touch;
}
22
mat

問題はメディアの問い合わせといくつかの数学で解決することができます。これは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%);
}

URLバーが消えるとvhが変わるので、高さを別の方法で決める必要があります。ありがたいことに、ビューポートの幅は一定で、モバイルデバイスはいくつかの異なる縦横比しかありません。あなたが幅とアスペクト比を決定することができるならば、vhがそうするべきであるように正確にあなたのビューポートの高さを少しの数学があなたに与えるでしょう。これがプロセスです

1)ターゲットにする縦横比について一連のメディアクエリを作成します。

  • uRLバーが消えると後者のサイズが変わるので、縦横比ではなくデバイス縦横比を使用します。

  • 私はdevice-aspect-ratioに 'max'を追加して、最も人気のあるアスペクト比の間で起こるアスペクト比をターゲットにしました。それほど正確ではありませんが、少数のユーザー向けであり、それでも適切なvhにかなり近いものになるでしょう。

  • 水平/垂直を使用したメディアクエリを覚えているので、portaitのためにあなたは数字を反転する必要があるでしょう

2)各メディアクエリに対して、要素を縦横比の逆数でvwにしたい垂直方向の高さの割合を乗算します。

  • 幅と高さに対する幅の比率はわかっているので、必要な%(この場合は100%)に高さ/幅の比率を掛けます。

3)URLバーの高さを決めてから、高さからマイナスします。正確な測定値は見つかりませんでしたが、横長のモバイルデバイスには9%を使用しています。これはかなりうまくいくようです。

これはそれほど洗練された解決策ではありませんが、他の選択肢もあまり良くありません。

  • あなたのウェブサイトをユーザーにバグがあるように思わせる

  • 不適切なサイズの要素がある、または

  • いくつかの基本的なスタイルにJavaScriptを使用する、

欠点は、一部のデバイスでは最も人気のあるものとは異なるURLバーの高さまたは縦横比がある可能性があることです。ただし、少数のデバイスで数ピクセルの加減算が行われる場合にこの方法を使用するのは、スワイプ時にWebサイトのサイズを変更するよりもはるかに優れているように思われます。

簡単にするために、私は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%);
  }
}
14
Jordan Los

ここでの答えはすべてURLバーの影響を受けるwindowの高さを使用しています。誰もが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()部分を追加すると、必然的に上揃えの絶対配置要素が下揃えに変更されるので、ジャンプはまったくありません。とはいえ、それを通常のCSSに直接追加しないだけの理由はないと思います。

デスクトップの画面の高さは役に立たないので、ユーザーエージェントのスニファが必要です。

また、これは#backgroundがウィンドウを埋める固定位置の要素であることをすべて前提としています。

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;
}

編集:これは直接複数の背景を持つあなたの特定の問題に答えるものではないことを残念。しかし、これはモバイルでジャンプする固定背景のこの問題を探すときの最初の結果の1つです。

12
cr0ybot

ビューポート全体をカバーする入り口スクリーンを作成しようとしたときにも、この問題に遭遇しました。残念ながら、受け入れられた答えはもはや機能しません。

1)高さが100vhに設定されている要素は、ビューポートのサイズが変わるたびにサイズが変更されます。これは、URLバーが表示されない(表示されない)ことが原因です。

2)$(window).height()は、URLバーのサイズによっても影響を受ける値を返します。

1つの解決策は、 AlexKemptonによる回答 で提案されているようにtransition: height 999999sを使用して要素を「凍結」することです。デメリットは、これにより、画面の回転によるものも含め、すべてのビューポートサイズの変更に対する適応が事実上無効になることです。

私の解決策は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: 100vhと一緒にこのテクニックを使っています。ページは最初から正しくレンダリングされ、その後JavaScriptが起動して手動で高さの管理を開始します。このようにして、ページがロードされている間(またはその後でさえ)、ちらつきはまったくありません。

9
tobik

私が現在使用している解決策は、$(document).readyuserAgentを調べて、問題のあるブラウザの1つであるかどうかを確認することです。そうであれば、次のステップに従ってください。

  1. 関連する高さを '100%'ではなく現在のビューポートの高さに設定します
  2. 現在のビューポートの水平方向の値を保存します
  3. 次に、$(window).resizeで、新しい水平ビューポートの寸法が初期値と異なる場合にのみ、関連する高さの値を更新します。
  4. 新しい水平方向と垂直方向の値を保存する

必要に応じて、アドレスバーの高さを超えている場合にのみ垂直方向のサイズ変更を許可することをテストすることもできます。

ああ、そしてアドレスバーは$(window).heightに影響します。参照項目: Mobile Webkitブラウザ(クロム)アドレスバーの変更$(ウィンドウ).height();背景サイズの作成:カバーのサイズ変更を毎回行うJS "ウィンドウ"幅 - 高さvs "画面"幅 - 高さ?

8
m-p

Javascriptを使わずに、本当に簡単な解決策を見つけました。

transition: height 1000000s ease;
-webkit-transition: height 1000000s ease;
-moz-transition: height 1000000s ease;
-o-transition: height 1000000s ease;

これは、動きを遅らせるだけなので、目に見えないほど非常に遅いです。

4
Pav Sidhu

VHユニットを使用するためのVanilla javascriptソリューションを作成しました。ほとんどどこでもVHを使用すると、スクロール時のアドレスバーが最小化されます。ページの再描画時に表示されるジャンクを修正するために、VHユニット(クラス.vh-fixを指定した場合)を使用してすべての要素を取得し、インラインピクセルの高さを指定するこのjsをここに用意しました。基本的に、必要な高さでそれらを凍結します。回転またはビューポートサイズの変更時にこれを行うと、応答性を維持できます。

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'
  }
}

これで私のすべてのユースケースが解決しました。役に立てば幸いです。

3
Geek Devigner

これはこの問題を解決するための私の解決策です、私はコードに直接コメントを加えました。私はこの解決策をテストしましたが、うまくいきました。私たちは誰もが同じ問題を抱えているために役立つことを願っています。

//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
  }); 
};
3
lino

私の解決策は少しJavaScriptを含んでいました。 divに100%または100vhを維持します(これにより、divが最初のページ読み込み時に表示されなくなります)。次に、ページが読み込まれたら、ウィンドウの高さをつかみ、それを問題の要素に適用します。今あなたはあなたのdivに静的な高さがあるのでジャンプを避けます。

var $hero = $('#hero-wrapper'),
    h     = window.innerHeight;

$hero.css('height', h);
3
Todd Miller

これは私が試したすべてのものの中で(最も簡単な)最善の解決策です。

...そしてこれはアドレスバーの本来の経験を維持するものではありません

たとえば、CSSを使用して高さを100%に設定してから、javascriptを使用して、ドキュメントが読み込まれたときにpxでウィンドウの高さの0.9 *に設定することができます。

例えばjQueryの場合:

$("#element").css("height", 0.9*$(window).height());

残念ながら、純粋なCSS:Pでは機能するものは何もありませんが、vhおよびvwがiPhone上でバグがあることにも注意してください - パーセンテージを使用します。

2
user742030

JavaScriptを使ってwidth要素を設定します。私は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を使いません。できるだけ早く読み込むようにしたいのです。

1
Johan Hoeksma

背景が許せば簡単な答え、なぜbackground-size:をメディアクエリでデバイスの幅をカバーするだけのものに設定し、:after position:fixedと一緒に使用しないでください。ハック ここ

IE:背景サイズ:901ピクセル。 900px未満のスクリーンでは?私は抽象的なBGを使用しているので、完璧でも反応的でもありませんが、モバイル<480pxで私にとって魅力的でした。

1
EasterMedia

この問題の詳細をすべて理解し、最適な実装を理解するのに数時間かかりました。 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');
});
1
littlequest

私が似たような問題を抱えているときに思いついた解決策は、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%にまたがります。アドレスバーの非表示または表示中にも.

それにもかかわらず、単純なposition: fixedが機能するはずのそのようなパッチを考えなければならないのは残念です。

0
Paul

@AlexKemptonの回答に似ています。 (申し訳ありませんがコメントできませんでした)

要素のサイズ変更を防ぐために長い遷移遅延を使用しています。

例えば:

transition: height 250ms 600s; /*10min delay*/

これとのトレードオフは、デバイスの回転を含む要素のサイズ変更を防ぐことです。ただし、問題がある場合は、JSを使用してorientationchangeを検出し、高さをリセットすることができます。

0
Chris Anderson

この回避策を使用しています。ページ読み込み時のbg1の高さを次の方法で修正します。

var BG = document.getElementById('bg1');
BG.style.height = BG.parentElement.clientHeight;

サイズ変更後の高さの差が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;
    }
}

シモンズ:このバグはとてもイライラする!

0
AadityaTaparia

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);

これが便利になることを願っています。誰かがより良い解決策を知っていますか?

0