html google - Imagem de plano de fundo salta quando a barra de endereços oculta iOS / Android / Mobile Chrome




search iphone (17)

Atualmente estou desenvolvendo um site responsivo usando o Twitter Bootstrap.

O site tem uma imagem de fundo em tela cheia no celular / tablet / desktop. Essas imagens giram e desaparecem em cada uma, usando dois divs.

É quase perfeito, exceto um problema. Usando o iOS Safari, o Navegador Android ou o Chrome no Android, o plano de fundo salta um pouco quando um usuário rola a página e faz com que a barra de endereço se esconda.

O site está aqui: http://lt2.daveclarke.me/

Visite-o em um dispositivo móvel e role para baixo e você deverá ver a imagem redimensionar / mover.

O código que estou usando para o plano de fundo DIV é o seguinte:

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

Todas as sugestões bem-vindas - isto tem feito a minha cabeça por um tempo !!


Answers

Descobri que a resposta de Jason não estava funcionando bem para mim e eu ainda estava dando um salto. O Javascript garantiu que não havia nenhuma lacuna na parte superior da página, mas o fundo ainda estava pulando sempre que a barra de endereços desaparecia / reaparecia. Então, assim como a correção de JavaScript, apliquei a transition: height 999999s para o div. Isso cria uma transição com duração tão longa que praticamente congela o elemento.


Demorou algumas horas para entender todos os detalhes desse problema e descobrir a melhor implementação. Acontece que a partir de abril de 2016 apenas o iOS Chrome tem esse problema. Eu tentei no Android Chrome e iOS Safari-, ambos estavam bem sem essa correção. Portanto, a correção para o iOS Chrome que estou usando é:

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

Eu defino meu elemento width, com javascript. Depois de definir o 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");

Isso funciona para mim. Eu não uso jquery ect. porque eu quero que seja carregado assim que possível.


Esta é a melhor solução (mais simples) acima de tudo que eu tentei.

... E isso não mantém a experiência nativa da barra de endereços !

Você pode definir a altura com CSS como 100%, por exemplo, e depois definir a altura como 0.9 * da altura da janela em px com o javascript, quando o documento é carregado.

Por exemplo, com jQuery:

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

)

Infelizmente não há nada que funcione com CSS puro: P mas também seja minfull que vh e vw são buggy em iPhones - use porcentagens.


Eu tenho um problema semelhante em um cabeçalho do nosso site.

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

Isso terminará em uma experiência de rolagem nervosa no Chrome Chrome, porque o contêiner .header será redimensionado depois que a barra de url se esconder e o dedo for removido da tela.

Solução CSS:

Adicionar as duas linhas a seguir evitará que a barra de URL oculte e a rolagem vertical ainda seja possível:

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

Resposta simples se o plano de fundo permitir, por que não definir o tamanho do plano de fundo: para algo que cubra apenas a largura do dispositivo com as consultas de mídia e use junto com: após a posição: fixo; hackear here .

IE: tamanho do plano de fundo: 901px; para qualquer tela <900px? Não é perfeito ou responsivo, mas trabalhou um charme para mim no celular <480px, já que estou usando um BG abstrato.


Estou usando essa solução alternativa: corrija a altura da bg1 no carregamento da página por:

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

Em seguida, anexe um ouvinte de eventos de redimensionamento à Janela que faz isso: se a diferença de altura após o redimensionamento for menor que 60px (nada mais que a altura da barra de url), não faça nada e, se for maior que 60px, ajuste a altura de bg1 novamente para a altura do pai! código completo:

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: Esse bug é tão irritante!


Esse problema é causado pelas barras de URL encolhendo / deslizando para fora do caminho e alterando o tamanho dos # bg1 e # bg2 divs, pois são 100% de altura e "fixos". Como a imagem de fundo está definida como "cover", ela ajustará o tamanho / posição da imagem à medida que a área de contenção for maior.

Com base na natureza responsiva do site, o plano de fundo deve ser dimensionado. Eu entretenho duas soluções possíveis:

