page scrolling inconsistency between mobile Chrome and Safari - javascript

One feature of my mobile web app involves scrolling users to a particular point on the page. The following code accomplishes this, but it only works on iPhone Safari. On Chrome browser / Android, it scrolls to the bottom of the page instead. Why the inconsistency?
Please note: I don't want to use jQuery.
var $ = function(elID) {
return document.getElementById(el);
}
// Get info about target element's position and dimensions
var getRect = function(el) {
return el.getBoundingClientRect();
}
var scrollJump = function(){
var page = $('dPageContainer');
headerHeight = getRect($('dFixedHeader')).height;
return function(el){
// If a jQuery object, convert to raw DOM el
if ('get' in el) {
el = el.get(0);
}
var rect = getRect(el);
// Scroll the page to the element's position
page.scrollTop+= rect.top - rect.height - headerHeight;
}
};
var scrollToEl = scrollJump();
scrollToEl( $('my_DIV_ID') );

I was able to solve this problem by simplifying and cleaning up the code. In particular, I used the offsetTop method instead of relying only on getBoundingClientRect:
var $ = function(el) {
return document.getElementById(el);
}
var scrollJump = function(){
var page = $('dPageContainer'),
headerHeight = $('dFixedHeader').getBoundingClientRect().height;
return function(el){
// If a jQuery object, convert to raw DOM el
if ('get' in el) el = el.get(0);
// Scroll the page to the element's position
page.scrollTop = el.offsetTop - headerHeight;
}
};
var scrollToEl = scrollJump();
scrollToEl( $('my_DIV_ID') );

Related

getComputedStyle width and height not working in chromium webview on real Android devices

I had this javascript function:
function onFontLoad(cb,font,size,table,interval)
{
var div=document.createElement("div");
div.style.fontFamily=font;
div.style.fontSize=size;
div.style.position="absolute";
div.style.top="-100px"
div.style.left="-100px"
document.body.appendChild(div);
var checkInterval=setInterval(function()
{
for(character in table)
{
div.textContent=character;
var t=table[character];
var s=getComputedStyle(div);
if(parseInt(s.width)!=t[0]||parseInt(s.height)!=t[1]) return;
}
div.parentNode.removeChild(div);
clearTimeout(checkInterval);
cb();
},interval||200);
And it worked since webview in android was based on webkit.
Since WebView was changed to chromium my function stop working even in Chromium browser. I got suggestion to use Math.ceil with rounding, and also avoid using parseInt.
Now I have this function:
function onFontLoad(cb, font, size, table, interval) {
var div = document.createElement("div");
div.style.fontFamily = font;
div.style.fontSize = size;
div.style.position = "absolute";
document.body.appendChild(div);
var getRawPixels = function (cssUnit) {
// Round up to the highest unit.
var re = /([\d.]+)(px)/; // css measure units.
var results = cssUnit.replace(re, "$1");
return Math.ceil((results * 10) / 10) ;
};
var checkInterval = setInterval(function () {
for (var character in table) {
div.textContent = character;
var t = table[character];
var s = getComputedStyle(div);
if (getRawPixels(s.width) != t[0] || getRawPixels(s.height) != t[1]) return;
}
div.parentNode.removeChild(div);
clearTimeout(checkInterval);
cb();
}, interval || 200);
And function works like intended now in Chromium browser or in Android (starting 4.4 to 6 emulators) and I have no problem with webview rendering in emulators. But its blank on some real devices, even without webview hardware acceleration.(mostly android 5.x devices) But I'm pretty there is no problem with canvas rendering, since if I comment or remove this string:
if (getRawPixels(s.width) != t[0] || getRawPixels(s.height) != t[1]) return;
Webview will start render as intended again even with real android devices I test application with, but without applying style from onFontLoad function.
Another thing I found in process is that broken webview in Chrome Developer Tools adds <i> after div. But same code running in emulator displaying canvas nicely and there no any <i> after div. However I can broke canvas in emulator if I remove string with div position. And after this doom action I'll see <i> in page source code after div too.
Also, I found that Chromium had some issues with getComputedStyle in past too. But I think getComputedStyle is working ok.
It was something with div hiding. I just removed hiding, since after hiding div destroyed itself with application in canvas. Simplicity really a key there.
function onFontLoad(cb, font, size, table, interval) {
var div = document.createElement("div");
div.style.fontFamily = font;
div.style.fontSize = size;
//div.style.position = "relative";
document.body.appendChild(div);
var checkInterval = setInterval(function () {
for (var character in table) {
div.textContent = character;
var t = table[character];
var s = getComputedStyle(div);
}
clearTimeout(checkInterval);
cb();
}, interval || 200);
}

Need to trigger an event as footer comes into view

I have a deep page with a deep footer
I want to use some jQuery to trigger an event when the top of the footer comes into view
I have looked and tried using
var scrollTop = jQuery (window).scrollTop();
but it just gives the position when you load, and it doesn't change as you scroll
Any ideas please
You can use my script on this answer: Pause and play video when in viewport
Fiddle: http://jsfiddle.net/pwhjk232/
$(document).ready(function() {
var inner = $(".inner");
var elementPosTop = inner.position().top;
var viewportHeight = $(window).height();
$(window).on('scroll', function() {
var scrollPos = $(window).scrollTop();
var elementFromTop = elementPosTop - scrollPos;
if (elementFromTop > 0 && elementFromTop < elementPosTop + viewportHeight) {
inner.addClass("active");
} else {
inner.removeClass("active");
}
});
})

scroll anchor show/hide

was working on a anchor point that triggers a divs visibility. There's no problems if I run it with Jquery 1.3.2 library but when I try with 1.7.1 it's not recognized. any ideas?
$(function() {
var a = function() {
var windowtop = $(window).scrollTop();
var d = $("#anchor").offset({scroll:false}).top;
var c= $("#flyout");
if (windowtop > d) {
c.css({visibility:"visible"});
} else {
if (windowtop <= d) {
c.css({visibility:"hidden"});
}
}
};
$(window).scroll(a);a()
});
});
d seems to always return undefined.
I suspect your code breaks because of the {scroll:false} object your are passing as an argument to offset(). Removing it might solve your problem.
Check the jQuery().offset() API;
jQuery(elem).offset()returns an object containing the element's top and left coordinates. Can be used as jQuery(elem).offset().top;.
jQuery(elem).offset({top:20, left:20}); sets the new top and left coordinates for the element.

