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


288

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

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

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

샘플 사이트 에서 문제점을 볼 수 있습니다.

누구든지 CSS 솔루션을 제안 / 제안 할 수 있습니까?


간단한 테스트 코드 :


1
내가 질문을 잘 이해하면 모바일 브라우저에서 높이가 보이는 높이보다 눈에.니다.
Gaurav Aggarwal

흥미롭고 전에는 눈치 채지 못했습니다. 주로 눈에 띄는 배경 그림입니다. 방법에 대해 당신은 추가 transition: 0.5s정도 덜 갑작스럽게 변화를 만들기 위해?
C14L

@GauravAggarwal nope, exatlyly : 실제 뷰포트 높이는 주소 표시 줄이 표시 될 때 브라우저가 제공 한 높이보다 높습니다 ...
Nereo Costacurta

1
내 질문이 인기를 얻고 있기 때문에 5 센트를주고 싶습니다. 실제 창 높이를 유지하고 메뉴 막대를 위로 밀어 올리는 것이 더 똑똑하지 않습니까? 그렇게 어렵지 않은 것 같습니다. 실제로는 더 쉬워야합니다 ... finger up-> 메뉴 표시 줄이 보이지 않을 때까지 위로 이동, finger down-> 메뉴 표시 줄이 완전히 표시 될 때까지 아래로 이동 ... 모두 다시 조정하거나 튀기지 않는 효과없이 신체와 함께 모두
Nereo Costacurta

4
Google은 이에 대한 유용한 정보를 제공합니다. developers.google.com/web/updates/2016/12/url-bar-resizing 몸 높이를 100 %로 변경 한 경우 100vh 대신 100 %를 사용할 수 있습니다.
Benisburgers

답변:


203

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

이것은 다른 문제를 방지하기 위해 의도적으로 알려진 잘 알려진 문제입니다 (적어도 사파리 모바일에서는). 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이 다음과 같이 변경되었습니다.


7
그렇습니다. 실행 가능한 솔루션 만 스크립팅 된 솔루션입니다. 내가 아는 바로 $(window).height()는이 버그의 영향을받지 않으므로 그렇게하겠습니다. 감사합니다!
Nereo Costacurta

3
스크립트는 나를위한 유일한 방법이며 완벽하게 작동했습니다.
captDaylight

459
가장 우울한 답변.
Winnemucca

15
Chrome 버전 56부터 vh는 항상 URL 표시 줄이 숨겨져있는 것처럼 계산되므로 vh는를 제외하고 스크롤시 증가하지 않습니다 position:fixed. 이것은 Safari에서의 구현과 유사합니다. 자세히 알아보기 : developers.google.com/web/updates/2016/12/url-bar-resizing
Kevin Farrugia

4
초기로드 후에 최신 Chrome이 변경 vh되거나 <html> 100%높이 가 변경되지 않습니다 . URL 막대 숨기기시 레이아웃 스레 싱 / 리플 로우가 두려운 것처럼 보일 수 있으므로 실제로 좋습니다. Firefox그리고 Edge Mobile여전히 동적으로 업데이트 vh<html>배경 이미지 SVGs을 사용하는 경우 특히 나쁜 찢어 많이 유발하고 스크롤 할 때 모든 구성 요소의 크기를 조정, 높이
Drenai

143

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


20
지원되지 않는 min-height: 100vh;대체로 남겨 두겠습니다 -webkit-fill-available.
Tammy Tee

우와, 고마워요!! 이것으로 더 이상 "react-div-100vh"가 필요 없습니다!
Andres Elizondo

1
가장 유용한 답변!
Gauthier

@TammyTee가 맞습니다. min-height: 100vh;그렇지 않으면 Firefox와 같은 브라우저에서 작동하지 않기 때문에 거기 에 보관하는 것이 좋습니다 (적어도 데스크톱에서는 iOS가 브라우저에 상관없이 웹킷을 사용함).
JoniVR

