Фоновое изображение прыгает, когда адресная строка скрывает iOS / Android/Mobile Chrome

в настоящее время я разрабатываю отзывчивый сайт с помощью Twitter Bootstrap.

сайт имеет полноэкранное фоновое изображение на мобильном / планшете / рабочем столе. Эти изображения вращаются и исчезают через каждый, используя два divs.

Это почти идеально, за исключением одного вопроса. С помощью iOS Safari, Android Browser или Chrome на Android фон слегка подскакивает, когда пользователь прокручивает страницу и заставляет адресную строку скрываться.

сайт здесь: 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;
}

все предложения приветствуются - это делает мою голову в течение некоторого времени!!

18 ответов


эта проблема вызвана тем, что бары URL сжимаются / сползают с пути и изменяют размер дивов #bg1 и #bg2, поскольку они имеют высоту 100% и "фиксированы". Поскольку фоновый рисунок устанавливается "крышка" регулировка размера изображения/положение, содержащее просторнее.

основываясь на отзывчивом характере сайта, фон должен масштабироваться. У меня есть два возможных решения:--3-->

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, и есть небольшой скачок изображения при загрузке страницы. Однако это единственное жизнеспособное решение, которое я вижу, учитывая ошибки "vh" iOS (которые, похоже, не исправлены в iOS 7).

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

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

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

на стороне Примечания, я видел так много проблем с этими изменение размера URL-баров в iOS и Android. Я понимаю цель, но им действительно нужно продумать странную функциональность и хаос, которые они приносят на веб-сайты. Последнее изменение - вы больше не можете "скрывать" строку URL при загрузке страницы в iOS или Chrome с помощью прокрутки трюки.

EDIT: хотя приведенный выше скрипт отлично работает для сохранения фона от изменения размера,он вызывает заметный пробел при прокрутке вниз. Это связано с тем, что он сохраняет размер фона до 100% высоты экрана за вычетом строки URL. Если мы добавим 60px к высоте, как предлагает swiss, эта проблема исчезнет. Это означает, что мы не видим нижнюю 60px фонового изображения, когда присутствует строка URL, но это мешает пользователям когда-либо видеть пробел.

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

Я обнаружил, что ответ Джейсона не совсем работает для меня, и я все еще получаю прыжок. Javascript гарантировал отсутствие разрыва в верхней части страницы, но фон все еще прыгал, когда адресная строка исчезала/появлялась. Так же, как исправление Javascript, я применил transition: height 999999s в div. Это создает переход с длительностью так долго, что он практически замораживает элемент.


у меня есть аналогичная проблема в заголовке нашего сайта.

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

это закончится нервным прокруткой на android chrome, потому что .заголовок-контейнер будет масштабироваться после того, как url-бар скрывается и палец удаляется с экрана.

CSS-решение:

добавление следующих двух строк предотвратит скрытие url-строки и вертикальную прокрутку:

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 исчезнет

  • я добавил " max " к соотношению сторон устройства, чтобы настроить любые соотношения сторон, которые следуют между самыми популярными. Они не будут такими точными, но они будут только для меньшинства пользователей и все равно будут довольно близко к правильному ВХ.

  • помните медиа-запрос, используя горизонтальный / вертикальный, поэтому для portait вам нужно перевернуть числа

2)для каждого медиа-запроса умножьте любой процент вертикальной высоты, который вы хотите, чтобы элемент был в vw, на обратную пропорцию.

  • поскольку вы знаете ширину и отношение ширины к высоте, вы просто умножаете%, которое хотите (100% в вашем случае) на отношение высота/ширина.

3) Вы должны определить высоту строки url, а затем минус это от высоты. Я не нашел точных измерений, но я использую 9% для мобильных устройств в ландшафте, и это, похоже, работает довольно хорошо.

это не очень элегантное решение, но другие варианты тоже не очень хороши, учитывая, что они:

  • наличие вашего сайта кажется пользователю багги,

  • имея неправильно размер элементов, или

  • использование javascript для некоторых basic стайлинг,

недостатком является то, что некоторые устройства могут иметь разные высоты или соотношения сторон url-адресов, чем самые популярные. Однако, используя этот метод, если только небольшое количество устройств страдает добавлением / вычитанием нескольких пикселей, это кажется мне намного лучше, чем у всех, кто имеет размер веб-сайта при прокрутке.

чтобы сделать это проще, я также создал Сасс миксин:

@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() часть меняет неизбежно выровненный сверху абсолютный позиционированный элемент на выровненный снизу, поэтому нет никакого прыжка вообще. Хотя, я полагаю, нет причин не добавлять это непосредственно к обычному 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;
}

