CSS3 100vh not constant in mobile browser
Unfortunately this is intentional…
This is a well know issue (at least in safari mobile), which is intentional, as it prevents other problems. Benjamin Poulain replied to a webkit bug:
This is completely intentional. It took quite a bit of work on our part to achieve this effect. :)
The base problem is this: the visible area changes dynamically as you scroll. If we update the CSS viewport height accordingly, we need to update the layout during the scroll. Not only that looks like shit, but doing that at 60 FPS is practically impossible in most pages (60 FPS is the baseline framerate on iOS).
It is hard to show you the “looks like shit” part, but imagine as you scroll, the contents moves and what you want on screen is continuously shifting.
Dynamically updating the height was not working, we had a few choices: drop viewport units on iOS, match the document size like before iOS 8, use the small view size, use the large view size.
From the data we had, using the larger view size was the best compromise. Most website using viewport units were looking great most of the time.
Nicolas Hoizey has researched this quite a bit: https://nicolas-hoizey.com/2015/02/viewport-height-is-taller-than-the-visible-part-of-the-document-in-some-mobile-browsers.html
No fix planned
At this point, there is not much you can do except refrain from using viewport height on mobile devices. Chrome changed to this as well in 2016:
- https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/BK0oHURgmJ4
- https://developers.google.com/web/updates/2016/12/url-bar-resizing
CSS 100vh is too tall on mobile due to browser UI
Usually the 100vh
height will account for the adjusted height, with is why you'll sometimes see mobile pages go funky when the browser's address bar slides down.
For browsers that don't account for the sliding bar within the vh
unit: The height for the address bars will not be constant across the browsers, so I'd advise against appending -50px
.
Try setting the height of the page (using javascript) with the window.innerheight
property.
function resetHeight(){
// reset the body height to that of the inner browser
document.body.style.height = window.innerHeight + "px";
}
// reset the height whenever the window's resized
window.addEventListener("resize", resetHeight);
// called to initially set the height.
resetHeight();
Infamous height:100% issue on chrome for android - address bar
I was able to solve this issue by
Creating a css variable (variables.scss)
:root {
--viewport-height: 100%;
}
Instead of using 100%
use var(--viewport-height)
height: calc(100% - 55px);
becomes
height: calc(var(--viewport-height) - 55px);
Then binding to the visualViewport.resize
event (MUST use addEventListener
here)
if (!serverSide) {
visualViewport.addEventListener('resize', () => {
document.documentElement.style.setProperty('--viewport-height', `${visualViewport.height}px`);
});
}
Make sure there is no transition set for the height property.
CSS variables are supported by all major browsers.
- VisualViewport docs
- Linked-from-docs Demo with source code
- Commit reference
Setting height to 100vh works but i get a scroll bar in mobile browsers
EDIT: New solution
html, body {
overflow: hidden;
height: 100%;
}
.centered_layout{
position: fixed;
inset: 0;
overflow: auto;
display: grid;
place-items: center;
}
<div class="centered_layout">
Centered app
</div>
Calculating Viewport Height on Chrome Android with CSS
Here's what I went with:
HTML
<div id="selector"></div>
CSS
#selector {
height: 100vh;
}
JQUERY
function calcVH() {
$('#selector').innerHeight( $(this).innerHeight() );
}
(function($) {
calcVH();
$(window).on('orientationchange', function() {
calcVH();
});
})(jQuery);
PURE JS (NO JQUERY)
function calcVH() {
var vH = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
document.getElementById("selector").setAttribute("style", "height:" + vH + "px;");
}
calcVH();
window.addEventListener('onorientationchange', calcVH, true);
Simply change #selector
to whatever your css selector is. If you use the pure js version you need to use an ID unless you change .getElementByID
to .getElementsByClassName
.
I'm only aware of this being a problem in Mobile Chrome Android, but I'm guessing it's the same for Chrome iOS as well. You could easily add a mobile detect option if you wanted so this only runs when you need it to. Personally I use Detectizr which works well, but to be honest, since it's pretty lightweight as it is, adding something like this is probably not worth it unless you're already using it.
Hopefully this gets fixed soon so a javascript solution isn't necessary. Also, I tried adding the resize event in case the browser width resizes, but after seeing this question I removed it from my answer. If you want to try using those just change the above to:
JQUERY
function calcVH() {
$('#selector').innerHeight( $(this).innerHeight() );
}
(function($) {
calcVH();
$(window).on('orientationchange resize', function() {
calcVH();
});
})(jQuery);
$(window).on('resize orientationchange', function() {
PURE JS (NO JQUERY)
function calcVH() {
var vH = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
document.getElementById("selector").setAttribute("style", "height:" + vH + "px;");
}
calcVH();
window.addEventListener('onorientationchange', calcVH, true);
window.addEventListener('resize', calcVH, true);
Get Android Chrome Browser Address bar height in JS
Best approach for me was to have something like that:
$(document).ready(function(){
var viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var viewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var isPortrait = viewportHeight > viewportWidth;
$( window ).resize(onresize);
function onresize() {
var newViewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
var newViewportWidth = Math.max(document.documentElement.clientWidth, window.innerWidth || 0);
var hasOrientationChanged = (newViewportHeight > newViewportWidth) != isPortrait;
var addressbarHeight = 130;
if (!hasOrientationChanged && (newViewportHeight != viewportHeight)) {
addressbarHeight = Math.abs(newViewportHeight - viewportHeight);
if (newViewportHeight < viewportHeight) {
// Android Chrome address bar has appeared
} else {
// Android Chrome address bar has disappeared
}
} else if(hasOrientationChanged) {
// Orientation change
}
viewportHeight = newViewportHeight;
viewportWidth = newViewportWidth;
isPortrait = viewportHeight > viewportWidth;
}
});
Related Topics
Floated Elements of Variable Height Push Siblings Down
Playing M3U8 Files With HTML Video Tag
Html:How to Make a Curve Like This Using HTML & CSS Using Border or Box
How to Make a Gap Between Two Div Within the Same Column
Html Select Only One Checkbox in a Group
Print Header/Footer on All Pages (Print Mode)
How to Make Flex Box Work in Safari
How to Hide Link Information At the Bottom Left/Right of the Browser on Hover
How to Remove Unwanted Space in This Table
Change Background Color of Iframe Issue
Css Margin Terror; Margin Adds Space Outside Parent Element
How to Make a Div Not Larger Than Its Contents
Css Technique For a Horizontal Line With Words in the Middle
How to Write A:Hover in Inline Css