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 :)
Related
I found a neat little JS library called Clippy.js that lets you implement Microsoft Word's old virtual assistants in your browser. After playing around with it for a while I realized that the text balloon has a setTimeout() method and a time delay causing it to disappear.
hide:function (fast) {
if (fast) {
this._balloon.hide();
return;
}
this._hiding = window.setTimeout($.proxy(this._finishHideBalloon, this), this.CLOSE_BALLOON_DELAY);
},
_finishHideBalloon:function () {
if (this._active) return;
this._balloon.hide();
this._hidden = true;
this._hiding = null;
},
I don't want that. I want the balloon to disappear when a user clicks. I tried registering an event listener by replacing this._hiding = ... with this:
var clickToHide = document.getElementsByClassName('clippy-balloon');
this._hiding = clickToHide.addEventListener('click', function(){$.proxy(this._finishHideBalloon, this)});
...but all that it does is hide the balloon completely. Why does that not work? And how do I achieve the functionality I want?
I think the delay is caused by the variable CLOSE_BALLOON_DELAY.
Changing this.CLOSE_BALLOON_DELAY to 0 should do the trick.
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;
});
For a mockup-webpage used for research on interaction on websites, I created a mockup message-stream using JavaScript. This message stream is loaded in an IFrame and should show images at pre-set intervals and scroll to the bottom of the page after placing a new image at the bottom of the page. Getting the images to appear is working quite well with the provided script. However, both Chrome and IE seem to have trouble scrolling the page to the bottom. I would like to scroll to the bottom of the page as soon as the image is attached, but have for now added a 5 ms delay because that seemed to work sometimes. My questions are:
Is it okay to use document.body.scrollHeight for this purpose?
Can I make the scroll occur directly, or do I need a small interval before scrolling?
How to make the code scroll to the bottom of the IFrame directly after adding an image?
The following functions are used and trypost() is started onLoad:
function scrollToBottom(){
window.scrollBy(0,document.body.scrollHeight);
}
function trypost(){
point = point + 1;
if(point < interval.length){
//create and append a new image
var newImg = document.createElement("IMG");
newImg.src = "images/"+images[point]+".png";
document.getElementById('holder').appendChild(newImg);
//create and append a return
var br = document.createElement("br");
document.getElementById('holder').appendChild(br);
//time scroll to bottom (after an arbitrary 5 seconds)
var stb = window.setTimeout(scrollToBottom, 5);
//time next post
var nextupdate = interval[point]*400;
var tp = window.setTimeout(trypost, nextupdate);
}
}
My script section contains at least the following variables:
var point = -1;
var interval = [10, 10, 15];
var images = ["r1", "a1", "r2"];
This questions is a continuation of the project described in How to proper use setTimeout with IE?
To answer one of your questions, document.body.scrollHeight is appropriate for this purpose, but not if you're actually calling for document. That'll give you the scroll height of the document the iFrame is in, not the iFrame's document. The iFrame's document can be called upon by [insert variable for iFrame here].contentDocument.
Here's how I did it (and by that, I mean I tested it out with my own stuff to make sure it worked):
let i = document.querySelector('iframe')
i.contentWindow.scrollTo(0, i.contentDocument.body.scrollHeight);
That being said, the other answer by Thomas Urban will also work most of the time. The difference is only if your page has a really long scroll height. Most pages won't be longer than 999999 (for all I know that's impossible and that's why they chose that number), but if you have a page longer than that, the method I showed here would scroll to the bottom and the 999999 would scroll to somewhere not yet at the bottom.
Also note, if you have more than one iFrame, you're gonna want to query it in a different way than I did, like by ID.
Scrolling to bottom is always like scrolling to some ridiculously large top offset, e.g. 999999.
iframe.contentWindow.scrollTo( 0, 999999 );
In addition see this post: Scrolling an iframe with javascript?
If scrolling occurs too early it's probably due to images not being loaded yet. Thus, you will have to scroll as soon as added image has been loaded rather than on having placed it. Add
newImg.onload = function() { triggerScrolling(); };
after creating newImg, but before assigning property src.
If several events are required to trigger scrolling you might need to use some "event collector".
function getEventCollector( start, trigger ) {
return function() {
if ( --start == 0 ) { trigger(); )
};
}
You can then use it like this:
var collector = getEventCollector( 2, function() { triggerScrolling(); } );
newImg.onload = collector;
window.setTimeout( collector, 100 );
This way triggerScrolling() is invoked after 100ms at least and after image has been loaded for collector has to be invoked twice for triggerScrolling() being invoked eventually.
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);
I'd like to know when the user first does some scrolling on my page, as distinct from the browser-initiated scrolling that happens automatically when you reload a page.
If I try capturing the window's initial scroll position, and then registering an onscroll handler to tell me the scroll position has changed, I don't get too far: browser-initiated scrolling happens after document ready (jQuery's definition), so window.pageYOffset is always 0 on doc ready, even if the browser's right about to jump me down a hundred pixels.
If I try inspecting the onscroll event, nothing seems to let me distinguish a user-initiated event object from a browser-initiated one. The two events have pretty identical properties.
I'm looking for something a little more robust than what's suggested here: How to distinguish scrolling by mouse from scrolling programmatically in JavaScript?.
Thanks...
It's ugly, but possibly the best way to tell is by timing. I notice that on Chrome, the change in pageYOffset happens within 1 millisecond of the window.onload, while on Firefox, it happens within one millisecond of the dom loading. (haven't tested IE, but it is likely that one or the other works) For instance I added this to the bottom of a page:
<script>
window.onload = function () {
var first = window.pageYOffset;
setTimeout(function () {
second = window.pageYOffset;
alert("first: " + first + ", second:" + second)
}, 1);
};
</script>
One chrome, "first" is 0, "second" is a big number, when refreshing a scrolled page. On firefox, that is only true if the below is added right before the closing body tag (which should be the same as jquery's document.ready).
<script>
var first = window.pageYOffset;
setTimeout(function () {
second = window.pageYOffset;
alert("first: " + first + ", second:" + second)
}, 1);
</script>
I think you could detect a "browser refresh initiated" scroll reliably using this sort of technique, but obviously, it's not what I'd call a pretty solution and it might break on a future browser version.
I use a similar technique for a scroll behavior on our home page, not the most elegant but it works well:
<html>
<head></head>
<body>
<div style="height:500px;line-height:500px">
<a id="bm" href="#bm">bookmarked</a>
</div>
<script>
(function(){
var scrollingCanStart = false;
//the user interact with the page
window.onmouseover = window.onkeydown = function(e){
scrollingCanStart = true;
};
//onscroll action
window.onscroll = function(e){
if(!scrollingCanStart){
return;
}
console.log('manual scroll');
};
})();
</script>
</body>
</html>
i was solving the same task and would like to share my approach.
my assumptions:
the user's scroll always preŃeded with events like 'wheel',
'another user's scroll' and etc
all events have timeStamp
I have chosen rxjs library for implementation
// this stream will contain last User's scroll
var last_scroll = new Rx.Subject();
var start = rx.Observable.merge(
Rx.Observable.fromEvent(element, 'wheel'),
last_scroll
)
.map(function (e) { return e.timeStamp; });
Rx.Observable.fromEvent(element, 'scroll')
.withLatestFrom(start, function (scroll, start) {
return {scroll: scroll, start: start};
})
.filter(function (o) {
return Math.abs(o.scroll.timeStamp - o.start) <= 500;
})
.map(function (o) {
return o.scroll;
})
.do(function (ev) {
last_scroll.onNext(ev);
})
.subscribe(function (ev) {
// here we have scroll event initiated by user
});
Please feel free to improve this code and share your thoughts. Happy coding!