2
이것은 매우 훌륭한 솔루션이지만 iOS 13에서 변경된 것 같습니다. 첫 번째 섹션의 하단에 추가 공간이 표시되지만 iOS 12.x 용 Safari에서 원하는대로 정확하게 작동합니다. codepen.io/RwwL/pen / PowjvPq (포크 한 다음 iOS의 CodePen 디버그 모드에서 확인하여 실제로 무엇을 의미하는지 확인해야 함).
RwwL

27

내 응용 프로그램에서 나는 그렇게합니다 (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 값과 엉망이되어 해결책을 찾으면 업데이트를 게시 할 수 있습니다.

데모


2
이것은 실제로 매우 성가신 문제에 대한 환상적인 접근법입니다.
Michael Giovanni Pumo 11

1
"@media not all and (hover : hover) {"는 모바일 브라우저를 감지하는 방탄 방법이 아니라는 경고를 추가하고 싶습니다. 다른 것을 자유롭게 사용하십시오.
Andreas Herd

나는이 접근법을 많이 좋아합니다. 내가 한 의견은 이벤트 리스너 사용에 관한 것입니다. 이로 인해 페이지가 다시 그려지고 사용자가 올바른 뷰포트 (예 : 홈페이지 초기보기)를 보는 것이 절대적으로 중요 할 때 특정 시나리오에서만 사용합니다
Zach Gollwitzer

22

내가 구축 한 많은 사이트에 대해 클라이언트가 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 규칙이 그대로 유지됩니다.


4
$('.banner').css({ height: window.innerHeight });뷰포트의 "실제"높이 인 대신 사용하도록 조정하겠습니다 . innerHeight 작동 방식의 예
Martin

8
document.querySelector('.banner').style.height = window.innerHeight;실제 JavaScript를 작성하는 사람들을위한 것입니다 .
Fabian von Ellerts

18

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


2
영리한 솔루션, 모바일 장치에서 뷰포트 높이에 문제가 발생했습니다.이 역시 솔루션으로 받아 들여야합니다 (특히 모바일 장치의 경우)
Julio Vedovatto

아주 좋은 해결책. 필자의 경우에는 포니 필을 사용하지 않고 모든 데스크톱 사이트에서 100vh를 사용하고 모바일에서는 var를 사용한다는 논리를 사용합니다 (모바일 세계에는 IE11이 없습니다).
프레이 캄

중첩 된 요소에 대해서만 작동하는 솔루션입니다. 다른 사람이 수백 개의 인스턴스를 교체 해야하는 경우 정규식 (-)? ([\ d.] +) vh와 일치시키고 (calc (var (-vh) *) $ 1 $ 2)
ecc521

10

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

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


3
모든 영웅이 모자를 쓴 것은 아닙니다. 당신은 예를 들어 괜찮습니다. 대단히 감사합니다. 시간을 절약했습니다.
NarayaN

그리고 Vue 애호가를 위해 ... github.com/razumnyak/vue-div-100vh
Tony O'Hagan

6

며칠 동안 해결책을 찾고 있었으므로 VueJS를 Vuetify와 함께 사용하는 모든 사람들을위한 광산입니다 (내 솔루션은 v-app-bar, v-navigation-drawer 및 v-footer를 사용합니다) : App.scss를 만들었습니다 (App에서 사용). vue) 다음 내용이 포함됩니다.

.v-application {
    height: 100vh;
    height: -webkit-fill-available;
}

.v-application--wrap {
    min-height: 100vh !important;
    min-height: -webkit-fill-available !important;
}


1
이것은 잘 작동하며 Vue / Vuetify 세계 외부에서 일반화 될 수 있습니다.
레오

5

나에게 그러한 트릭은 일을했다 :

height: calc(100vh - calc(100vh - 100%))

높이와 다른가 : 100 %?
FF_Dev

예, 100vh는 뷰포트 높이 (장치)의 100 %입니다. 순수한 100 %는 사용 가능한 모든 부모 영역 만 채 웁니다 (부모 블록은 50px 높이를 가질 수 있으며이 부모 높이 만 채울 것입니다). 짧게 말하면
Patryk Janik

4

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

다음은 무엇입니까?

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

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


