it-swarm.com.de

Das Hintergrundbild springt, wenn die Adressleiste iOS/Android/Mobile Chrome verbirgt

Ich entwickle derzeit eine responsive Site mit Twitter Bootstrap.

Die Website verfügt über ein Vollbild-Hintergrundbild für Mobilgeräte/Tablet/Desktop. Diese Bilder werden durch zwei Divs rotiert und ausgeblendet.

Es ist fast perfekt, bis auf ein Problem. Bei Verwendung von iOS Safari, Android Browser oder Chrome unter Android springt der Hintergrund leicht, wenn ein Benutzer auf der Seite nach unten blättert und die Adressleiste ausgeblendet wird.

Die Website ist hier: http://lt2.daveclarke.me/

Besuchen Sie es auf einem mobilen Gerät und scrollen Sie nach unten, und Sie sollten das Bild vergrößern/verkleinern/verschieben. 

Der Code, den ich für den Hintergrund DIV verwende, lautet wie folgt:

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

Alle Vorschläge sind willkommen - das hat mir schon eine Weile gedauert !!

157
Dave Clarke

Dieses Problem wird dadurch verursacht, dass die URL-Leisten schrumpfen/aus dem Weg rollen und die Größe der Divisionen # bg1 und # bg2 ändern, da sie eine Höhe von 100% und "fixiert" haben. Da das Hintergrundbild auf "Abdeckung" eingestellt ist, wird die Bildgröße position angepasst, wenn der enthaltende Bereich größer ist.

Aufgrund der Reaktionsfähigkeit der Website muss der Hintergrund skaliert werden. Ich unterhalte zwei mögliche Lösungen:

1) Stellen Sie die Höhe von # bg1, # bg2 auf 100 vh ein. Theoretisch ist dies eine elegante Lösung. IOS hat jedoch einen vh-Fehler (/ - http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/ ). Ich habe versucht, eine maximale Höhe zu verwenden, um das Problem zu verhindern, aber es blieb bestehen. 

2) Die Größe des Darstellungsfelds wird durch die URL-Leiste nicht beeinflusst, wenn es durch Javascript festgelegt wird. Daher kann mit Javascript eine statische Höhe für # bg1 und # bg2 basierend auf der Größe des Darstellungsbereichs festgelegt werden. Dies ist nicht die beste Lösung, da es kein reines CSS ist und beim Laden der Seite ein leichter Bildsprung auftritt. Es ist jedoch die einzige realisierbare Lösung, die ich sehe, wenn man die "vh" -Fehler von iOS betrachtet (die in iOS 7 nicht behoben zu sein scheinen).

var bg = $("#bg1, #bg2");

function resizeBackground() {
    bg.height($(window).height());
}

$(window).resize(resizeBackground);
resizeBackground();

Nebenbei bemerkt, ich habe so viele Probleme mit diesen Größenänderungs-URL-Leisten in iOS und Android gesehen. Ich verstehe den Zweck, aber sie müssen wirklich über die merkwürdige Funktionalität und das Chaos nachdenken, das sie auf Websites bringen. Die letzte Änderung ist, dass Sie die URL-Leiste beim Laden der Seite unter iOS oder Chrome nicht mehr mithilfe von Scroll-Tricks "ausblenden" können.

BEARBEITEN: Das obige Skript funktioniert zwar perfekt, um die Größenanpassung des Hintergrunds zu verhindern, verursacht jedoch eine deutliche Lücke, wenn Benutzer nach unten scrollen. Dies liegt daran, dass der Hintergrund auf 100% der Bildschirmhöhe minus URL-Leiste eingestellt wird. Wenn wir die Höhe um 60px erhöhen, wie von Swiss vorgeschlagen, verschwindet dieses Problem. Das bedeutet, dass wir nicht die untersten 60px des Hintergrundbilds sehen können, wenn die URL-Leiste vorhanden ist. Dies verhindert jedoch, dass Benutzer eine Lücke sehen.

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

Ich stellte fest, dass Jasons Antwort für mich nicht ganz funktionierte und ich immer noch einen Sprung bekam. Das Javascript stellte sicher, dass keine Lücke am oberen Rand der Seite vorhanden war. Der Hintergrund sprang jedoch immer dann, wenn die Adressleiste verschwand/wieder angezeigt wurde. Neben dem Javascript-Fix habe ich also transition: height 999999s auf das div angewendet. Dadurch wird ein Übergang mit einer Dauer erstellt, die das Element praktisch einfriert.