Menu that fit to the buttom/top of the screen

I saw a cool style/js function (I can tell what it is) that implemented on a side menu.
You know the situation when you have a long center page and one of / both of you sides ends and that leave a blank space? Well this site implemented this thing that just when the user scrool to the place where the side menu end - the menu get absolute postion and doesnt move.
How can I do this?
If you want to see an example you can look here (just scroll and look on the sides)
I believe you can achieve similar effect using this: http://www.wduffy.co.uk/blog/keep-element-in-view-while-scrolling-using-jquery/comment-page-1/ (just making it move with 0 as speed parameter instead of slow, as in the example) and adding conditions about whether the current position fits within the box it is displayed (you can take height of the box - menu being moved on page or box that contains the menu - by using .height() jQuery function).
EDIT:
The page you referenced uses the following JavaScript code to support what you try to accomplish:
<script type="text/javascript">
$(function(){
var seoHeight = $$('dvIndexSeoMaster').height();
seoHeight = (seoHeight > 0) ? seoHeight : 0;
var documentHeight = $(document.body).height() - 120 - seoHeight;
var fixedMode = false;
var hasFixedClass = false;
var leftColElm = $sc('dvFixed');
var leftColPos = leftColElm.offset().top;
var leftColHeight = leftColElm.height();
var rightColElm = $$('dvIndexMasterRightCol');
var rightColPos = rightColElm.offset().top;
var rightColHeight = rightColElm.height();
function scrollElm(elmPos,elmHeight,objElm, cssClass){
var fixedMode = false;
var hasFixedClass = false;
var windowTop = $(window).scrollTop();
(windowTop >= elmPos && (windowTop + elmHeight) < documentHeight) ? fixedMode = true : fixedMode = false;
if( fixedMode){
$(objElm).addClass(cssClass);
hasFixedClass = true;
}else if( (fixedMode == false)){
$(objElm).removeClass(cssClass);
hasFixedClass = false;
}
};
$(window).scroll(function(){
scrollElm(leftColPos,leftColHeight,leftColElm,'make-fixed');
scrollElm(rightColPos,rightColHeight,rightColElm, 'make-fixed');
});
});
</script>
And the make-fixed CSS class has the following definition:
.make-fixed {
position: fixed;
top: 0;
z-index: 200;
}
You can make an element stay in the same place, even as the user scrolls, with the CSS position:fixed property: http://www.w3.org/TR/CSS2/visuren.html#fixed-positioning

javascript: detect scroll end