EDIT: Извините, что это напрямую не отвечает на вашу конкретную проблему с более чем одним фоном. Но это один из первых результатов при поиске этой проблемы фиксированных фонов, прыгающих на мобильных устройствах.


я столкнулся с этой проблемой, когда пытался создать входной экран, который охватывал бы весь видовой экран. К сожалению, принятый ответ больше не работает.

1) элементы с высотой установлено 100vh получить изменение размера каждый раз, когда размер окна просмотра изменяется, в том числе в тех случаях, когда это вызвано (dis)появляется URL-бар.

2) $(window).height() возвращает значения, также зависящие от размера строки URL.

одно решение - "заморозить" элемент используя transition: height 999999s как полагают в ответ 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);

EDIT: я действительно использую эту технику вместе с height: 100vh. Страница отображается правильно с самого начала, а затем javascript запускается и начинает управлять высотой вручную. Таким образом вообще нет мерцания во время загрузки страницы (или даже позже).


решение, которое я сейчас использую, - это проверить userAgent on $(document).ready чтобы узнать, является ли это одним из оскорбительных браузеров. Если это так, выполните следующие действия:

  1. установите соответствующие высоты на текущую высоту окна просмотра, а не " 100%"
  2. сохранить текущее горизонтальное значение видового экрана
  3. затем на $(window).resize, только обновите соответствующие значения высоты, если новый горизонтальный размер видового экрана отличается от его начального значения
  4. сохранить новые горизонтальные и вертикальные значения

дополнительно, вы также можете проверить разрешение вертикальных изменений только тогда, когда они выходят за пределы высоты адресной строки (- ов).

О, и адресная строка влияет на $(window).height. См.: мобильный браузер Webkit (chrome) адресная строка изменения $(окно).высота (); создание фона-размер: обложка масштабируется каждый раз JS" окно "ширина-высота vs" экран " ширина-высота?


Я нашел очень простое решение без использования 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);

Я создал ванильное javascript-решение для использования VH-единиц. Использование VH практически в любом месте осуществляется путем минимизации адресных баров при прокрутке. Чтобы исправить jank, который показывает, когда страница перерисовывается, у меня есть этот js, который захватит все ваши элементы, используя VH-единицы (если вы дадите им класс .vh-fix), и дайте им встроенные высоты пикселей. По сути, заморозить их на нужной высоте. Вы можете сделать это при вращении или изменении размера окна просмотра, чтобы остаться отзывчивый.

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

это решило все мои случаи использования, надеюсь, это поможет.


Это мое решение для решения этой проблемы, я добавил комментарии непосредственно к коду. Я протестировал это решение и отлично работает. Надеюсь, мы будем полезны, потому что у всех одна и та же проблема.

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

Это лучшее решение (самое простое) выше всего, что я пробовал.

...И это не сохраняет родной опыт адресной строки!

вы можете установить высоту с CSS до 100%, например, а затем установить высоту до 0,9 * высоты окна в px с javascript, когда документ загружен.

например с jQuery:

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

)

к сожалению нет ничего это работает с чистым CSS: P, но также быть minfull, что vh и vw глючат на айфонах - используйте проценты.


Я установил свой элемент width с помощью javascript. После того, как я установил 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. потому что я хочу, чтобы загрузить как можно скорее.


потребовалось несколько часов, чтобы понять все детали этой проблемы и выяснить лучшую реализацию. Оказывается, по состоянию на апрель 2016 только iOS Chrome имеет эту проблему. Я пробовал на Android Chrome и iOS Safari - оба были в порядке без этого исправления. Таким образом, исправление для iOS Chrome я использую:

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

Я использую этот способ: Исправить высоту 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;
    }
}

PS: эта ошибка так раздражает!


похоже на ответ @AlexKempton. (не смог прокомментировать извините)

Я использую длинные задержки перехода, чтобы предотвратить изменение размера элемента.

например:

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

компромисс с этим-это предотвращает изменение размера элемента, в том числе на вращающемся устройстве, однако вы можете использовать некоторые JS для обнаружения orientationchange и сбросить высоту, если это было проблемой.


для тех, кто хотел бы слушать фактическую внутреннюю высоту и вертикальную прокрутку окна, в то время как браузер Chrome mobile-это переход строки 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);

Я надеюсь, что это будет удобно. Кто-нибудь знает лучше решение?


решение, которое я придумал, когда подобная проблема заключалась в том, чтобы установить высоту элемента в window.innerHeight каждый раз touchmove событие было запущено.

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 должны работать.