1
높이 : 배너의 100 %가 여전히 모바일 브라우저에서 점프합니다. 나는 안드로이드에서 그것을 테스트 해 왔으며, 지금까지 Chrome과 Opera Mini는 100 %를 보이는 VP 높이로 제공하며 스크롤시 변경되지 않습니다. Edge와 Firefox는 100 % 높이를 변경하고 뷰를 다시 페인트합니다. Firefox는 특히 나쁘고, 찢어지고, 텍스트가 다시 렌더링되고, 매우 분명하게 다시 레이아웃됩니다
Drenai

1
@Drenai 당신은 이것을 올바르게 구현 하시겠습니까? jsfiddle.net의 작은 예에서 그것을 증명할 수 있습니까?
klimat

네, 확실합니다 :-)
Drenai

3

방금 내가 디자인 한 웹 응용 프로그램이 iPhone 및 iPad 에서이 문제가 있음을 발견했으며 특정 Apple 장치를 대상으로하는 미디어 쿼리를 사용하여 문제를 해결하는 기사를 찾았습니다.

나는 그 기사에서 코드를 공유 할 수 있는지 모르겠지만 주소는 다음과 같습니다 : http://webdesignerwall.com/tutorials/css-fix-for-ios-vh-unit-bug

기사 인용 : "이전 버전의 iPhone 및 iPad 해상도를 대상으로하는 미디어 쿼리를 사용하여 요소 높이를 장치 높이와 일치시키기 만하면됩니다."

전체 높이 요소를 조정하기 위해 6 개의 미디어 쿼리 만 추가했으며 CSS가 완전히 구현되었으므로 작동해야합니다.

수정 보류 중 : 지금 테스트 할 수 없지만 돌아와서 결과를보고합니다.


23
아직도 그 결과를 기다리고 😉
gman

2
약속대로 돌아 오지 않아서 미안 해요 그러나 내가 원했던 것보다 훨씬 오랫동안 HTML과 CSS를 다루고 난 후에, 나는 레이아웃의 디자인을 바꾸고 내 요구에 "좋아"작동하는 방법을 찾았지만 보편적 인 해결책은 아니었다.
Jahaziel

2

내가 새로 왔을 때 다른 답변에 대해서는 언급 할 수 없습니다.

누군가이 작업을 수행 할 수있는 답변을 찾고 있다면 (현재 자바 스크립트를 사용할 수있는 것처럼 보일 수 있습니다)이 접근법은 나에게 매우 효과적이며 모바일 방향 변경도 설명합니다. 예제 코드에는 Jquery를 사용하지만 vanillaJS로 가능해야합니다.

먼저, 스크립트를 사용하여 장치가 터치 또는 호버링되었는지 감지합니다. 베어 본 예제 :

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

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

그러면 나중에 높이 스크립트에 사용할 수있는 장치 유형 (호버 또는 터치)에 따라 본문 요소에 클래스가 추가됩니다.

다음으로이 코드를 사용하여로드 및 방향 변경시 장치 높이를 설정하십시오.

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");


}

-시간 초과는 장치가 방향 변경시 새 높이를 정확하게 계산하도록 설정됩니다. 시간 초과가 없으면 내 경험상 높이가 정확하지 않습니다. 500ms는 지나친 것이지만 나를 위해 일했습니다.

브라우저가 CSS 100vh를 대체하는 경우 호버 디바이스의 -100vh가 대체입니다.


2
Touchstart가 모든 브라우저에서 지원되는 것은 아니며 일부 비 모바일 장치에는 developer.mozilla.org/en-US/docs/Web/Events/touchstart
Drenai가

@Drenai Touchstart는 대부분의 모바일 브라우저에서 지원됩니다. 데스크탑에서는 지원이 약간 적으며 IE, Opera 및 Safari는 지원하지 않습니다. 그러나 원래 질문은 데스크탑이 아닌 모바일을위한 것입니다. 이것이 올바른 대답입니다.
Paul

의견 주셔서 감사합니다! 나는 주로이 전략을 사용하여 일부 모바일 브라우저에서 화면의 재조정 및 점프를 극복했습니다. 브라우저가 터치 스타트를 지원하지 않으면 폴백은 CSS 100vh가됩니다. 100vh가 지원되지 않으면 다른 주제입니다. 데스크탑 장치에 터치 지원이 있으면 높이는 자바 스크립트로 계산됩니다. 그런 다음 100vh가 제공하는 크기 조정에 대한 재 계산이 손실되지만 데스크톱에 방향 변경이 없기 때문에 일반적으로 치명적인 문제는 아닙니다.
tjgoodman

또한 높이 계산을 크기 조정 이벤트에 연결할 수도 있지만 모바일 장치에서 재조정 및 점프 문제와 동일한 정확한 문제가 발생할 수 있습니다. 그러므로 나는이 전술이 실용적이라는 것을 알았다.
tjgoodman

1
@Paul Chrome 및 Firefox 데스크톱 브라우저에 터치 스타트 기능이있는 경우 모바일 브라우저 감지에 사용하는 것이 잘못된 기능입니까? 방금 Windows의 Chrome 및 Firefox에서 테스트했으며 둘
다이

2

다음 코드는 문제를 해결했습니다 (jQuery 사용).

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

그리고 다른 요소들은 %대체 할 단위로 사용 됩니다 vh.


2

여기 내 React 앱에 사용 된 해결 방법이 있습니다.

iPhone 11 Pro 및 iPhone Pro Max-120px

아이폰 8-80px

max-height: calc(100vh - 120px);

타협이지만 비교적 간단한 수정입니다.


1

다음은 나를 위해 일했습니다.

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%해당 컨테이너가 가시 뷰포트의 높이를 가지고 할 것입니다.



0

때문에 고정되지 않습니다, 당신은 뭔가를 할 수 있습니다 :

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

# css
.content {
  height: 80vh;
}

나를 위해 많은 장치와 브라우저에서 작동하지 않는 JavaScript를 사용하는 것보다 가장 빠르고 순수한 솔루션이었습니다.

vh귀하의 요구에 맞는 적절한 가치를 사용 하십시오.


0

주소 표시 줄 등을 포함하지 않는 장치의 전체 높이를 사용하는 디자인 선택으로 인해 모바일 장치에서 vh를 사용하면 100vh에서 작동하지 않습니다.

실제 뷰 높이에 비례하는 div 높이를 포함한 레이아웃을 찾고 있다면 다음과 같은 순수한 CSS 솔루션을 사용합니다.

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

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

뷰포트 높이를 설정하는 두 가지 옵션이 있습니다. --devHeight를 작동 가능한 높이로 수동 설정하십시오 (그러나 코딩하려는 각 유형의 장치에 대해이 값을 입력해야합니다)

또는

자바 스크립트를 사용하여 창 높이를 얻은 다음 뷰 포트로드 및 새로 고침에 대한 --devheight를 업데이트하십시오 (그러나 자바 스크립트를 사용해야하지만 순수한 CSS 솔루션은 아닙니다)

올바른 뷰 높이를 얻으면 높이를 할당하는 각 div에서 승수를 변경하여 총 뷰포트 높이의 정확한 비율로 여러 div를 만들 수 있습니다.

0.10 = 시야 높이의 10 % 0.57 = 시야 높이의 57 %

이것이 누군가를 도울 수 있기를 바랍니다.)


1
좋은 해결책입니다. 이 기사에서 Css-tricks에 대한 자세한 내용을 읽을 수 있습니다 .
Amaury Hanser

0

다음 스크립트와 스타일을 추가하면됩니다.

  function appHeight() {
    const doc = document.documentElement
    doc.style.setProperty('--vh', (window.innerHeight*.01) + 'px');
  }
  window.addEventListener('resize', appHeight);
  appHeight();

스타일

.module {
 height: 100vh; /* Fallback for browsers that do not support Custom Properties */
  height: calc(var(--vh, 1vh) * 100);
}

0

html, body { height: 100% }모바일 장치에서 100vh의 영향을받는 것을 시도하십시오 .


-1

position: fixed; top: 0; bottom: 0;컨테이너에 속성을 부여 할 수 있습니다 .


2
이것이 질문에 대한 답변 인 이유에 대한 추가 정보를 추가하십시오.
감염된 드레 이크
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.