59
AlexKempton

Ich habe eine ähnliche Ausgabe in einem Header unserer Website.

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

Dies führt bei Android Chrome zu einem sprunghaften Bildlauf, da der .header-Container neu skaliert wird, nachdem der URL-Balken ausgeblendet wurde und der Finger vom Bildschirm entfernt wurde.

CSS-Lösung:

Durch das Hinzufügen der folgenden zwei Zeilen wird verhindert, dass der URL-Balken ausgeblendet wird und der vertikale Bildlauf weiterhin möglich ist:

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

Das Problem kann mit einer Medienabfrage und etwas Mathematik gelöst werden. Hier ist eine Lösung für eine Portait-Orientierung:

@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%);
}

Da sich vh ändert, wenn die URL-Leiste verschwindet, müssen Sie die Höhe auf andere Weise bestimmen. Glücklicherweise ist die Breite des Ansichtsfensters konstant und mobile Geräte haben nur ein paar unterschiedliche Seitenverhältnisse. Wenn Sie die Breite und das Seitenverhältnis bestimmen können, erhalten Sie mit ein wenig Berechnung die Höhe des Ansichtsfensters genauso wie vh soll . Hier ist der Prozess

1) Erstellen Sie eine Reihe von Medienabfragen für Seitenverhältnisse, die Sie als Ziel festlegen möchten.

  • verwenden Sie das Seitenverhältnis des Geräts anstelle des Seitenverhältnisses, da die Größe des letzteren geändert wird, wenn der URL-Stab verschwindet

  • Ich fügte dem Geräte-Seitenverhältnis "max" hinzu, um alle Seitenverhältnisse zu berücksichtigen, die zufällig zwischen den beliebtesten liegen. Sie sind zwar nicht so präzise, ​​aber sie werden nur für eine Minderheit der Benutzer sein und sind dennoch ziemlich nahe am richtigen vh.

  • erinnern Sie sich an die Medienabfrage mit horizontal/vertikal, so dass Sie für Portait die Zahlen umdrehen müssen

2) Multiplizieren Sie für jede Medienabfrage den Prozentsatz der vertikalen Höhe, für den das Element in vw sein soll, mit der Umkehrung des Seitenverhältnisses. 

  • Da Sie die Breite und das Verhältnis von Breite zu Höhe kennen, multiplizieren Sie einfach die gewünschten% (in Ihrem Fall 100%) mit dem Verhältnis von Höhe zu Breite. 

3) Sie müssen die Höhe der URL-Leiste bestimmen und diese dann von der Höhe abziehen. Ich habe keine exakten Maße gefunden, aber ich verwende 9% für mobile Geräte in der Landschaft, und das scheint ziemlich gut zu funktionieren.

Dies ist keine sehr elegante Lösung, aber auch die anderen Optionen sind nicht sehr gut, wenn man bedenkt, dass sie: 

  • Wenn Ihre Website für den Benutzer fehlerhaft erscheint, 

  • mit ungeeigneten Elementen, oder 

  • Verwenden von Javascript für einige grundlegende Styling, 

Der Nachteil ist, dass einige Geräte andere URL-Stabhöhen oder Seitenverhältnisse haben als die gängigsten. Wenn jedoch diese Methode angewendet wird, wenn nur eine kleine Anzahl von Geräten die Addition/Subtraktion einiger Pixel erleidet, erscheint mir dies viel besser als jeder, der über eine Website verfügt, wenn er die Größe ändert. 

Um es einfacher zu machen, habe ich auch ein SASS Mixin erstellt:

@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

Alle Antworten hier verwenden window height, die von der URL-Leiste beeinflusst wird. Hat jeder die screen Höhe vergessen?

Hier ist meine jQuery-Lösung:

$(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);
  }
});

Durch das Hinzufügen des Teils .css() wird das zwangsläufig nach oben ausgerichtete, absolut positionierte Element nach unten ausgerichtet, sodass überhaupt kein Sprung erfolgt. Ich denke jedoch, dass es keinen Grund gibt, das nicht direkt in das normale CSS einzufügen.

Wir benötigen den User Agent Sniffer, da die Bildschirmhöhe auf Desktops nicht hilfreich ist.

Dies alles setzt auch voraus, dass #background ein Element mit fester Position ist, das das Fenster ausfüllt.

Für die JavaScript-Puristen (Warnung - nicht getestet):

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