1) Defina a altura # bg1, # bg2 para 100vh. Em teoria, esta é uma solução elegante. No entanto, o iOS tem um bug vh ( http://thatemil.com/blog/2013/06/13/viewport-relative-unit-strangeness-in-ios-6/ ). Eu tentei usar um max-height para evitar o problema, mas permaneceu.

2) O tamanho da viewport, quando determinado por Javascript, não é afetado pela barra de URL. Portanto, o Javascript pode ser usado para definir uma altura estática no # bg1 e # bg2 com base no tamanho do viewport. Esta não é a melhor solução, pois não é CSS puro e há um pequeno salto de imagem no carregamento da página. No entanto, é a única solução viável que vejo considerando os bugs "vh" do iOS (que não parecem estar corrigidos no iOS 7).

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

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

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

Em uma nota lateral, vi muitos problemas com essas barras de URL de redimensionamento no iOS e no Android. Eu entendo o propósito, mas eles realmente precisam pensar sobre a estranha funcionalidade e o caos que eles trazem para os sites. A última alteração é que você não pode mais "ocultar" a barra de URLs no carregamento da página no iOS ou no Chrome usando truques de rolagem.

EDIT: Embora o script acima funcione perfeitamente para manter o plano de fundo de redimensionamento, ele causa uma lacuna visível quando os usuários rolam para baixo. Isso ocorre porque mantém o plano de fundo dimensionado para 100% da altura da tela menos a barra de URL. Se adicionarmos 60px à altura, como sugere swiss, esse problema desaparece. Isso significa que não conseguimos ver os 60px inferiores da imagem de fundo quando a barra de URL está presente, mas isso impede que os usuários vejam uma lacuna.

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

O problema pode ser resolvido com uma consulta de mídia e um pouco de matemática. Aqui está uma solução para uma orientação 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%);
}

Como vh mudará quando a barra de url desaparecer, você precisará determinar a altura de outra forma. Felizmente, a largura da viewport é constante e os dispositivos móveis vêm em apenas algumas proporções diferentes; Se você puder determinar a largura e a relação de aspecto, um pouco de matemática lhe dará a altura da viewport exatamente como vh deve funcionar. Aqui está o processo

1) Crie uma série de consultas de mídia para as proporções que você deseja segmentar.

  • use proporção de aspecto de dispositivo em vez de proporção de aspecto porque o último será redimensionado quando a barra de URL desaparecer

  • Eu adicionei 'max' à proporção de aspecto do dispositivo para segmentar quaisquer proporções de aspecto que se seguem entre as mais populares. Eles não serão tão precisos, mas serão apenas para uma minoria de usuários e ainda estarão bem perto do vh apropriado.

  • lembre-se da consulta de mídia usando horizontal / vertical, então para portait você precisará inverter os números

2) para cada consulta de mídia, multiplique a porcentagem de altura vertical desejada no elemento vw pelo reverso da proporção.

  • Como você sabe a largura e a proporção entre a largura e a altura, basta multiplicar a% desejada (100% no seu caso) pela proporção de altura / largura.

3) Você tem que determinar a altura da barra de url e, em seguida, menos que a partir da altura. Não encontrei medições exatas, mas uso 9% para dispositivos móveis na paisagem e isso parece funcionar bastante bem.

Esta não é uma solução muito elegante, mas as outras opções também não são muito boas, considerando que são:

  • Tendo seu site parecido com bugs para o usuário,

  • ter elementos de tamanho incorreto ou

  • Usando javascript para algum estilo básico ,

A desvantagem é que alguns dispositivos podem ter diferentes alturas ou proporções de barras de url do que os mais populares. No entanto, usando esse método, se apenas um pequeno número de dispositivos sofrer a adição / subtração de alguns pixels, isso parece muito melhor para mim do que todos os que têm um site redimensionado ao passar.

Para facilitar, também criei um 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%);
  }
}

Todas as respostas aqui estão usando a altura da window , que é afetada pela barra de URL. Todo mundo esqueceu a altura da screen ?

Aqui está minha solução 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);
  }
});

