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

Any page scrolls in the mobile browser Chrome. #1917

Closed
erkinsergey opened this issue Apr 11, 2018 · 26 comments

Comments

Projects
None yet
8 participants
@erkinsergey
Copy link

commented Apr 11, 2018

Software version
Quasar: 0.15.12
OS: Linux MInt 18.3 'Sylvia'
Node: v9.8.0
NPM: 5.8.0
Browsers: mobile Chrome 65.0.3325.109
iOS:
Android: 4.4.2

JsFiddle
https://jsfiddle.net/serg12/27oth9n4/

What did you get as the error?
In the mobile version of the Chrome browser, any page, even empty, scrolls to the height of the address bar of the browser. In a mobile browser, Firefox does not. I found that the reason for this are styles from the standard stylesheet quasar.mat.css:
body { ... min-height: 100vh; } .q-layout { width: 100%; min-height: 100vh; }
The min-height: 100vh style is the cause of the scrolling.

What were you expecting?
I want the center of the q-layout component with the header and footer to occupy the entire height of the screen of the mobile device and not scroll in different (popular) mobile browsers. I got the required result by overriding the styles of the min-height components: 100vh; in min-height: auto; and using the class fit.
My code that works correctly:
< style type="text/css">
body {
padding: 0;
margin: 0; }
html, body {
height: 100%;
width: 100vw;
}
body {
min-height: auto !important;
}
< /style>
< body >
< div id="q-app" class="fit">
< q-layout view="lhh lpr lff" class="fit bg-secondary" style="min-height:auto !important">
< q-layout-header class="q-pa-sm bg-white"> some header < /q-layout-header>
< q-page-container class="bg-light fit">
< q-page class="q-pa-sm fit" style="min-height:auto !important;">
< div class="fit absolute-full bg-secondary"> main content < /div>
< /q-page>
< /q-page-container>
< q-layout-footer class="bg-white q-pa-sm"> footer content < /q-layout-footer>
< /q-layout>
< /div>
< /body>

What steps did you take, to get the error?
Create any, you can even empty the page with standard styles from quasar.mat.css and open it in the mobile browser Chrome (under Android).

@nothingismagick

This comment has been minimized.

Copy link
Member

commented Apr 11, 2018

Thanks for reporting this!

@pdanpdan

This comment has been minimized.

Copy link
Collaborator

commented Apr 12, 2018

Are you talking about the feature of chrome where it hides the address bar?

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Apr 12, 2018

No, not at all. I'm talking about that every page in mobile Chrome, even empty, scrolls to the height of the address bar of the browser. In mobile Firefox, a blank page does not scroll and takes up all the remaining space. I just want the page to always adjust in height and not scroll.

@pdanpdan

This comment has been minimized.

Copy link
Collaborator

commented Apr 12, 2018

Have you tested you're solution on a page with more content (with scroll) - you'll get interesting side effects both on mobile and desktop?
And I'm not very sure this will fix the size when the soft keyboard is shown.
I'll do some tests also with the way Chrome evaluates the screen height.

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Apr 12, 2018

I'm doing a mapping application with a header and footer, which will be used even on mobile devices. In desktop browsers (Chromuim, Firefox), in adaptive and normal modes and mobile Firefox, everything works correctly. But in a mobile Chrome, the map scrolls to the height of the address line. In previous versions of the framework (0.12, 0.13), which I used at the beginning everything was fine and there was no such effect. The effect occurred after the update and, as I found out, is associated with the min-height: 100vh styles.
I do not know if this is a flaw in the framework, or maybe I'm doing something wrong.

@rstoenescu rstoenescu changed the title Any page scrolls in the mobile browser Chrome. [ios] Any page scrolls in the mobile browser Chrome. Jul 20, 2018

@rstoenescu rstoenescu changed the title [ios] Any page scrolls in the mobile browser Chrome. Any page scrolls in the mobile browser Chrome. Jul 20, 2018

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jul 20, 2018

@rstoenescu Sorry I didn't know this was a duplicate.
2 small comments:

  1. it's also on mobile Safari. (in fact it's worse on mobile Safari than mobile Chrome iOS)
  2. it's easily fixed by swapping out any location where it uses 100vh by window.innerHeight after all Vue components are rendered.

I want to suggest a small polyfill that can be turned on optionally in quasar.conf that swaps out the 100vh css for window.innerHeight.

If you want I can help with this, do a PR.

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Jul 20, 2018

Thanks for the answer.
Yes, a polyfill or at least an example of code would be very good!

