Loading content with getBoundingClientRect - javascript

if (element.getBoundingClientRect().bottom < window.innerHeight) {...}
I'm loading content when scrolling to the bottom of the page. The problem is, at a certain point getBoundingClientRect().bottom ain't smaller than window.innerHeight - 640.390625 640. I don't know where this slightly bigger number comes from. There's no margin or anything else preventing the container getting to the end of the page.
If you need more details, just ask and I'll add it.
EDIT: The problem just seems to appear when simulating mobile devices in the dev tools. As a workaround I just substracted 25 from getBoundingClientRect().bottom but this seems ugly.

Try using IntersectionObserver. You can read up on it here

Related

What's the width of a screen? 100vw vs innerWidth vs visualViewport.width vs screen.width (React)

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 and visualViewport.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 from innerWidth and visualViewport.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?

Browser Zoom changes window.scrollTop/ document.scrollTop behaviour

I'm trying to read the current y-scroll of a page to fadeIn/out elements while the user scrolls past them.
I tried many different solutions from this site, things like .scrollTop, .pageYOffset, .scrollY etc. , with $(window) and $(document), $("element"), convert it to percentage and so on...
First they all work fine, But when I zoom in the browser, the results I get change each time:
I have this simple setup as a page
<div style="height: 800px"></div>
<h1 style="" id="test"> Test </h1>
<div style="height: 2000px"></div>
and for example this to read the scroll position:
$(window).scroll(function() {
console.log($(this).scrollTop());
When I scroll down to my header and go just above the T of Test it says 830px.
But when I zoom in (tried chrome and firefox), first of all my console stops giving continous values and seems to get laggy(?) and going to the same place (right above the T) returns a different value (smaller when zooming in) depending on my zoom, so for example 500px.
Is there a solution to this, or Is there maybe another approach to achieve what I'm trying to do?
Additional information
After more reading I know also see the difference between Zooming with Ctrl+/- (e.g. changing the font-size) and zooming by using my touchpad and 2 fingers. That also changes the results I get, so sometimes the element appears when window.scrollY returns 800px and sometimes it starts appearing when it says 300px. I'm getting more and more confused by this, maybe someone can help me with be basics here ;)
Came across this : this, Set precise scroll position when pinch-zoomed in sounds kind of what I'm experiencing.
Thanks in advance for any insights!
My Question is obsolete.
After reading more about browser zoom vs OS zooming, pixel vs pixelDensity etc.
it all makes sense now.

Rendering bug in WebKit browsers

In the project I currently work on we experience very strange rendering issue. The worst thing is that this issue emerges completely spontaneously and after several days of testing we haven't managed to find the sequence of actions wich would reproduce this issue. Here is an explanation of how this bug look like. Here is a screenshot of how the page should look like:
But instead of this after some manipulations content block pops up so only the part of the content is visible and its look like:
The most strange thing is that such a position of the block is not based on values of CSS properties as shown by Web Inspector.
As you can see the CSS properties are ok, while the position of the block is not. This fact suggest me that it could be some rendering bug of the WebKit engine
The project is built using Ext JS 3.4 and it is a classical one-page web application. This issue was seen in the last versions of Chrome and Safari on Mac OS 10.7/10.8. Though due to the spontaneous nature of this issue it might be present in other browsers and platforms too.
Any piece of advice on how to debug such issues or how it could arise is welcome.
Please check if any of your code or Ext JS's code is using scrollIntoView method, we have seen similar issue when scrollIntoView is called on any element that does not have overflow set to auto and it is inside an clipped element that is probably placed relatively positioned.
It seems bug in webkit because it scrolls clipped element which is not happening in other browsers.
I also see two elements in same hierarchy which has overflow set to auto. And scrollIntoView is scrolling wrong element.
Chrome and safari on Mac are having problems with scrolling. If the element has been scrolled and the content changes, the scroll position is kept even if the content is not high enough to require a scrolling.
The work around we have found in our application is to resize the container (the one that has the scroll) so that it has the scrollbar (or else you cannot play with the scrolling properties) and then reset the scrolling, and the height.
$(container).css('height',1).scrollTop('1').css('height','');
Here is how we do it in jQuery. You will not even see a flickering :)
I am not sure if it is the problem, but this thing kept us on our feet for a while.
i went through the same problem while working with a sencha touch 2 app and because thats same as ExtJS i have a solution for you
this probably is a bug in the framework and this happens when the ExtJS renders the application before the browser populates mayb the correct window.innerWidth and window.innerHeight and thus the viewport cannot take the correct width and height. this also explains the randomness of the event. This becomes more prominent when used on mobiles probably because of the limited resources and slow response.
the solution that i took to handle this mayb isnt a good one but i couldnt find a better one considering is a glitch in the framework itself
i poll for the correct height and width of the browser for around a sec after every say 100ms for the correct height and width of the window and if i find that the height OR width of the viewport isnt same i re adjust it. because you are working with ExtJS and app would run on high powered systems(as compared to mobile phones) i would recommend a smaller interval and then to be safe a larger time period to which it polls.
heres the code that i use currently edit according to your needs
var aId = setInterval(function () {
if (Ext.Viewport.getWidth() !== window.innerWidth || Ext.Viewport.getHeight() !== window.innerHeight) {
Ext.Viewport.setSize(window.innerWidth, window.innerHeight);
clearInterval(aId);
}
num = num + 1;
if (num > 10) {
clearInterval(aId);
}
}, 100)
i currently use this code inside the launch function of the app. but you can also use this inside the show event of the viewport for which you should keep the interval time to minimum possible to avoid any lags.
with this if you think this app might be used on devices where the window height and width would be changed by the user (like that of mobile browser when the orientation changes or if you think user would change the height and width of the browser window). then just copy & paste the same code piece inside the viewports resize event so that it also polls and resizes viewport when the size of the viewport changes.
Did you try adding a clear:both; block after the toolbar div ?
<div style="clear:both;"></div>
#bjornd it's pretty hard to debug without any code :)
Is the toolbar positioned and has the content an ID that's called in the URL?
In other words: is there some link (e.g.) that triggers #content and has no preventDefault() etc? This would scroll the page probably.
I dunno, this was the first thing that came to mind.
It could also be the toolbar content that is (for some reason) no longer cleared or some change in the content's top position (relative to another changed/removed element?)
Try and create a stripped-down test-case that contains the simplest of code but still triggers the bug. If you post that (through e.g. a Fiddle etc) we can have a proper look.
It might be a css issue;
I've had a similar issue using equal height divs by setting a padding-bottom: 99999px; and margin-bottom: -99999px;. Which workes fine in all cases, except when you use hashtag anchors to jump to a div further on the page. Jump down.
In that case the top of the page clipped and started with the div I wanted to see.
Since you say the problem is pretty hard to track, this might be something to have a look at. The solution was to remove these 2 css lines and use another method of setting div heights.

Mobile browser persistent footer (Non jquery)

I'm looking for a non-jquery solution to add a persistent footer overlay to my mobile site. It is similar to a popup ad that is on top of content but anchored to the bottom of the page.
I've been using a javascript approach to this:
window.addEventListener(
'scroll',
function() {
//if scrolled and offsets are the same (iphone)
if(_self.initOffsetY == window.pageYOffset)
{
document.getElementById(_self.id).style.bottom = _self.initWindowHeight - window.innerHeight+"px";
}
else
{
document.getElementById(_self.id).style.bottom = _self.initWindowHeight - window.innerHeight - window.pageYOffset+"px";
}
},
false
);
where initPage Height is the initial page height and initOffsetY is the initial offset of the page. This takes care of the case with the browser menu bar.
But it doesn't really work too well on android. The positioning is off. Can someone explain why? Thanks
You should probably use either of these standalone scrolling helpers:
http://joehewitt.github.com/scrollability/
or http://cubiq.org/iscroll
Wouldn't it be better to have two separate elements, a main wrapper and a footer div perhaps, and enable scrolling in just the wrapper (overflow:auto;)? This would avoid most browser inconsistencies, or even cases where JS is turned off.
There's a drawback though. You will need to program a method for scrolling inner elements for some mobile devices. There are libraries for this (gasp!), but frankly it isn't too hard to program yourself (as I've done with my site).
If you're attached to this approach of floating an element to where you want it / approximating position:fixed, you're going to have a number of things to check, one being html code that you've got to make sure there aren't any margins or padding interfering with the above script. The quick hack solution would be to just measure the heigh difference and calibrate your script according to that. The number you get from the calibration might be helpful in determining the source of the problem. There are probably some additional tricks to make this work smoothly, but I would go with a library thats being used already, and it looks like there are a number of them: http://bradfrostweb.com/blog/mobile/fixed-position/
btw - the iscroll4 library will fix the scrolling issue with overflow:auto on ios < 5, android < 4

Detect if address bar is shown in iPhone browser

I'm trying to detect, in a future-proof and device-independent way, when the address bar in the iPhone browser is showing. This is the toolbar that is shown at the top in order to display the URL. It can be hidden by calling:
window.scrollTo(0, 0)
What I'd like to do, is detect when it's being show (thus reducing the available viewing space) and set a timer to hide it again a second or so later. Any more frequent than that and it'll be quite annoying since users won't be able to get to the address bar.
I've tried checking window.pageYOffset, unfortunately, this returns zero if any part of the url bar is visible.
I don't want to hard code any dimensions on the iPhone and check those against the current viewport size. It's too fragile.
Anyone know a solution here?
The window.innerHeight property is what you're looking for. This is the height of the actual content on the screen. It's significantly less when the toolbar at the top is visible, because there's less room for the content. There is a slight problem that I can't seem to figure out on my iPhone 4 - window.innerHeight sometimes returns 3 pixels less at certain scroll positions of the screen.
I've set up an example for you that does more or less what you asked, it should at least get you started:
http://jsfiddle.net/rUSEb/show/light (test it out on your iphone).

Categories

Resources