CSS3 100vh не константа в мобильном браузере



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




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

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

  • все макет перекрасить и заново настроить, так как размеры имеют изменилось

  • плохой нервный эффект для пользовательского опыта


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



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



может кто-нибудь помочь мне с / предложить 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>
724   8  

8 ответов:

к сожалению, это умышленное...

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

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

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

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

динамическое обновление высоты не работало, у нас было несколько вариантов: drop viewport устройства на 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

исправление не планируется

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

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

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

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

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

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

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

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

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

в моем приложении я делаю это так (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, я могу опубликовать обновление, если найду решение для него.

демо

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

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

выход из статьи: "просто сопоставьте высоту элемента с высотой устройства, используя медиа-запросы, которые нацелены более старые версии разрешения iPhone и iPad."

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

Edit pending: я не могу проверить его прямо сейчас, но я вернусь и сообщу о своих результатах.

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

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

@Нильс объяснил это четко.

что дальше?

Я просто вернулся, чтобы использовать относительную "классику"% (процент) в CSS.

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

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

Если кто - то ищет ответ, чтобы сделать эту работу (и может использовать 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");


}

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

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

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

Comments

    Ничего не найдено.