Even though the latest ios safari supports vh units, modernizr is passing negative class "no-cssvhunit".
just for historical sake, latest is 9.0.2, right?
latest is 9.0.2, right?
@patrickkettner 9.2.0.
@patrickkettner, @alrra : I am looking at iPhone 6, version 9.1
The test will fail in iOS 8+ because 100vh is the innerHeight + the bottom interactive bar. What happens is that when the bar disappear, you get a true 100vh. But with the initial bar, the test is justifiably negative.
I managed to detect the bar condition (and height to some extend) in my own custom script, in order to assess when to correct vh units subtracting the bar height. But technically, the current test works as intended by detecting a bug. It's a tough call because it's a design decision on Apple's part. That issue occured on the Firefox OS Phone as well. See this article by Nicolas Hoizey for details on the issue.
Sadly the only way to use vh correctly accross an iOS view is to rely on detection heuristics of that bar.
Thanks @hexalys for mentioning my post about this 100vh not being the real full height on iOS and Firefox OS (at least).
This is really annoying for the development of a full screen app, for example a game like my own https://github.com/nhoizey/esviji
Here is the welcome screen iOS users currently get… :-/
It seems something add been done for iOS8 in #1430, maybe it can be extended for iOS9…
@nhoizey It's quite frankly impossible to adjust the test with a fixed set of code to reflect iOS support. The support varies according to window conditions, and would require to update 'cssvhunit' or 'no-cssvhunit' dynamically. e.g. In portrait, the bar at the bottom is 49px, while it's 44 at the top in landscape.
I do this in my script by reading a combo of a hidden head.height (set at 100%), window.innerheight, screen.availHeight (corrected for the iOS fixed orientation bug), and do a recalc of all conditions at resize, scroll or orientationchange events. But that whole test is too big for the scope of modernizr.
It only works with my entire script. IMO, this bug somewhat has to fall under modernizr "undetectables".
@hexalys it's impossible (I hope) that "the support varies according to window conditions".
Current test works or not according to window conditions, ok, but not support. The browser knows vh or it doesn't.
The test in Modernizr doesn't work. Because browsers (not just Safari on iOS it seems) chose to implement vh in a way that is counterintuitive, not really because Modernizr people made a mistake, I know. But it doesn't work.
I don't know if it is "too big for the scope of Modernizr", or if it has to fall under "undetectables".
I just want to know once if the browser supports the vh unit. Not if 100vh represents the full height of the viewport. These are two different things. The first will stay true or false whatever the portrait or landscape mode, the scroll, etc.
A 49 or 44px difference could be used for vh on iOS. But unless there is an instance with vw support and no vh; I'd instead suggest relying on a vw test as good enough for both (i.e. "knows vh" too.)
Noting also that both vw and vh are buggy when the viewport is zoomed in Safari:
Bug 145614 - Viewport unit values affected by browser zoom
So that test can also fail in case of desktop zoom, or an eventual mobile "sticky zoom''.
You're right, testing vw support should be enough, and it has less issues. I'll do that, thanks.
I still think Modernizr should have a proper vh support test, through… ;-)
@nhoizey You'd have to use my script. :) In the near future... if I ever get to release it. It's a complex piece of work as relative substitute to Modernizr w/font & zoom detection aspect we've talked about before. /aside
NB: I've managed to get around the iOS behavior with a special class for it.
@hexalys what is "iBAR detect"?
It's the identification of the iOS bar being shown, with an iBAR class at the body, all auto handled by JS.
The normal case there being calc(100vh - 42px) (42px being my fixed navigation menu). My CSS style plan for subtracting another 70px when the bottom iOS bar is detected and body.iBAR exists. If not, the iBAR class is removed, falling back to the default calc(100vh - 42px) declaration when vw is supported.
Ok, thanks for clarification.
For anyone interested in this old issue the following is the approach I've taken. (For reference, here is what modernizr does: https://github.com/Modernizr/Modernizr/blob/5eea7e2a213edc9e83a47b6414d0250468d83471/feature-detects/css/vhunit.js )
On the site I'm working on I removed vhunit test from modernizr. Instead I have some JS that tests if a 50vh div is equal to half the window.innerHeight (just like modernizr does). If they are not equal, but 15% of each other, I test if 100vh equalt to what 50vh is. If it is then I consider vh as being supported. Technically this approach isn't perfect since a browser could calculate vh but cacluate it incorrectly. Still, this approach seems to work in every environment I tested and provides me the cssvhunit class I want on mobile devices.
(function(){
var d = document.documentElement;
var elem = document.createElement('div');
elem.style.position = 'absolute';
elem.style.height = '50vh';
d.appendChild(elem);
var height = parseInt(window.innerHeight / 2, 10);
var compStyle = parseInt(window.getComputedStyle(elem, null).getPropertyValue('height'), 10);
var vhSupported = height === compStyle;
if (!vhSupported && compStyle !== undefined && compStyle > 0) {
var howOffIsIt = Math.abs((compStyle - height)/height);
if (howOffIsIt <= 0.15) {
// On mobile comparing vh to window.innerHeight is an issue because the top locaiton bar
// doesn't always display. Because of this we do an additional test.
elem.style.height = '100vh';
var vhFull = parseInt(window.getComputedStyle(elem, null).getPropertyValue('height'), 10);
if (Math.abs(vhFull - (compStyle * 2)) <= 1) {
// (Note we allow for one pixel difference incase there is an odd number of pixels
vhSupported = true;
}
}
}
d.appendChild(elem);
d.className = d.className + (vhSupported ? ' cssvhunit' : ' no-cssvhunit');
})();
Just a thought;
The test sets height: 50vh and then measures that against the computed height / 2, which gives a false result in iOS. Instead of matching against computed height why don't you test for height > 0. Based on the idea that if vh isn't supported the element won't have any height?
Would be great to fix this issue
This test fails on mobile Chrome 74 as well. In my case it was Honor 10 which had "height" equal to 337px and "compStyle" equal to 365px. I guess it was caused by the same issue: 100vh = innerHeight + the browser's address bar
Most helpful comment
Just a thought;
The test sets
height: 50vhand then measures that against the computed height / 2, which gives a false result in iOS. Instead of matching against computed height why don't you test for height > 0. Based on the idea that ifvhisn't supported the element won't have any height?