Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mobile: Status bar scrolls out of view when the soft keyboard is open #50

Open
dfabulich opened this issue Nov 22, 2021 · 6 comments
Open

Comments

@dfabulich
Copy link

Go to https://eblong.com/zarf/glk/glkote/sample-demo.html on iOS. Click the input line to open the keyboard.

Actual: When the keyboard is open, the status bar ("The Kitchen") scrolls out of view.
Expected: The status bar should appear floating at the top of the visual viewport.

@erkyrath
Copy link
Owner

How would you define "status bar" here? A grid window can be any size and any position in the screen rectangle.

@erkyrath
Copy link
Owner

I think my solution for the iOS native app (back when that was supported) was to resize the screen rectangle to "above the keyboard" when the keyboard was open. This gives more or less the right effect, unless the game doesn't fit in that smaller space. Then things get ugly.

I'm afraid I'm not up on what kind of HTML layout shenanigans you need to make this happen on mobile browsers.

@dfabulich
Copy link
Author

I think this would be involved. https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API

@dfabulich
Copy link
Author

dfabulich commented Nov 24, 2021

I did some experimenting with the visual viewport API on iOS today; it didn't go well.

  1. visualViewport.height seemed to be reporting wrong numbers while the keyboard is animating in. I had a reliable repro of it reporting that the height was 394px on an iOS 15.0 iPod Touch 7th gen simulator, and then "later" reporting that it's 250px. glkote already includes a resize debouncer that runs 200ms later, but it would still say that the viewport was 394px. I tried requestAnimationFrame; no help. The only thing that worked was to manually put in a large setTimeout delay.
  2. Even when the numbers stabilized, they were never quite accurate. On an iOS 15.0 iPod Touch 7th gen simulator, with the on-screen keyboard up, the visual viewport is 230 pixels, but visualViewport.height reports that it's 250. (I think that's because of the 20px URL bar at the bottom of the screen…?)
  3. Resizing the buffer window smaller isn't actually very wise while the keyboard is opening, because the scroll position remains at the top of wherever it was originally, and Safari is still happy to scroll the window down while animating the keyboard in. The result of all of this resizing was to scroll the body scrollbar down while leaving the buffer scrollbar inappropriately scrolled up, like this:

Simulator Screen Shot - iPod touch (7th generation) - 2021-11-23 at 22 52 55

I think it's possible that by clever application of debouncing we could scroll the body up and the buffer down to compensate, but we're inherently fighting the platform here.

I think the "right" thing to do as far as the web platform is concerned is to:

  1. Severely limit the allowable windows in "small screen sizes." I'm a newbie to Glk, but I think that means something like: refuse to create more than one buffer window, and allow only grid windows to be children of the root window.
  2. Make grid windows use position: sticky
  3. Dump all buffer "window" contents (and the grid windows themselves) directly into the HTML body, ensuring that the body's scrollbar is the only scrollbar that exists.

@dfabulich
Copy link
Author

After some more experimentation today, I learned that even position: fixed won't work. https://blog.opendigerati.com/the-eccentric-ways-of-ios-safari-with-the-keyboard-b5aa3f34228d

When opening the keyboard, iOS Safari doesn't honor position: fixed / position: sticky.

dfabulich added a commit to dfabulich/glkote that referenced this issue Nov 29, 2021
Fixes erkyrath#50.

When the iOS soft keyboard opens, the "resize" event doesn't fire on the window (the "layout viewport" hasn't changed) but the the "visual viewport" resizes.
https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API
https://developers.google.com/web/updates/2017/09/visual-viewport-api

In this commit, we respond to changes in the size of the visual viewport, moving the top-most grid window down to the top of the visual viewport. Since the vast majority of games have just one grid window at the top of the screen, this does what we want.

I set this code to only slide around the top-most grid window when the game UI sets spacing to 0, because non-zero spacing introduces a visual border around the windows, with the background color coming from the #gameport, but if we slide a grid window down on top of a buffer window, it can't bring its spacing with it. (This is OK by me, because I'm really only doing this for Parchment's sake, which does set spacing 0. Lectrote uses spacing 4, which is fine; it won't be affected by these changes. I tested this code with spacing 4, showing that it has no effect, and with spacing 0, on iOS 15.)

I'd previously experimented with re-measuring the window and using the visual viewport's dimensions for the computation, but we don't actually want to resize the primary buffer window smaller; that will screw up its scroll position, and, worse, it will look really weird to the user.
Furthermore, we can't actually trust visualViewport.height on iOS 15; we can know where the top of the viewport is, but the 20px URL bar may overlay the bottom. See erkyrath#50 for a screenshot of the buggy results.
dfabulich added a commit to dfabulich/glkote that referenced this issue Nov 29, 2021
Fixes erkyrath#50.

When the iOS soft keyboard opens, the "resize" event doesn't fire on the window (the "layout viewport" hasn't changed) but the the "visual viewport" resizes.
https://developer.mozilla.org/en-US/docs/Web/API/Visual_Viewport_API
https://developers.google.com/web/updates/2017/09/visual-viewport-api

In this commit, we respond to changes in the size of the visual viewport, moving the top-most grid window down to the top of the visual viewport. Since the vast majority of games have just one grid window at the top of the screen, this does what we want.

I set this code to only slide around the top-most grid window when the game UI sets spacing to 0, because non-zero spacing introduces a visual border around the windows, with the background color coming from the #gameport, but if we slide a grid window down on top of a buffer window, it can't bring its spacing with it. (This is OK by me, because I'm really only doing this for Parchment's sake, which does set spacing 0. Lectrote uses spacing 4, which is fine; it won't be affected by these changes. I tested this code with spacing 4, showing that it has no effect, and with spacing 0, on iOS 15.)

I'd previously experimented with re-measuring the window and using the visual viewport's dimensions for the computation, but we don't actually want to resize the primary buffer window smaller; that will screw up its scroll position, and, worse, it will look really weird to the user.
Furthermore, we can't actually trust visualViewport.height on iOS 15; we can know where the top of the viewport is, but the 20px URL bar may overlay the bottom. See erkyrath#50 for a screenshot of the buggy results.
@dfabulich
Copy link
Author

I got it, and filed a PR on both branches of glkote.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants