33

I'm experiencing something strange in iOS 12.3.1 Safari. This issue dates back to at least iOS 12.2, but I imagine it's been a problem for much longer than that.

The issue manifests itself when trying to align an element to the bottom axis of the viewport, and is a problem in both portrait and landscape mode.

In order to reproduce the problem, the element must have a position of fixed or absolute, yet it doesn't matter whether you position the element with top and transform or bottom.

Portrait Mode

The issue only manifests itself in portrait mode if Safari is displaying its condensed URL bar, which replaces the normal URL and menu bars, and there is no vertical overflow.

Normal URL and Menu Bars // Condensed URL Bar

enter image description here enter image description here

Notably, the condensed menu bar is only ever displayed when there is either vertical overflow and the browser is scrolled downwards or when the browser's orientation has been changed from portrait to landscape and then back again (despite whether or not there is vertical overflow).

Changing Orientation with Vertical Overflow // Without Overflow

enter image description here enter image description here

I'm not sure exactly what's happening here.

Landscape Mode

The issue with landscape mode always and only occurs when the normal navigation bar is displayed at the top of the page. The navigation bar is only ever hidden in landscape mode due to downward scrolling or orientation change from portrait to landscape.

With Vertical Overflow

enter image description here enter image description here

Without Vertical Overflow

enter image description here enter image description here

What's interesting is that the height of the navigation bar in landscape mode clearly offsets the viewport so that position of bottom: 0 or top: 100% is pushed outside of the viewport when the navigation bar is being displayed.

Crappy "Workaround" for Portrait Mode

It's a super hack-ish workaround, and a crappy workaround at that, but it's the only thing so far that causes position: fixed; bottom: 0; to actually position an element at the bottom of the viewport after switching orientations if there is no overflow.

<div style='height: 0'>
  <!-- the quantity of <br> elements must create vertical overflow -->
  <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
  <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
  <!-- this does not work without the space character -->
  &nbsp;
</div>

However, I just noticed that it creates an invisible vertical overflow and thus unnecessary vertical scrolling in at least Safari and Chrome. I'm also worried that it might cause other issues on other devices in other browser that I'm unable to test.


It absolutely sucks that a website has to sometimes look like crap for the sake of user-experience due to this bug.

Does anybody out there have any idea what is happening?

Anybody aware of any workarounds?

Anybody aware of an actual solution?

Community
  • 1
  • 1
oldboy
  • 5,729
  • 6
  • 38
  • 86
  • Check if https://stackoverflow.com/a/52936930/5623035 helps and let me know. – Mojtaba Hosseini Jun 21 '19 at 19:25
  • @MojtabaHosseini the issue seems very similar, but it's ultimately a different issue, although they could very likely be related to one another. the browser itself in those images is or looks different than the Safari browser that my phone uses on my device in 12.3.1 too. – oldboy Jun 21 '19 at 19:53
  • Images are related to `SFSafariViewController` embedded inside the app, not Safari itself. I recommend you to try solutions there and see if it helps but not promise. – Mojtaba Hosseini Jun 21 '19 at 19:57
  • @MojtabaHosseini my issue has no relation to images or the `` element at all – oldboy Jun 21 '19 at 21:38

1 Answers1

16

Hello this question kind of got me at first and I thought back to my days poking around in HTML and CSS for hours on end trying to get things right. Alas all those hours of misery have been for this moment.

vh used to be calculated by the current viewport of your browser. If you loaded a site in your browser, 1vh would be the same as 1% of your screen height, and then minus the browser interface.

But! If you wanted to scroll, it gets tricky. Once you brush past the browser interface (in this case your address bar), you would have a weird jump in your content because the vh would be updated.

Safari for iOS was actually was one of the first to implement a fix. They set a fixed vh value based on the max screen height. Then the user wouldn't experience the jump in content, but .... yup, there's always a but...

