IT story

모바일 브라우저에서 CSS3 100vh가 일정하지 않음

hot-time 2020. 5. 13. 08:04
반응형

모바일 브라우저에서 CSS3 100vh가 일정하지 않음


매우 이상한 문제가 있습니다 ... 모든 브라우저 및 모바일 버전 에서이 동작이 발생했습니다.

  • 페이지 스크롤을 시작할 때 위로 이동하는 페이지를로드하면 (예 : 주소 표시 줄 표시) 모든 브라우저에 최상위 메뉴가 있습니다.
  • 100vh는 때때로 뷰포트의 보이는 부분에서만 계산되므로 브라우저 막대가 100vh 위로 올라가면 픽셀 단위로 증가합니다
  • 치수가 변경되었으므로 모든 레이아웃을 다시 페인트하고 다시 조정
  • 사용자 경험에 좋지 않은 영향

이 문제를 어떻게 피할 수 있습니까? 내가 viewport-height에 대해 처음 들었을 때 나는 흥분했고 자바 스크립트를 사용하는 대신 고정 높이 블록에 사용할 수 있다고 생각했지만 이제는 resize 이벤트가있는 실제로 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 should 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>


불행히도 이것은 의도적 인 것입니다…

이것은 다른 문제를 방지하기 위해 의도적으로 알려진 잘 알려진 문제입니다 (적어도 사파리 모바일에서는). Benjamin Poulain이 웹킷 버그에 답했습니다 .

이것은 완전히 의도적입니다. 이 효과를 달성하기 위해서는 상당한 노력이 필요했습니다. :)

기본 문제는 이것입니다. 스크롤 할 때 보이는 영역이 동적으로 변경됩니다. CSS 뷰포트 높이를 적절히 업데이트하면 스크롤하는 동안 레이아웃을 업데이트해야합니다. 그것은 똥처럼 보일뿐만 아니라 60 FPS에서 그렇게하는 것은 대부분의 페이지에서 실제로 불가능합니다 (60 FPS는 iOS의 기본 프레임 속도입니다).

"똥 모양"부분을 보여주기는 어렵지만 스크롤 할 때 내용이 이동하고 화면에서 원하는 내용이 계속 바뀌고 있다고 상상해보십시오.

동적으로 높이를 업데이트하지 않으면 몇 가지 선택 사항이 있습니다 .iOS에서 뷰포트 단위를 삭제하고, iOS 8 이전과 같은 문서 크기를 일치시키고, 작은 뷰 크기를 사용하고, 큰 뷰 크기를 사용하십시오.

우리가 가진 데이터에서 더 큰 뷰 크기를 사용하는 것이 가장 타협했습니다. 뷰포트 단위를 사용하는 대부분의 웹 사이트는 대부분 멋지게 보였습니다.

Nicolas Hoizey는 이것을 꽤 연구했습니다 : https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile -browsers.html

수정 계획 없음

이 시점에서 모바일 장치에서 뷰포트 높이를 사용하지 않는 것 외에는 할 수있는 일이 많지 않습니다. 2016 년에도 Chrome이 다음과 같이 변경되었습니다.


min-height: -webkit-fill-available;대신 CSS를 사용해보십시오 100vh. 해결되어야한다


내가 구축 한 많은 사이트에 대해 클라이언트가 100vh 배너를 요청하고 찾은 것처럼 스크롤을 시작할 때 모바일에서 "점프"경험이 나빠집니다. 이것이 모든 장치에서 일관되고 일관된 경험을 위해 문제를 해결하는 방법입니다.

먼저 배너 요소 CSS를 height:100vh

그런 다음 jQuery를 사용하여 배너 요소의 높이를 픽셀 단위로 가져 오고이 높이를 사용하여 인라인 스타일을 적용합니다.

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

이렇게하면 페이지가로드 될 때 CSS를 사용하여 배너 요소가 100vh로 설정된 다음 모바일 요소의 문제가 해결됩니다 .jQuery는 배너 요소에 인라인 CSS를 배치하여 사용자가 스크롤하기 시작할 때 크기 조정을 중지하여이를 무시합니다.

그러나 데스크톱에서 사용자가 브라우저 창 크기를 조정하면 위의 jQuery로 인해 배너 요소의 높이가 고정되어 있기 때문에 배너 요소의 크기가 조정되지 않습니다. 이를 해결하기 위해 Mobile Detect사용 하여 문서 본문에 'mobile'클래스를 추가합니다. 그런 다음 위의 jQuery를 if 문으로 묶습니다.

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