BEARBEITEN: Es tut uns leid, dass dies Ihr spezifisches Problem nicht direkt mit mehr als einem Hintergrund löst. Dies ist jedoch eines der ersten Ergebnisse bei der Suche nach diesem Problem fester Hintergründe, die auf dem Handy springen.

12
cr0ybot

Ich bin auch auf dieses Problem gestoßen, als ich versuchte, einen Eingangsbildschirm zu erstellen, der den gesamten Ansichtsbereich abdeckt. Leider funktioniert die akzeptierte Antwort nicht mehr.

1) Elemente, deren Höhe auf 100vh eingestellt ist, werden bei jeder Änderung der Größe des Ansichtsfensters in der Größe geändert, einschließlich der Fälle, in denen dies durch (nicht) erscheinende URL-Leisten verursacht wird.

2) $(window).height() gibt Werte zurück, die auch von der Größe der URL-Leiste beeinflusst werden.

Eine Lösung besteht darin, das Element mit transition: height 999999s "einzufrieren", wie in der Antwort von AlexKempton vorgeschlagen. Der Nachteil ist, dass dadurch die Anpassung an alle Änderungen der Ansichtsfenstergröße, einschließlich der durch das Drehen des Bildschirms verursachten, effektiv deaktiviert wird.

Meine Lösung besteht also darin, Viewport-Änderungen manuell mit JavaScript zu verwalten. Dadurch kann ich die kleinen Änderungen, die wahrscheinlich durch die URL-Leiste verursacht werden, ignorieren und nur auf die großen reagieren.

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

BEARBEITEN: Ich verwende diese Technik tatsächlich zusammen mit height: 100vh. Die Seite wird von Anfang an richtig gerendert. Anschließend wird das Javascript aktiviert und die Höhe wird manuell verwaltet. Auf diese Weise wird beim Laden der Seite (oder sogar danach) überhaupt kein Flackern ausgeführt.

9
tobik

Die Lösung, die ich derzeit verwende, besteht darin, die Variable userAgent auf $(document).ready zu überprüfen, um festzustellen, ob es sich um einen der beleidigenden Browser handelt. Wenn ja, folgen Sie diesen Schritten: 

  1. Setzen Sie die relevanten Höhen auf die aktuelle Höhe des Ansichtsfensters anstatt auf "100%". 
  2. Speichern Sie den aktuellen horizontalen Wert des Ansichtsfensters 
  3. Aktualisieren Sie dann bei $(window).resize die relevanten Höhenwerte nur, wenn sich die neue Ansichtsdimension horizontal von ihrem Anfangswert unterscheidet 
  4. Speichern Sie die neuen horizontalen und vertikalen Werte

Optional können Sie auch das Erlauben vertikaler Größenänderungen nur testen, wenn diese über der Höhe der Adressleiste (n) liegen. 

Oh, und die Adressleiste wirkt sich auf $(window).height aus. Siehe: Adressleiste des Mobile Webkit-Browsers (Chrome) $ (Fenster) .height (); Hintergrundgröße erstellen: Cover jedes Mal neu skalierenJS "Window" width-height vs. "screen" width-height?

8
m-p

Ich habe eine wirklich einfache Lösung ohne die Verwendung von Javascript gefunden:

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

Das alles verzögert die Bewegung so, dass sie unglaublich langsam ist und nicht auffällt.

4
Pav Sidhu

Ich habe eine Vanilla-Javascript-Lösung für die Verwendung von VH-Einheiten entwickelt. Die Verwendung von VH wird praktisch überall durch Adressleisten bewirkt, die beim Scrollen minimiert werden. Um den Jank zu korrigieren, der angezeigt wird, wenn die Seite neu gezeichnet wird, habe ich hier ein js, das alle Ihre Elemente mit VH-Einheiten (wenn Sie ihnen die Klasse .vh-fix geben) erfasst und ihnen inline Pixelhöhe gibt. Sie werden im Wesentlichen auf der gewünschten Höhe eingefroren. Sie können dies bei Rotation oder Änderung der Ansichtsfenstergröße tun, um ansprechbar zu bleiben.

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

Dies hat alle meine Anwendungsfälle gelöst, ich hoffe es hilft. 

3
Geek Devigner

dies ist meine Lösung, um dieses Problem zu beheben. Ich habe direkt Kommentare zum Code hinzugefügt. __ Ich habe diese Lösung getestet und funktioniert einwandfrei. Ich hoffe, wir werden für alle nützlich sein, die das gleiche Problem haben.

//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