A adição da parte .css() está mudando o elemento de posição absoluta inevitavelmente alinhado pela parte superior para alinhado na parte inferior, de modo que não há nenhum salto. Embora, eu suponha que não há razão para não adicionar isso diretamente ao CSS normal.

Precisamos do sniffer do agente do usuário, porque a altura da tela nos desktops não seria útil.

Além disso, tudo isso pressupõe que o #background seja um elemento de posição fixa que preenche a janela.

Para os puristas JavaScript (aviso - não testado):

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

EDIT: Desculpe que isso não responde diretamente ao seu problema específico com mais de um plano de fundo. Mas este é um dos primeiros resultados ao procurar por este problema de fundos fixos pulando no celular.


Semelhante à resposta do @AlexKempton. (não poderia comentar desculpe)

Eu tenho usado longos atrasos de transição para evitar o redimensionamento de elementos.

por exemplo:

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

A desvantagem disso é que evita o redimensionamento do elemento, inclusive na rotação do dispositivo; no entanto, você poderia usar algum JS para detectar o change de orientationchange e redefinir a altura se isso fosse um problema.


Eu criei uma solução JavaScript para usar unidades VH. Usando VH praticamente em qualquer lugar é afetado por barras de endereços minimizando em pergaminho. Para consertar o jank que mostra quando a página redesenha, eu tenho esse js aqui que vai pegar todos os seus elementos usando unidades VH (se você der a classe .vh-fix ), e dar a elas alturas de pixel embutidas. Essencialmente congelando-os na altura que queremos. Você pode fazer isso em rotação ou na alteração do tamanho da viewport para permanecer responsivo.

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

Isso resolveu todos os meus casos de uso, espero que ajude.


Eu me deparei com esse problema também quando eu estava tentando criar uma tela de entrada que cobrisse a viewport inteira. Infelizmente, a resposta aceita não funciona mais.

1) Os elementos com a altura definida como 100vh são redimensionados sempre que o tamanho da viewport é alterado, incluindo os casos em que isso é causado por (dis) barra de URL.

2) $(window).height() retorna valores também afetados pelo tamanho da barra de URL.

Uma solução é "congelar" o elemento usando transition: height 999999s como sugerido na resposta de AlexKempton . A desvantagem é que isso efetivamente desativa a adaptação a todas as mudanças no tamanho da viewport, incluindo aquelas causadas pela rotação da tela.

Então, minha solução é gerenciar as alterações da viewport manualmente usando JavaScript. Isso me permite ignorar as pequenas alterações que provavelmente são causadas pela barra de URL e reagem apenas às grandes.

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

EDIT: Eu realmente uso essa técnica juntamente com height: 100vh . A página é renderizada corretamente desde o início e, em seguida, o javascript entra em ação e começa a gerenciar a altura manualmente. Desta forma, não há cintilação enquanto a página está carregando (ou mesmo depois).


Eu encontrei uma solução muito fácil sem o uso de Javascript:

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

Tudo isso faz atrasar o movimento de modo que seja incrivelmente lento e não seja perceptível.


A solução que estou usando atualmente é verificar o userAgent em $(document).ready para ver se é um dos navegadores ofensivos. Se for, siga estas etapas:

  1. Defina as alturas relevantes para a altura da janela de visualização atual em vez de '100%'
  2. Armazene o valor horizontal da viewport atual
  3. Então, em $(window).resize , atualize apenas os valores de altura relevantes se a nova dimensão de viewport horizontal for diferente do seu valor inicial
  4. Armazene os novos valores horizontais e verticais

Opcionalmente, você também pode testar permitir redimensionamentos verticais somente quando eles estiverem além da altura da (s) barra (s) de endereço.

Ah, e a barra de endereços afeta $(window).height . Consulte: Barra de endereços do navegador Webkit móvel (cromo) altera $ (window) .height (); fazendo tamanho de fundo: cobrir a escala toda vez JS "Janela" largura-altura vs "tela" largura-altura?


esta é a minha solução para resolver esse problema, eu adicionei comentários diretamente no código. Eu testei essa solução e funciona bem. Espero que possamos ser úteis para todos terem o mesmo problema.

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





android html ios css twitter-bootstrap-3