결과적으로 사용자가 모바일 장치에 있으면 'mobile'클래스가 내 페이지 본문에 있으며 위의 jQuery가 실행됩니다. 따라서 내 배너 요소는 모바일 장치에 적용된 인라인 CSS 만 가져 오는 반면 데스크톱에서는 원래 100vh CSS 규칙이 그대로 유지됩니다.


내 응용 프로그램에서 나는 그렇게합니다 (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);
    }
}

그것은 적어도 크롬 모바일과 아이 패드에서 작동합니다. 작동하지 않는 것은 iOS의 홈 화면에 앱을 추가하고 방향을 몇 번 변경하면 확대 / 축소 수준이 innerHeight 값과 엉망이되어 해결책을 찾으면 업데이트를 게시 할 수 있습니다.

데모


React 구성 요소를 생각해 냈습니다. React 를 사용 하는지 확인 하거나 그렇지 않은 경우 소스 코드를 탐색 하여 환경에 맞게 조정할 수 있습니다.

전체 화면 div의 높이를 설정 한 window.innerHeight다음 창 크기 조정시 업데이트합니다.


이것은 당신이 필요로하는 트릭입니다 https://css-tricks.com/the-trick-to-viewport-units-on-mobile/ .

CSS

.my-element {
    height: 100vh;                      /* Fallback for browsers that do not support Custom Properties */
    height: calc(var(--vh, 1vh) * 100);
    transition: 1s;                     /* To avoid a jumpy result */
}

JS

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

이 답변을보십시오 : 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>


@nils가 명확하게 설명했습니다.

다음은 무엇입니까?

CSS에서 상대적인 '클래식' %(백분율) 을 사용하기 위해 돌아 왔습니다 .

종종 사용하는 것보다 무언가를 구현하는 것이 더 많은 노력 vh이지만 적어도 이상한 UI 결함없이 다른 장치와 브라우저에서 작동하는 매우 안정적인 솔루션이 있습니다.


I just found a web app i designed has this issue with iPhones and iPads, and found an article suggesting to solve it using media queries targeted at specific Apple devices.

I don't know whether I can share the code from that article here, but the address is this: http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug

Quoting the article: "just match the element height with the device height using media queries that targets the older versions of iPhone and iPad resolution."

They added just 6 media queries to adapt full height elements, and it should work as it is fully CSS implemented.

Edit pending: I'm unable to test it right now, but I will come back and report my results.


The following code solved the problem (with jQuery).

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

And the other elements use % as a unit to replace vh.


As I am new, I can't comment on other answers.

If someone is looking for an answer to make this work (and can use javascript - as it seems to be required to make this work at the moment) this approach has worked pretty well for me and it accounts for mobile orientation change as well. I use Jquery for the example code but should be doable with vanillaJS.

-First, I use a script to detect if the device is touch or hover. Bare-bones example:

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

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

This adds class to the body element according to the device type (hover or touch) that can be used later for the height script.

-Next use this code to set height of the device on load and on orientation change:

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 is set so that the device would calculate the new height correctly on orientation change. If there is no timeout, in my experience the height will not be correct. 500ms might be an overdo but has worked for me.

-100vh on hover-devices is a fallback if the browser overrides the CSS 100vh.


The following worked for me:

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

The body will take the visible viewport height and #your-app-container with height: 100% will make that container take the visible viewport height.


Hopefully, this will be a UA-defined CSS environment variable as suggested here: https://github.com/w3c/csswg-drafts/issues/2630#issuecomment-397536046


Because it won't be fixed, you can do something like:

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

# css
.content {
  height: 80vh;
}

For me it was the fastest and more pure solution than playing with the JavaScript which could not work on many devices and browsers.

Just use proper value of vh which fits your needs.


Using vh on mobile devices is not going to work with 100vh, due to their design choices using the entire height of the device not including any address bars etc.

If you are looking for a layout including div heights proportionate to the true view height I use the following pure css solution:

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

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

You have two options for setting the viewport height, manually set the --devHeight to a height that works (but you will need to enter this value for each type of device you are coding for)

or

Use javascript to get the window height and then update --devheight on loading and refreshing the viewport (however this does require using javascript and is not a pure css solution)

Once you obtain your correct view height you can create multiple divs at an exact percentage of total viewport height by simply changing the multiplier in each div you assign the height to.

0.10 = 10% of view height 0.57 = 57% of view height

Hope this might help someone ;)


You can try giving position: fixed; top: 0; bottom: 0; properties to your container.

참고URL : https://stackoverflow.com/questions/37112218/css3-100vh-not-constant-in-mobile-browser

반응형