@slowaways

This comment has been minimized.

Copy link
Contributor

commented Jul 27, 2018

What's the status of this Issue?

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jul 28, 2018

You can manually swap any 100vh with window.innerHeight on mounted().

@rstoenescu

This comment has been minimized.

Copy link
Member

commented Jul 28, 2018

@mesqueeb You requested style-fn Function prop for QPage, remember? https://quasar-framework.org/components/layout-page.html#Style-fn

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jul 28, 2018

@rstoenescu yes exactly. But even with a tweak this would still use 100vh. (I mean on the body & #q-app) And it’s only recently I found out that 100vh on mobile Safari is really bad (hides a big chunk underneath the tool bar). You can open any Quasar app that has content stretched until the bottom (like a keypad) on mobile safari and you'll see it looks really bad.

So it’s unfortunately not curable through that style fn function, but instead all 100vh’s in the quasar framework would need to be changed with something else.

I believe that for this reason (even though it’s just a mobile Safari problem) quasar should consider to not use 100vh at all. This would be most beneficial for most users.

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Jul 30, 2018

I updated the framework to version 0.17.05 and used the style-fn property for default project with header, drawer and Quasar logo image.
My desired result - the lack of scrolling in the mobile Chrome I managed to achieve only in the following way:
<html class="fit">
...
<body class="fit" style="min-height: auto !important;">
<div id="q-app" class="fit" style="height:100%;"></div>
...
<q-layout view="lHh Lpr lFf" class="fit" style="min-height:auto !important">
...
<q-page class="flex flex-center fit" :style-fn="myTweak">

export default {
name: "PageIndex",
methods: {
myTweak (offset) {
// any value other than
return { minHeight: '100vh' }
// for example:
//return { minHeight: 'auto !important' }
// return { minHeight: 'calc(100vh - ${offset}px)' }
}
}
}

That is, it should not return a function style-fn { minHeight: '100vh' } and can even be empty.
As I understand it, the style-fn property applies only to q-page and does not affect the parent containers.

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2018

@erkinsergey
Do you not use any header or footer?
I believe when you return { minHeight: '100vh' } you'll have a too high page because the height of the header and footer will be added extra.

What I am doing is return { minHeight: '${window.innerHeight - offset}px' } and this solves all problems in all mobile browsers as far as my tests go.

Does this work for you?

PS: when writing code blocks on Github issues it's better to write three back dashes on top and below the code → ```

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Aug 1, 2018

Thank you for three back dashes, I did not know. 👍
I tried the example. Unfortunately this does not work as I should.
I do not know how to explain ...
Method:

myTweak (offset) {
    return { minHeight: `${window.innerHeight - offset}px` }
}

affects the container main:

<main class="q-layout-page flex flex-center" style="min-height: 536px;"><img alt="Quasar logo" src="img/quasar-logo-full.svg"></main>

it really works.
But this does not affect body, for which:

body {
...   
 min-height: 100vh;
...

from qusar.mat.styl

Again, to get the desired effect, I need to override the min-height: 100vh styles for all the parent containers.

Perhaps, to place an example on the test hosting that it was more comprehensible?

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Aug 1, 2018

Yes exactly I need that too. For now my work around is the complete guide I wrote two posts below. ↓

@florentpeyrard

This comment has been minimized.

Copy link

commented Nov 7, 2018

Hi,

@erkinsergey's workaround is still necessary with Quasar v0.17.17 (at least on mobile Chrome), thanks for sharing. Non-scrolling is necessary to get a native look-and-feel, hoping the workaround is going to be integrated soon in Quasar.

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jan 8, 2019

Guide to app window height on mobile browsers

My guide to successfully integrate the correct window height (at all times in any browser and on mobile)

The culprit

CSS property vh is the culprit, as on mobile browsers this gives unexpected results.

The saviour

We will need to use JavaScript's window.innerHeight or window.outerHeight which is much more reliable, as it does not count in any status bars / toolbars.

Luckily we have Quasar framework and we do not need to research what is the best way to calculate the window height, we can just use the built in Window Resize Observable to get the window height.

Also an added bonus is that Window Resize Observable is reactive, which is very important to make sure users can still resize the browser window.

Save correct sizes

We can use Quasar's Window Resize Observable to make sure we always have the correct window sizes. Add it to your App.vue file like so:

<template>
  <div id="q-app">
    <q-window-resize-observable @resize="onResize" />
  </div>
</template>
<script>
export default {
  name: 'App',
  methods:
  {
    onResize (size) {
      $store.state.windowSize = size
    },
  }
}
</script>

Identify all occurrences of 100vh

If we search the Quasar repo for "100vh" we have about 9 occurrences of 100vh we'll need to deal with.

Replace occurrences of 100vh

The most important ones are:

body
  min-height 100vh
// and
.q-layout
  min-height 100vh

First reset them by adding global css rules:

body, .q-layout
  min-height initial

Now we can modify these to use our own calculated min-height.
Any time you use <q-layout> just add:

<q-layout
  :style="{min-height: $store.state.windowSize.height + 'px'}"
>

This way it will be the correct height.

Then our final step is to change the behaviour of Q-Page as this also sets min-height but can be changed via a function called "style-fn" (which I had added).

Any time you use <q-page> just add:

<q-page style-fn="myTweak">
// and in script
<script>
export default {
  methods: {
    myTweak (offset) {
      if (!offset) offset = 0
      return {
        minHeight: this.$store.state.windowSize.height - offset + 'px'
      }
    },
  }
}
</script>

Please do not forget to review all other occurrences of 100vh in the Quasar framework, and check if your app works OK on mobile Safari / mobile Chrome etc.

Important for Cordova iOS

If you use the WKWebView plugin for iOS cordova then the calculation of the window height as retrieved by Quasar's Window Resize Observable will not be correct. However only in this case, 100vh is parsed correctly again.

You can adapt the above solution to work even with iOS cordova by changing myTweak to:

    myTweak (offset) {
      if (!offset) offset = 0
      const minHeight = ($q.platform.is.cordova)
        ? `calc(100vh - ${offset}px)`
        : this.$store.state.windowSize.height - offset + 'px'
      return { minHeight }
    },

Bonus:

In cases you want a page to be full height by default, instead of "min-height" just add the same logic to the "height" property in the same places!

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Jan 10, 2019

Thanks for the instructions!
But not

onResize (size) 
{
   $store.state.windowSize = size
},

but

// mutations.js
export function setWindowSize (state, newWindowSize) {
  state.windowSize = newWindowSize;
}
// App.vue
onResize (size)
{
  $store.commit('store_name/setWindowSize', size);
},

for reactivity and dynamic change.
Otherwise, everything really works!

P.S. How do you highlight syntax?

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2019

We will need to revisit this issue after Quasar version 1 has come out. I will need to either propose an official solution or make a PR with this guide in the docs.

For now I'll wait for Quasar v1 later this or next month.

@erkinsergey it works for me directly editing the state. without a mutation. Reason being, I don't want my mutation history to be cluttered with the same mutation a million times. : D

Also, maybe it's better to add a debounce to the onResize, but I'm not sure.

Syntax you can highlight by writing js or html behind the three ```

like this: ```js

close with: ```

@erkinsergey

This comment has been minimized.

Copy link
Author

commented Jan 10, 2019

You are right, many mutations are a bad idea, but direct editing, as in your example, did not update the content dynamically. Only when loading the page.
Thanks, did not know about syntax.

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jan 10, 2019

Maybe because you had no initial value set for store.state.windowSize
Try adding that prop to your initial state. That should make it reactive.

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jan 11, 2019

Updated the guide above for Cordova iOS when the plugin WKWebView is used!
Added the new chapter called "Important for Cordova iOS"

@jeancaffou

This comment has been minimized.

Copy link

commented Feb 16, 2019

Any solution for this on V1 ?
QWindowResizeObservable is not present on V1

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Mar 31, 2019

@jeancaffou I have updated my solution to work for V1.
Please look here:
#3757 (comment)

Might be made even simpler when offset is corrected in the future.

@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented May 3, 2019

In my workaround for V1 I made a mistake, I now corrected it:

I wrote:

.q-page
  min-height initial !important

But it requires this to work properly:

.q-page
  min-height inherit !important
@mesqueeb

This comment has been minimized.

Copy link
Contributor

commented Jun 3, 2019

iOS cordova still has problems where the page height is not calculated properly in the QPage and QLayouts.

The previous problem I had found:

  • a dynamic/conditional header/footer might be rendered after QLayout calculates the height

Another problem I have found:

  • iOS cordova has automatic hiding of the splashscreen, which in my case caused the height of the header/footer to be calculated incorrectly by quasar.

So for anyone using iOS cordova. You'll have to manually hide the splashscreen and add a short delay to the calculation of your header and footer after your layout mounts.

I have described the detailed solution in this post.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.