Having the fixed value is awesome, except when you wanna have a full sized element, or an element with fixed position at the bottom of the screen because then it would get cropped out!

That is your problem....and say goodbye to it, because...

This is your solution!!

css:

.my-element {
  height: 100vh; /* This is for browsers that don't support custom properties */
  height: calc(var(--vh, 1vh) * 100);
}

js:

// Get the viewport height and multiply it by 1% to get a value for a vh unit
let vh = window.innerHeight * 0.01;
// Then set the custom --vh value to the root of the document
document.documentElement.style.setProperty('--vh', `${vh}px`);

Now you can use --vh as your height value like we would any other vh unit, multiply it by 100 and you have the full height we want.

One thing left, the js up there runs, but we never update the element's size when the viewport changes, so that wouldn't work yet, you need a listener...

more js:

// We listen to the resize event
window.addEventListener('resize', () => {
  // Update the element's size
  let vh = window.innerHeight * 0.01;
  document.documentElement.style.setProperty('--vh', `${vh}px`);
});

Cheers!

danronmoon
  • 3,814
  • 5
  • 34
  • 56
jose reyes
  • 1,533
  • 1
  • 13
  • 17
  • i know i can do what i wanna do with JS, but i was hoping for an answer that wasnt JS, which is why i didnt tag JS. aside from that, why do u have two values in `var(--vh, 1vh)`?? – oldboy Jun 19 '19 at 20:38
  • 2
    Oh man, im sorry. The truth is it cannot be done in html alone because of it's dynamic nature. There is too much going on here with updating the viewport height. You would need the ability to set variables and be able to constantly update them as the viewport height is effected by the browser address bar. Also the var works like this: "var(custom value, fallback value)" you could add as many as you want. Example: var(custom value, fallback1, fallback2, fallback3, etc.) – jose reyes Jun 20 '19 at 13:31
  • 1
    `var(--vh, 1vh)` the 1vh is called the fallback or the default value that will get used if you don't specify the value of the custom property or you set it to initial (related: https://stackoverflow.com/a/55615712/8620333 / https://stackoverflow.com/a/53239881/8620333 ) – Temani Afif Jun 20 '19 at 15:49
  • yup that's exactly right as I explained above. This is correct. – jose reyes Jun 20 '19 at 15:52
  • 1
    @jreyes ah didnt know u could set fallbacks. anyways, theres multiple issues even with your JS approach for landscape in Safari; if u scroll up it creates an empty space below the element about the same size as the URL bar. it also has many issues in Chrome on iOS. and thats just on the browsers ive been able to test. – oldboy Jun 20 '19 at 22:44
  • hmm. Not sure about the issues, I tested the code and no problems showed up, that's why I posted it. Sorry it didn't work out :/ – jose reyes Jun 21 '19 at 10:30
  • 1
    it creates issues on an iPhone 6 iOS 12.3.1, and i dont imagine iOS Safari is any different on newer devices? how extensively did you test it? because it only took me a few seconds to break it while testing? ill take some screenshots of the issues it causes and send them to you if youd like? unless you address these issues, unfortunately ill be forced to downvote your answer. – oldboy Jun 21 '19 at 19:45
  • hmm, can you send the screenshots over please? I'd like to have a look at what is going on... Yea I tested on apple's xcode simulator. https://developer.apple.com/library/archive/documentation/IDEs/Conceptual/iOS_Simulator_Guide/GettingStartedwithiOSSimulator/GettingStartedwithiOSSimulator.html – jose reyes Jun 23 '19 at 21:38
  • 2
    ive messed around with it to try and reproduce the issues again, but i was only able to reproduce one of them. [heres a screenshot.](https://i.postimg.cc/pLs03qJW/IMG-0401.png). it seems the `resize` event is being triggered if you swipe down to display the URL bar, thus it recalculates `var(--vh)` as 1% of `innerHeight` minus the URL bar height. if one then swipes up to scroll down the page while the URL bar is still displayed, it leaves a gap of space and scrolls the page even though theres nothing to scroll. i hope that makes sense? – oldboy Jun 24 '19 at 02:48
  • 1
    aside from that, what i dont like about this approach is not only do i have to constantly monitor the size of the viewport, but i also have to constantly monitor whether or not the content is greater than `calc(var(--vh) * 100)`, since once the height of the content exceeds that given height the whole layout of course breaks. – oldboy Jun 24 '19 at 02:50
  • The issue makes sense, but I am not sure why that's happening. Also the method should be something similar regardless right? A viewport has elements that can either be there or not (the browser address bar), then it has the content. It seems simple enough to detect a change and then adjust the content accordingly, but then when those changes revert, how do we deal with the content? That is the question yes? Therefore a detection system, dynamic in nature, theoretically, should work. Hope someone figures it out, ill keep an eye on this post. Cheers! – jose reyes Jun 24 '19 at 11:04
  • I do not belive this is possible wiht only HTML and CSS, but I could certainly be wrong. I hope there is so I can see how it works ofcourse, but I just do not know if it is possible. – jose reyes Jun 24 '19 at 11:07
  • 1
    that bug is just super strange considering the URL bar is first treated as if its in the document flow, but then as soon as you scroll, even if the URL bar remains expanded, the URL bar is seemingly removed from the document flow all of a sudden. – oldboy Jun 24 '19 at 20:27
  • 1
    p.s. tag me in your responses, otherwise i dont get notified. im lucky i manually checked back – oldboy Jun 24 '19 at 20:27
  • @BugWhisperer Wow that tag is useful, and yea I know what you mean. I am not sure how to fix it. I will make a few changes when I have time. – jose reyes Jun 25 '19 at 11:07
  • what tag? like tagging a persons username? also, u dont need to tag somebody if u are commenting on their answer/question e.g. i dont need to tag u when im responding to/commenting on ur answer – oldboy Jun 25 '19 at 22:29
  • Oh gotcha, so only if its an answer not a comment. That makes sense. – jose reyes Jun 27 '19 at 16:24
  • @jreyes the only time u shouldnt be tagging a user is if ur responding to him/her specifically on their specific question/answer, otherwise u should always be tagging somebody if u want them to be notified. for instance, i was never notified of your last comment because youre commenting on your own answer and didnt tag me – oldboy Jul 25 '19 at 18:56
  • @TemaniAfif hey Temani im in a huge bind, can u take a look at [this question of mine](https://stackoverflow.com/q/57237867/7543162) – oldboy Jul 28 '19 at 05:05
  • 1
    @jreyes I have implemented your solution into this pen so other can live test. I'll share with you https://codepen.io/Breaker222/pen/dxZLVM – Breaker222 Aug 05 '19 at 18:22
  • yay! @Breaker222 – jose reyes Aug 06 '19 at 17:27
  • guess i had never voted your response up. now you get a thumbs up :) – oldboy Oct 15 '19 at 09:27
  • 2
    Unfortunately... innerHeight is also unreliable on safari. It is going to completely break up when you open the key board. And the resize event is unreliable too, it is not always fired. Dawn many bugs. – Jerry Dec 12 '19 at 04:18
  • surprised i didnt mark this as the answer at the time. just earned a gold badge from this question being viewed 10k times! thanks again for imparting your knowledge on the community <3 – oldboy Nov 11 '20 at 09:24
  • can you verify whether or not this still works? – oldboy Dec 27 '20 at 09:49
  • The problem is that it doesn't animate accordingly with the Safari bottom bar, so it makes an ugly jump after the bottom bar disappears – Fred K Oct 25 '21 at 10:53
  • 1
    @oldboy just tested on iPhone 13 mini. it doesn't work for me. when scrolling down to the bottom, the safari bar jumps and for a short while, it looks okay. When I release the scroll, it goes back to cutting off elements at the bottom – eruina Apr 03 '23 at 02:03