I have a div layer with overflow set to scroll.
When scrolled to the bottom of the div, I wanna run a function.
The accepted answer was fundamentally flawed, it has since been deleted. The correct answer is:
function scrolled(e) {
if (myDiv.offsetHeight + myDiv.scrollTop >= myDiv.scrollHeight) {
scrolledToBottom(e);
}
}
Tested this in Firefox, Chrome and Opera. It works.
I could not get either of the above answers to work so here is a third option that works for me! (This is used with jQuery)
if (($(window).innerHeight() + $(window).scrollTop()) >= $("body").height()) {
//do stuff
}
Hope this helps anyone!
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight)
{
//your code here
}
I too searched it and even after checking all comments here and more,
this is the solution to check if reached the bottom or not.
OK Here is a Good And Proper Solution
You have a Div call with an id="myDiv"
so the function goes.
function GetScrollerEndPoint()
{
var scrollHeight = $("#myDiv").prop('scrollHeight');
var divHeight = $("#myDiv").height();
var scrollerEndPoint = scrollHeight - divHeight;
var divScrollerTop = $("#myDiv").scrollTop();
if(divScrollerTop === scrollerEndPoint)
{
//Your Code
//The Div scroller has reached the bottom
}
}
This worked for me:
$(window).scroll(function() {
buffer = 40 // # of pixels from bottom of scroll to fire your function. Can be 0
if ($(".myDiv").prop('scrollHeight') - $(".myDiv").scrollTop() <= $(".myDiv").height() + buffer ) {
doThing();
}
});
Must use jQuery 1.6 or higher
I found an alternative that works.
None of these answers worked for me (currently testing in FireFox 22.0), and after a lot of research I found, what seems to be, a much cleaner and straight forward solution.
Implemented solution:
function IsScrollbarAtBottom() {
var documentHeight = $(document).height();
var scrollDifference = $(window).height() + $(window).scrollTop();
return (documentHeight == scrollDifference);
}
Resource: http://jquery.10927.n7.nabble.com/How-can-we-find-out-scrollbar-position-has-reached-at-the-bottom-in-js-td145336.html
Regards
I created a event based solution based on Bjorn Tipling's answer:
(function(doc){
'use strict';
window.onscroll = function (event) {
if (isEndOfElement(doc.body)){
sendNewEvent('end-of-page-reached');
}
};
function isEndOfElement(element){
//visible height + pixel scrolled = total height
return element.offsetHeight + element.scrollTop >= element.scrollHeight;
}
function sendNewEvent(eventName){
var event = doc.createEvent('Event');
event.initEvent(eventName, true, true);
doc.dispatchEvent(event);
}
}(document));
And you use the event like this:
document.addEventListener('end-of-page-reached', function(){
console.log('you reached the end of the page');
});
BTW: you need to add this CSS for javascript to know how long the page is
html, body {
height: 100%;
}
Demo: http://plnkr.co/edit/CCokKfB16iWIMddtWjPC?p=preview
This will actually be the correct answer:
function scrolled(event) {
const container = event.target.body
const {clientHeight, scrollHeight, scrollY: scrollTop} = container
if (clientHeight + scrollY >= scrollHeight) {
scrolledToBottom(event);
}
}
The reason for using the event is up-to-date data, if you'll use a direct reference to the div you'll get outdated scrollY and will fail to detect the position correctly.
additional way is to wrap it in a setTimeout and wait till the data updates.
Take a look at this example: MDN Element.scrollHeight
I recommend that check out this example: stackoverflow.com/a/24815216... which implements a cross-browser handling for the scroll action.
You may use the following snippet:
//attaches the "scroll" event
$(window).scroll(function (e) {
var target = e.currentTarget,
scrollTop = target.scrollTop || window.pageYOffset,
scrollHeight = target.scrollHeight || document.body.scrollHeight;
if (scrollHeight - scrollTop === $(target).innerHeight()) {
console.log("► End of scroll");
}
});
Since innerHeight doesn't work in some old IE versions, clientHeight can be used:
$(window).scroll(function (e){
var body = document.body;
//alert (body.clientHeight);
var scrollTop = this.pageYOffset || body.scrollTop;
if (body.scrollHeight - scrollTop === parseFloat(body.clientHeight)) {
loadMoreNews();
}
});
To do the same in React/JSX, here is the snippet.
export const scrolledToEnd = event => {
const container = event.target;
if (container.offsetHeight + container.scrollTop >= container.scrollHeight) {
return true;
}
return false;
};
And in your component add
<Component onScroll={scrolledToEnd}>
There is experimental onscrollend event https://developer.mozilla.org/en-US/docs/Web/API/Document/scrollend_event
For now works only in firefox 109+, if other browsers catch up will be very nice.
Have polyfill for that https://github.com/argyleink/scrollyfills
Use like
import "scrollyfills";
...
scrollContainer.addEventListener(
"scrollend",
(ev) => { console.log('scroll END') }
);
I found this methode to get the end of the scroll :
let TheBody = document.getElementsByTagName("body"); // I choose the "body" element for my exemple
function OnScrolling(){ // put this on a scrolling EVENT
let ScrollEnd = TheBody[0].scrollHeight - window.innerHeight; // this is the scroll end Pixel
if (ScrollEnd.toFixed() == window.scrollY.toFixed()){
//do stuff
}
}
Okay now for your DIV or any other element that have a scrolling I found this method on JavaScript :
let D = document.getElementById("D1"); // I gave "D1" as id to my div
// this one is to calculate the scroll end Pixels
let Calc = D.scrollHeight - D.clientHeight;
function ScrollingInD1() {
//this one is to calculate the scrolling percent while going through the <div> it can help for "Responsivity"
let percent = (D.scrollTop * 100) / Calc;
if (D.scrollTop == Calc) {
// do Stuffs
}
}

Categories