As you could imagine, I'm trying to make my webpage responsive and mobile friendly.
I have an outer container on which I set the width dynamically using this hook (window.innerWidth). So to test if the page is responsive I open up Chrome-devtools and start making the devtools wider:
Sure it's a little jumpy but it scales correctly, as expected. The problem starts when I open up to do the same in the responsive tools:
Suddenly the whole page scales down? Also, it's hard to see but I'm logging window.innerWidth
and it's not changing as I'm changing the width.
So I try it out on my cell-phone and the the behaviour is really unexpected:
On load it looks ok
Flip the phone, still as expected, but when I flip it back???
This crazy effect happens, I mean now it looks like window.innerHeight is having some trouble as well? Because the container with the gray background color has it's min-height set to window.innerHeight. And if i try going to some other page of the app and then back I get this:
It's a zoomed in version of the last image. I can pinche-zoom out from it.
So I google around and it looks like I find someone with the same problem there's a detailed answer suggesting I should use window.visualViewport.width
instead. So I try it out:
Main differences, the resizing seem's a little jumpier. I'm also logging window.visualViewport.width
and it is changing, but only slightly and it's not corresponding to the responsive-width that's shown above the screen.
But most importantly, it's unfortunately not fixing the problem of weirdly resizing the entire screen, and the unexpected behaviour on mobile remains. (should be mentioned that this one too, works as expected if I'm not in "responsive mode" and just resize the window.
So I spot another answer further down suggesting to use window.screen.width
instead, so I try it out:
Which introduced a whole new type of wonkyness? It seems to scale correctly, but down at around a few pixels above 300 it starts to just cut-off a piece of the header while making the container (which should be the width of the screen) smaller at a faster rate than the screen?
This seem to be related to the fact that the header has the css:
grid-template-columns: 130px auto 130px;
. If I lower the 130px
-value, the point at which the header gets cut off lowers as well. I suppose making the screen go below the headers min-width causes some (in my opinion) really unexpected behaviour.
Though the console log (now logging window.screen.width
, now correctly prints the width reported by chromes responsive tool. The bug can be seen in my phone as well
I guess my phone must be a few pixels below 300 in width. Interesting fact is that using 100vw
displays exactly the same behaviour as using screen.width
.
It's also interesting to look at the difference between screen.width
, innerWidth
and visualViewport.width
. If I set the size of the responsive window to 500px and reload the window. All of them evaluates to 500px. If I set the screen to any value below the threshold where screen.width
starts to cut off a piece of the screen.
screen.width
evaluates to the width of the responsive window.
innerWidth
and visualViewport.width
will both evaluate to 309px (which I assume is the minimum functional width of the header.
If we look at how innerWidth
and visualViewport.width
looks on my phone:
On both visualViewport.width
and innerWidth
we can see a much smaller but similar line to the one on screen.width
(here it can be seen on a zoomed in screenshot).
First solution
So the first and most straight forward solution would be to use window.screen.width
(or 100vw
) and simply make sure that no element ever push themselves outside the width of the screen.
But wait, another solution has appeared!
By looking at a comment to an answer of the previous question I see that someone solved it by changing the the viewport meta-tag from
<meta name="viewport" content="width=device-width, initial-scale=1" />
to
<meta name="viewport" content="width=device-width, minimum-scale=1" />
All alternatives, screen.width
, innerWidth
and visualViewport.width
all now behave identically to each other and as desired:
They all log the correct width of the responsive window, the page on my mobile also works. If you look closely you can see that the header does get cut off a little when the screen goes below the 309-threshold. But with this solution it seems like the page breaks a lot more gracefully than in first solution.
So if you've already solved the problem, why are you posting this question?
Well, as you might have understood by now, I love this problem more than I love the solution. That is, I would really like to know WHY this solution works? So even though my "practical" problem is solved I'm really curious as to a few remaining mysteries:
- Why does resizing the window (first video) behave differently from resizing the "responsive box" in chrome dev tools?
- Why does the bug appear on my mobile when I tilt my phone, and then tilt it back again? (third picture)
- Why, when I (on the phone) go into some page and back again, is the screen super zoomed in? (fourth picture)
- Why does
innerWidth
andvisualViewport.width
continue to print the same value when resizing the responsive window. - Why do they weirdly scale down the whole screen instead of changing the size of the screen in the expected way (are they for some reason zooming out when making the responsive window smaller? Is that why setting
minimum-scale=1
solves the issue?) - Why does
screen.width
behave differently frominnerWidth
andvisualViewport.width
? And why does it cause such a weird white-space effect when going below the minimum width of the header? - Are there any reason one wouldn't want to set
minimum-scale=1
?