Фоновое изображение прыгает, когда адресная строка скрывает 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
чтобы узнать, является ли это одним из оскорбительных браузеров. Если это так, выполните следующие действия:
- установите соответствующие высоты на текущую высоту окна просмотра, а не " 100%"
- сохранить текущее горизонтальное значение видового экрана
- затем на
$(window).resize
, только обновите соответствующие значения высоты, если новый горизонтальный размер видового экрана отличается от его начального значения - сохранить новые горизонтальные и вертикальные значения
дополнительно, вы также можете проверить разрешение вертикальных изменений только тогда, когда они выходят за пределы высоты адресной строки (- ов).
О, и адресная строка влияет на $(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
должны работать.