it-swarm.com.ru

CSS3 100vh не постоянный в мобильном браузере

У меня очень странная проблема ... в каждом браузере и мобильной версии я сталкивался с таким поведением:

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

как можно избежать этой проблемы? Когда я впервые услышал о viewport-height, я был взволнован и подумал, что смогу использовать его для блоков фиксированной высоты вместо использования javascript, но теперь я думаю, что единственный способ сделать это - фактически javascript с некоторым событием resize ...

вы можете увидеть проблему по адресу: образец сайта

Кто-нибудь может мне помочь/предложить решение CSS?


простой тестовый код:

/* maybe i can track the issue whe it occours... */
$(function(){
  var resized = -1;
  $(window).resize(function(){
    $('#currenth').val( $('.vhbox').eq(1).height() );
    if (++resized) $('#currenth').css('background:#00c');
  })
  .resize();
})
*{ margin:0; padding:0; }

/*
  this is the box which sould keep constant the height...
  min-height to allow content to be taller than viewport if too much text
*/
.vhbox{
  min-height:100vh;
  position:relative;
}

.vhbox .t{
  display:table;
  position:relative;
  width:100%;
  height:100vh;
}

.vhbox .c{
  height:100%;
  display:table-cell;
  vertical-align:middle;
  text-align:center;
}
<div class="vhbox" style="background-color:#c00">
  <div class="t"><div class="c">
  this div height should be 100% of viewport and keep this height when scrolling page
    <br>
    <!-- this input highlight if resize event is fired -->
    <input type="text" id="currenth">
  </div></div>
</div>

<div class="vhbox" style="background-color:#0c0">
  <div class="t"><div class="c">
  this div height should be 100% of viewport and keep this height when scrolling page
  </div></div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

133
Nereo Costacurta

К сожалению, это намеренно ...

Это хорошо известная проблема (по крайней мере, в Safari Mobile), которая является преднамеренной, поскольку предотвращает другие проблемы. Бенджамин Пулен ответил на ошибку webkit :

Это совершенно намеренно. С нашей стороны потребовалось немало усилий для достижения этого эффекта. :)

Основная проблема заключается в следующем: видимая область динамически изменяется при прокрутке. Если мы соответствующим образом обновим высоту области просмотра CSS, нам нужно обновить макет во время прокрутки. Мало того, что это похоже на , но сделать это при 60 FPS практически невозможно на большинстве страниц (60 FPS - базовая частота кадров на iOS).

Сложно показать вам часть «выглядит как », но представьте, что при прокрутке содержимое перемещается, а то, что вы хотите на экране, постоянно смещается.

Динамическое обновление высоты не работало, у нас было несколько вариантов: отбросить единицы просмотра в iOS, соответствовать размеру документа, как до iOS 8, использовать маленький размер представления, использовать большой размер представления.

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

Николя Хойзи исследовал это совсем немного: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some -mobile-browsers.html

Исправление не запланировано

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

102
nils

Для многих сайтов, которые я создаю, клиент будет запрашивать 100-вольтовый баннер, и, как вы уже нашли, это приводит к плохому «нервному» впечатлению на мобильном телефоне, когда вы начинаете прокручивать. Вот как я решаю проблему для бесперебойного согласованного взаимодействия на всех устройствах:

Сначала я установил свой элемент баннера CSS на height:100vh

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

var viewportHeight = $('.banner').outerHeight();
$('.banner').css({ height: viewportHeight });

Это решает проблему на мобильных устройствах, так как при загрузке страницы элемент баннера устанавливается на 100vh с использованием CSS, а затем jQuery переопределяет это, помещая встроенный CSS в мой элемент баннера, что останавливает его изменение размера, когда пользователь начинает прокручивать.

Однако на рабочем столе, если пользователь изменяет размер своего окна браузера, размер элемента баннера не изменится, потому что теперь он имеет фиксированную высоту, заданную в пикселях из-за вышеупомянутого jQuery. Чтобы решить эту проблему, я использую Mobile Detect , чтобы добавить «мобильный» класс в тело моего документа. А затем я обертываю вышеупомянутый jQuery в оператор if:

if ($('body').hasClass('mobile')) {
  var viewportHeight = $('.banner').outerHeight();
  $('.banner').css({ height: viewportHeight });
}

В результате, если пользователь находится на мобильном устройстве, класс «mobile» присутствует в теле моей страницы, и вышеупомянутый jQuery выполняется. Таким образом, мой баннерный элемент будет применять только встроенный CSS на мобильных устройствах, в то время как на рабочем столе оригинальное правило CSS 100vh остается в силе.

18
user6261119

в моем приложении я делаю это так (TypeScript и вложенный postcss, поэтому измените код соответствующим образом):

const appHeight = () => {
    const doc = document.documentElement
    doc.style.setProperty('--app-height', `${window.innerHeight}px`)
}
window.addEventListener('resize', appHeight)
appHeight()

в вашем css:

:root {
   --app-height: 100%;
}

html,
body {
    padding: 0;
    margin: 0;
    overflow: hidden;
    width: 100vw;
    height: 100vh;

    @media not all and (hover:hover) {
        height: var(--app-height);
    }
}

это работает по крайней мере на Chrome Mobile и Ipad. Что не работает, так это когда вы добавляете свое приложение на домашний экран на iOS и меняете ориентацию несколько раз - каким-то образом уровни масштабирования портятся со значением innerHeight, я могу опубликовать обновление, если найду решение для него.

Демо

11
Andreas Herd

Вы можете попробовать min-height: -webkit-fill-available; в вашем css вместо 100vh. Должно быть решено

5
Saurabh Jain

Я только что обнаружил, что разработанное мной веб-приложение имеет эту проблему с iPhone и iPad, и нашел статью, предлагающую решить его с помощью медиазапросов, предназначенных для определенных устройств Apple.

Я не знаю, могу ли я поделиться кодом из этой статьи здесь, но адрес таков: http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug

Цитирую статью: «просто сопоставьте высоту элемента с высотой устройства, используя медиазапросы, предназначенные для более старых версий iPhone и iPad».

Они добавили всего 6 медиа-запросов, чтобы адаптировать элементы полной высоты, и это должно работать так, как это полностью реализовано в CSS.

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

3
Jahaziel

@nils объяснил это ясно. 

Что дальше?

Я просто вернулся к использованию относительного «классического»% (процент) в CSS.

Зачастую для реализации чего-либо требуется больше, чем для использования vh, но, по крайней мере, у вас есть довольно стабильное решение, которое работает на разных устройствах и в разных браузерах без странных сбоев пользовательского интерфейса.

3
klimat

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

Он устанавливает высоту полноэкранного div на window.innerHeight, а затем обновляет его при изменении размера окна.

2
Mike

Следующий код решил проблему (с помощью jQuery). 

var vhHeight = $("body").height();
var chromeNavbarHeight = vhHeight - window.innerHeight;
$('body').css({ height: window.innerHeight, marginTop: chromeNavbarHeight });

А другие элементы используют % как единое целое для замены vh

2
Ray1422

Поскольку я новичок, я не могу комментировать другие ответы.

Если кто-то ищет ответ, чтобы сделать эту работу (и может использовать javascript - поскольку, как мне кажется, требуется сделать эту работу в данный момент), этот подход сработал довольно хорошо для меня, и он также учитывает изменение ориентации мобильного устройства. Я использую Jquery для примера кода, но должен быть выполним с vanillaJS.

Во-первых, я использую скрипт, чтобы определить, является ли устройство сенсорным или зависшим. Пример с обнаженными костями:

if ("ontouchstart" in document.documentElement) {
    document.body.classList.add('touch-device');

} else {
    document.body.classList.add('hover-device');
}

Это добавляет класс к элементу body в соответствии с типом устройства (указатель мыши или касание), который можно использовать позже для сценария высоты.

-Далее используйте этот код для установки высоты устройства при нагрузке и при изменении ориентации:

if (jQuery('body').hasClass("touch-device")) {
//Loading height on touch-device
    function calcFullHeight() {
        jQuery('.hero-section').css("height", $(window).height());
    }

    (function($) {
        calcFullHeight();

        jQuery(window).on('orientationchange', function() {
            // 500ms timeout for getting the correct height after orientation change
            setTimeout(function() {
                calcFullHeight();
            }, 500);

        });
    })(jQuery);

} else {
    jQuery('.hero-section').css("height", "100vh");


}

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

-100vh на hover-устройствах - это запасной вариант, если браузер переопределяет CSS 100vh.

1
t.j.goodman

Посмотрите на этот ответ: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/

// First we get the viewport height and we multiple it by 1% to get a value for a vh unit
let vh = window.innerHeight * 0.01;
// Then we set the value in the --vh custom property to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`);

// We listen to the resize event
window.addEventListener('resize', () => {
  // We execute the same script as before
  let vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh', `${vh}px`);
});
body {
  background-color: #333;
}

.module {
  height: 100vh; /* Use vh as a fallback for browsers that do not support Custom Properties */
  height: calc(var(--vh, 1vh) * 100);
  margin: 0 auto;
  max-width: 30%;
}

.module__item {
  align-items: center;
  display: flex;
  height: 20%;
  justify-content: center;
}

.module__item:nth-child(odd) {
  background-color: #fff;
  color: #F73859;
}

.module__item:nth-child(even) {
  background-color: #F73859;
  color: #F1D08A;
}
<div class="module">
  <div class="module__item">20%</div>
  <div class="module__item">40%</div>
  <div class="module__item">60%</div>
  <div class="module__item">80%</div>
  <div class="module__item">100%</div>
</div>

1
manuel-84

Следующее работало для меня:

html { height: 100vh; }

body {
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100vw;
}

/* this is the container you want to take the visible viewport  */
/* make sure this is top-level in body */
#your-app-container {
  height: 100%;
}

body примет видимую высоту области просмотра, а #your-app-container с height: 100% заставит этот контейнер принять видимую высоту области просмотра.

1
Rico Kahler

Использование vh на мобильных устройствах не будет работать с 100vh, из-за их выбора дизайна, используя всю высоту устройства, не включая адресные строки и т.д.

Если вы ищете макет, включающий высоты div, пропорциональные истинной высоте просмотра, я использую следующее чистое решение CSS:

:root {
  --devHeight: 86vh; //*This value changes
}

.div{
    height: calc(var(--devHeight)*0.10); //change multiplier to suit required height
}

У вас есть два варианта установки высоты области просмотра, вручную установите --devHeight на высоту, которая работает (но вам нужно будет ввести это значение для каждого типа устройства, для которого вы кодируете)

или же

Используйте javascript, чтобы получить высоту окна, а затем обновите --devheight при загрузке и обновлении области просмотра (однако это требует использования javascript и не является чистым решением css)

Как только вы получите правильную высоту просмотра, вы можете создать несколько элементов div с точным процентом от общей высоты области просмотра, просто изменив множитель в каждом элементе div, которому вы назначаете высоту.

0,10 = 10% высоты обзора 0,57 = 57% высоты обзора

Надеюсь, это может кому-то помочь;)

0
Ray Andison

Вы можете попробовать задать свойства position: fixed; top: 0; bottom: 0; для вашего контейнера.

0
Hasan upinion

Поскольку это не будет исправлено, вы можете сделать что-то вроде:

# html
<body>
  <div class="content">
    <!-- Your stuff here -->
  </div>
</body>

# css
.content {
  height: 80vh;
}

Для меня это было самое быстрое и более чистое решение, чем игра с JavaScript, который не мог работать на многих устройствах и браузерах. 

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

0
turkus

Надеемся, что это будет переменная среды CSS, определенная UA, как предлагается здесь: https://github.com/w3c/csswg-drafts/issues/2630#issuecomment-397536046

0
Malvoz