I am writing a web app in HTML and JavaScript for use on an iPhone. What I would like to achieve is preventing the app from elastic scrolling (scrolling past the pages extents and bouncing back). However, I need some of the longer elements of my app to be able to be scrolled (the app has a long canvas).
I have tried many answers to this found elsewhere on the internet, however, all of those solutions either used JQuery, disabled scrolling altogether, used Phonegap or just plain didn't work on IOS 7. How can I do this?
There is a way to achieve this without jQuery:
document.body.addEventListener('touchmove', function(event) {
event.preventDefault();
});
But this is not a proper solution. It's better to wrap your content in some div, and use css property on it:
-webkit-overflow-scrolling: touch;
Here is the example
Edit:
This will only prevent overscroll in webview, not in app. So you need to disable this feature in app config.
If you use phonegap:
<preference name="DisallowOverscroll" value="true" />
More description here
If you don't use phonegap, you can use this.
The above solution was insufficient in my case. It prohibits all scrolling. It is possible to build a solution here that prevents elastic scrolling in iOS, but that still allows scrolling on children. I this took the above solution and added a check that bubbles up the DOM to determine which scrollable element "owns" the scroll event, and if it's the root element of the page, I drop it:
function overflowIsHidden(node) {
var style = getComputedStyle(node);
return style.overflow === 'hidden' || style.overflowX === 'hidden' || style.overflowY === 'hidden';
}
function findNearestScrollableParent(firstNode) {
var node = firstNode;
var scrollable = null;
while(!scrollable && node) {
if (node.scrollWidth > node.clientWidth || node.scrollHeight > node.clientHeight) {
if (!overflowIsHidden(node)) {
scrollable = node;
}
}
node = node.parentNode;
}
return scrollable;
}
document.addEventListener('DOMContentLoaded', function() {
document.body.addEventListener('touchmove', function(event) {
var owner = findNearestScrollableParent(event.target);
if (!owner || owner === document.documentElement || owner === document.body) {
event.preventDefault();
}
});
}, false);
At this point, the body is no longer scrollable or elastically scrollable in iOS, but children elements are. You can then add -webkit-overflow-scrolling: touch; to those children so they are elastic but the document wont be. This will actually capture all scroll events even as you scroll to the bottom of the children, so the window's scroll position wont ever change erroneously. Alternatively you may also consider:
['resize', 'orientationchange', 'scroll'].forEach(function(event) {
window.addEventListener(event, function() {
window.scrollTo(0, 0);
});
});
which in addition to the first code block I shared, should really throw an axe at document scrolling in ios altogether.
So when you have scroll content in body & want to disable elastic scroll
use:
let scrollToTop = $(window).scrollTop();
if (scrollToTop < 0) {
// do something here
}
Because elastic scroll will always have negative value
Based on answer by #umidbek this is how it worked for me
document.getElementById('content-sections').
addEventListener('touchmove', function (event) {
event.preventDefault();
return false;
});
Related
What tools can be used to create scrolling behavior like the one on this site: https://yuga.com/ ?
I tried to use a lock on the sections, waiting for them to scroll fully horizontally.
After I finished scrolling, I returned the ability to scroll the page
const screenLock = (entries: IntersectionObserverEntry[]) => {
if (window.innerWidth < 790) return;
const event = entries[0].isIntersecting;
if (!event) return;
if (!props.ignoreFixed) {
setTimeout(() => {
setFixed(true);
document.body.style.overflow = "hidden";
}, 100)
}
};
so what you are looking for is called "Parallax".
There actually is a library for that called "react-scroll-parallax", here is the link for it's npm https://www.npmjs.com/package/react-scroll-parallax
It's very simple to use, I've previously used it in some projects and it looks great. There also is a great documentation page with a few examples you could follow and refer to.
https://react-scroll-parallax.damnthat.tv/docs/intro
Hope this helps :)
I have a problem with my script.
It was working perfectly until last week, when my client talked about it.
My website has some links with an hash added to scroll smoothly to id when page is loaded. Now it doesn't scroll smoothly anymore. I did check my variables, and it gets the hash has id (e.g. #content) and also the height of the header nav.
I can't find the problem.
Here's the script:
if (window.location.hash) {
//bind to scroll function
$(document).scroll( function() {
var hash = window.location.hash;
//var hashName = hash.substring(1, hash.length);
var element;
//if element has this id then scroll to it
if ($(hash).length !== 0) {
element = $(hash);
}
//if we have a target then go to it
if (element !== undefined) {
window.scrollTo(0);
}
//unbind the scroll event
$(document).unbind("scroll");
$("html, body").animate({scrollTop: ($(element).offset().top - $('header nav ul').height()) }, 500);
});
}
Thanks in advance
Native scrollers dont work nice. Handling different browsers and mobile devices is realy difficult. Use iScroll my friend http://cubiq.org/iscroll-5 .. it works like a charm and comes with a lot of features!!!
I am using raphael to draw items on the screen. I have the container for the drawing object contained in a div and overflow: scroll. In all broswers except for IE 7/8 when the user is drawing it does not scroll. However, in IE 7/8 when the user is dragging (i.e. drawing a line) it scrolls automatically as the user nears the edges. I have found some help with jQuery and have tried overriding the onscroll event of the div but that didn't work.
I am not using jQuery and cannot add it.
Sometimes scrolling is caused by "selecting" text in the window (click and drag from top to bottom on this SO page to see what I mean). I can't tell from your description if this is the issue without seeing a jsFiddle example or sample code, but you might try disabling selection.
As you mentioned jQuery is not an option for you. If it were, you'd just use disableSelection().
For a vanilla Javascript solution, try:
function disableSelection(target) {
if (typeof target.onselectstart != "undefined") { //IE
target.onselectstart = function () {
return false;
};
} else if (typeof target.style.MozUserSelect != "undefined") { //Firefox
target.style.MozUserSelect = "none";
} else { //All other ie: Opera
target.onmousedown = function () {
return false;
};
}
target.style.cursor = "default";
}
window.onload = function () {
disableSelection(document.body);
};
Source (slightly modified for clarity): Disable selection on browser using Javascript
I've written a rather basic js function that programatically and automatically aligns the iPhone keyboard perfectly underneath each and every input field that gets focused (feel free to use it if you like it!). The alignment's primarily handled by window.scroll - a standard method that works in any browser view, except in UIWebView hence phonegap/cordova (2.1). So I need a workaround.
My working code:
function setKeyboardPos(tarId) {
//programmatically: set scroll pos so keyboard aligns perfectly underneath textfield
var elVerticalDistance = $("#"+tarId).offset()["top"]; //i.e. 287
var keyboardHeight = 158;
var heightOfView = document.height; // i.e. 444
var inputHeight = $("#"+tarId).outerHeight();
var viewPortSpace = heightOfView-keyboardHeight; //i.e. 180
var verticalNewSroll = (elVerticalDistance+inputHeight)-viewPortSpace;
if(verticalNewSroll<0) { verticalNewSroll = 0; }
////
//OK, all done lets go ahead with some actions
$("#footer").hide(); //hide footer so that the keyboard doesn't push it on top of textfield
$("#containingDiv").css("bottom","0px"); //remove bottom space for footer
window.scrollTo(0,verticalNewSroll); //scroll! where the problem starts
}
Working in everything but UIWebView, that is. As I mentioned above, everything works except the window.scrollTo (N.B. some minor changes have been made for the sake of clarity). So does anyone know of an alternative solution or even a good workaround?
Similar questions
window.scrollTo doesn't work in phonegap for IOS
PhoneGap / Cordova scrollTo Ignored
How to add vertical scroll in Phonegap
Above are furthermore three similar questions that somewhat points one in the right direction. One of the answerers mentions the use of css to accomplish this. Can anyone come up with a more concrete example? Another guy suggests anchors but that's not a very pretty solution and doesn't go very well with the rest of my code.
After doing some research, I realized window.scrollTo() does actually work in iOS6 with phonegap 2.1, there was something else that failed; for some reason, document.height didn't yield a property of equal proportion within UIwebView so I had to write a small workaround. I'll post the solution and the entire code below for future reference.
function setKeyboardPos(tarId) {
//programmatically: set scroll pos so keyboard aligns perfectly underneath textfield
var elVerticalDistance = $("#"+tarId).offset()["top"];
var keyboardHeight = 157;
if(isNativeApp()) { keyboardHeight = 261; } //I choose to change the keyboard height for the sake of simplicity. Obviously, this value does not correnspond to the actual height of the keyboard but it does the trick
var keyboardTextfieldPadding = 2;
var heightOfView = document.height;
var inputHeight = $("#"+tarId).outerHeight();
var viewPortSpace = heightOfView-keyboardHeight-keyboardTextfieldPadding; //180
var verticalNewSroll = (elVerticalDistance+inputHeight)-viewPortSpace;
if(verticalNewSroll<0) { verticalNewSroll = 0; }
////
//OK, all done lets go ahead with some actions
$("#footer").hide(); //hide footer so that the keyboard doesn't push it on top of textfield
$("#containingDiv").css("bottom","0px"); //remove bottom space for footer
window.scrollTo(0,verticalNewSroll); // perform scroll!
}
function isNativeApp() {
var app = (document.URL.indexOf('http://') === -1) && (document.URL.indexOf('https://') === -1);
if (app) {
return true; // PhoneGap native application
} else {
return false; // Web app / safari
}
}
you can try and use the animate and scrollTop property to scroll It looks something like this:
$("html, body").animate({ scrollTop: "The value to scroll to" });
Hope this helps.
You just need to use this:
$(window).scrollTop(0);
Basically I need to find all elements on the page that have a scrollbar (vertical or horizontal)
How to tell if an element has a scrollbar and can actually be scrolled? I found this code snippet on jsperf. Is it possible to capture the logic behind the code into and XPath expression? Or are there any other ways to check for scrollbars?
Added:
Just to explain what I'm trying to do: I'm developing VimFx - extension for Firefox. Basically it introduces Vim-style mouseless shortcuts (I know there is Vimperator and Pentadactyl...). One of the features I'd like to implement is to allow the use to select the container that's scrolled with j/k keys. That's why I need to discover all scrollable elements on any given random page.
You can check it with javscript is the overflow of a div is set to "scroll"
document.getElementById(elementId).style.overflow == "scroll";
I would check that on every element tough. If all of your elements are divs' then use this:
var allElements = document.getElementsByTagName("div");
for(index in allElements) {
var element = allElements[index];
if (element.style.overflow == "scroll" || element.style.overflowX == "scroll" || element.style.overflowY == "scroll"){
//do something
}
}
I have now implemented support for discovering scrollable elements in VimFx.
The key to solving this problem is to use the Mozilla-specific events overflow
and underflow.
The concept is:
// The function used for the overflow event:
function(event) {
// `window` is a reference to the current window.
var computedStyle = window.getComputedStyle(event.target)
// `overflow: hidden` can cause overflow, but without a scrollbar, so
// exclude such elements
if (computedStyle && computedStyle.getPropertyValue('overflow') == 'hidden') {
return
}
// `scrollableElements` is a reference to a `WeakMap` object for the
// current window.
scrollableElements.set(event.target)
}
// The function used for the underflow event:
function(event) {
scrollableElements.delete(event.target)
}
// Somewhere else in the code we can now get a suitable `scrollableElements`
// object and check if elements are present in it.
if (scrollableElements.has(someElement)) {
// `someElement` is scrollable!
}