Meine Lösung beinhaltete ein bisschen Javascript. Behalten Sie 100% oder 100 vh auf dem div bei (dies verhindert, dass das div beim ersten Laden der Seite nicht erscheint). Wenn die Seite dann geladen wird, greifen Sie die Fensterhöhe und wenden Sie sie auf das betreffende Element an. Vermeidet den Sprung, da Sie jetzt eine statische Höhe in Ihrem div haben.

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

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

Dies ist die beste (einfachste) Lösung über alles, was ich versucht habe.

... und das hält nicht die native Erfahrung der Adressleiste!

Sie können beispielsweise die Höhe mit CSS auf 100% setzen und dann mit Javascript die Höhe der Fensterhöhe in px auf 0,9 * setzen, wenn das Dokument geladen wird.

Zum Beispiel mit jQuery:

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

)

Leider funktioniert nichts mit reinem CSS: P, aber seien Sie auch vorsichtig, dass vh und vw auf iPhones fehlerhaft sind - verwenden Sie Prozentsätze.

2
user742030

Ich setze mein Breitenelement mit Javascript. Nachdem ich die de vh eingestellt habe.

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

Das funktioniert für mich. Ich benutze kein Jquery-Ect. weil ich möchte, dass es so bald wie möglich geladen wird.

1
Johan Hoeksma

Einfache Antwort, wenn Ihr Hintergrund es zulässt, warum nicht die Hintergrundgröße einstellen: auf etwas, das nur die Gerätebreite mit Medienabfragen abdeckt und neben: after position: fixed; Hack hier .

IE: Hintergrundgröße: 901px; für alle Bildschirme <900px? Nicht perfekt oder reaktionsschnell, aber ich habe auf Mobile <480px einen Zauber erlebt, da ich eine abstrakte BG benutze.

1
EasterMedia

Es hat einige Stunden gedauert, bis Sie alle Details dieses Problems verstanden und die beste Implementierung herausgefunden haben. Ab April 2016 stellt sich heraus, dass nur iOS Chrome dieses Problem hat. Ich habe es mit Android Chrome und iOS Safari ausprobiert - beide waren ohne dieses Update in Ordnung. Das Update für iOS Chrome, das ich verwende, ist:

$(document).ready(function() {
   var screenHeight = $(window).height();
   $('div-with-background-image').css('height', screenHeight + 'px');
});
1
littlequest

Die Lösung, die ich bei einem ähnlichen Problem hatte, bestand darin, die Elementhöhe bei jedem touchmove-Ereignis auf window.innerHeight zu setzen.

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

Dies macht das Element zu jeder Zeit exakt 100% des verfügbaren Bildschirms aus, nicht mehr und nicht weniger. Auch während der Adressleiste verstecken oder anzeigen.

Trotzdem ist es schade, dass wir solche Patches finden müssen, bei denen einfache position: fixed funktionieren sollte.

0
Paul

Ähnlich wie bei @AlexKempton. (konnte mich nicht entschuldigen)

Ich habe lange Übergangsverzögerungen verwendet, um die Größenänderung des Elements zu verhindern.

z.B: 

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

Der Nachteil dabei ist, dass die Größenänderung des Elements auch beim Drehen des Geräts verhindert wird. Sie könnten jedoch JS verwenden, um orientationchange zu erkennen und die Höhe zurückzusetzen, falls dies ein Problem war.

0
Chris Anderson

Ich verwende diese Problemumgehung: Fixiere die Höhe von bg1 beim Laden der Seite durch:

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

Fügen Sie anschließend einen Listener für die Größenänderung von Window hinzu, der Folgendes ausführt: Wenn der Höhenunterschied nach der Größenänderung weniger als 60px ist (etwas mehr als die Höhe der URL-Leiste), dann nichts tun, und wenn er größer als 60px ist, setzen Sie die Höhe von bg1 erneut auf Höhe der Eltern vollständiger Code:

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

PS: Dieser Fehler ist so irritierend!

0
AadityaTaparia

Für diejenigen, die die tatsächliche Innenhöhe und den vertikalen Bildlauf des Fensters hören möchten, während der Chrome-Browser die URL-Leiste von angezeigt auf verborgen und umgekehrt umstellt, besteht die einzige Lösung darin, eine Intervallfunktion festzulegen Messen Sie die Diskrepanz des window.innerHeight mit seinem vorherigen Wert.

Dies führt diesen Code ein:

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

Ich hoffe, dass dies praktisch ist. Kennt jemand eine bessere Lösung?

0