There were some problems, led to scrolling "contents_container" instead of scrolling "body".
From then on, click "history.back" to forget the scroll position.
I found jquery cookie but it doesn't works.
// When document is ready...
$(document).ready(function() {
// If cookie is set, scroll to the position saved in the cookie.
if ( $.cookie("scroll") !== null ) {
$(document).scrollTop( $.cookie("scroll") );
}
// When a button is clicked...
$('#submit').on("click", function() {
// Set a cookie that holds the scroll position.
$.cookie("scroll", $(document).scrollTop() );
});
});
and this too.
if (history.scrollRestoration === 'manual') {
history.scrollRestoration = 'auto';
}
and this too.
I really want to remember the page's scroll position.
Here is my css code and could you fix the problem?
.contents_container {width: 100%; height: 100%; overflow-y: scroll; position: relative; float:left;}
Thank you.
I made it on popstate, you can achieve this on 'beforeunload' even
on this event page still exist but is not visible. (if is server side rendered)
window.addEventListener('popstate', onLocationChange);
function onLocationChange(e){
const scrollY = window.scrollY || window.pageYOffset;
localStorage.setItem("scrollY", scrollY)
}
window.addEventListener("load", onPageLoad);
function onPageLoad(){
const scrollY = parseInt(localStorage.getItem("scrollY"));
if(scrollY && !isNaN(scrollY)) {
window.scrollTo(0, scrollY)
}
}
for overflowded container
window.addEventListener('popstate', onLocationChange);
function onLocationChange(e){
//if(document.location.test() or startsWith() ....
// to fire only on desired pages
const container document.querySelector('.contents_containe');
const scrollTop = container.scrollTop;
localStorage.setItem("container-scrollTop", scrollTop)
}
window.addEventListener("load", onPageLoad);
function onPageLoad(){
const scrollTop = parseInt(localStorage.getItem("container-scrollTop"));
if(scrollTop && !isNaN(scrollTop)) {
const container document.querySelector('.contents_containe');
container.scrollTop = scrollTop;
}
}
Related
I found a lot of examples of console logging scroll direction. But even though I tried modifying almost all of them to return a value instead, I couldn't make them work.
My goal is to check the scrolling direction when entering a specific viewport, and return false if the scrolling direction is down. Then I want to use the false value in a exitviewport function to only then send ONE ReactGA event of scrolling. My attempts have either resulted in 'cannot read property of undefined' error or to a lot of events which I do not want. I think my main problem is combining a return with the fact that there is a reassignment that needs to be reached by the code.
My code so far is:
//this code I found and it seems to work
onEnterViewPort () {
window.onscroll = function (e) {
console.log(this.oldScroll > this.scrollY);
this.oldScroll = this.scrollY;
};
}
//used console logs to check.
onExitViewPort () {
console.log('I have left the viewport.')
// ReactGA.event({
// category: 'Scroll',
// action: 'Scrolled down',
// });
}
which I use in
<ScrollTrigger onEnter={this.onEnterViewPort} onExit={this.onExitViewPort} triggerOnLoad={false}>
<div >
<thingshere>
</div>
</ScrollTrigger>
Please help a noob out!
Example with jQuery.
This will start to display the scrolling direction after u entered the Viewpoint the first time, so you would need to create another funtion for the onExitViewpoint event...
$.fn.onEnterViewport = function (callback) {
var $window = $(window);
return this.each(function () {
var that = this;
var oldHeight = 0;
$(document).on('scroll', function () {
var docHeight = $window.height();
var myTop = $(this).scrollTop();
var myOffset = $(that).offset();
var top = myOffset.top - myTop;
if(top < docHeight){
callback(oldHeight, top);
}
oldHeight = top;
});
});
};
$('.viewpoint-in').onEnterViewport(function(oldHeight, newHeight) {
if (oldHeight > newHeight) {
console.log('Scroll Down')
} else {
console.log('Scroll Top')
}
});
*{
padding: 0;
margin: 0;
}
.viewpoint-out {
background: red;
height: 1000px;
}
.viewpoint-in {
background: white;
height: 600px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section>
<div class="viewpoint-out"></div>
<div class="viewpoint-in"></div>
<div class="viewpoint-out"></div>
</section>
I have this header that is working fine. My issue is that when you reload the page when the scroll position is passed 114, the header is not fixed until you scroll. I'm trying to get it to detect the scroll position of the page before the user scrolls.
function initHeader() {
var Header = document.querySelector(".header");
var HeaderContainer = document.querySelector(".header-container-after");
document.addEventListener('scroll', function () {
if (window.scrollY > 114) {
Header.classList.add('header--is-fixed');
HeaderContainer.classList.add('fixed-header-container');
} else {
Header.classList.remove('header--is-fixed');
HeaderContainer.classList.remove('fixed-header-container');
}
});
}
window.onload = initHeader;
thanks
There can be an even easier solution, use position: sticky; top: 0
It will act as an relative element until it hits the top (or before, change the top value) and from that point it will act as a fixed element.
In case you want to stick with JS for this, wrap it in a function and call it on load
let header;
let headerContainer;
function fixNav(){
if (window.scrollY > 114) {
header.classList.add('header--is-fixed');
headerContainer.classList.add('fixed-header-container');
} else {
header.classList.remove('header--is-fixed');
headerContainer.classList.remove('fixed-header-container');
}
}
document.addEventListener('DOMContentLoaded', ()=>{
header = document.querySelector(".header");
headerContainer = document.querySelector(".header-container-after");
document.addEventListener('scroll', fixNav);
fixNav();
})
Looks like you are only running the code when the user scrolls. Try running it when the user scrolls AND when the page loads. Like so:
function initHeader() {
var Header = document.querySelector(".header");
var HeaderContainer = document.querySelector(".header-container-after");
// extract the logic to a function
var updateNav = function () {
if (window.scrollY > 114) {
Header.classList.add('header--is-fixed');
HeaderContainer.classList.add('fixed-header-container');
} else {
Header.classList.remove('header--is-fixed');
HeaderContainer.classList.remove('fixed-header-container');
}
}
// run that function on scroll
document.addEventListener('scroll', updateNav);
// but also run it right now (page load)
updateNav();
}
window.onload = initHeader;
Hello there I've been trying to find a fix for the many scroll events firing on one scroll. This is the only thing close to working for me so far. I want to smoothscroll between two divs (#boxes and #header) I want to use the scroll bar to trigger this smooth scroll and not a button. Any suggestions on how to only take one scroll event? I also used solutions based from prev stackoverflow questions. I used my own locator instead of offsets because thats also unreliable
$(window).scroll(function () {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(function () {
if (locator == 0) {
id = $("#boxes");
locator = 1;
} else if (locator = 1) {
id = $("#header");
locator = 0;
}
// target element
var $id = $(id);
if ($id.length === 0) {
return;
}
// top position relative to the document
var pos = $id.offset().top;
// animated top scrolling
$('html, body').animate({scrollTop: pos}, 1500, function () {
$('html, body').clearQueue();
$('html, body').stop();
});
}, 2);
});
So, to be clear, you want any minor scroll event to scroll between one item and the other? Note that when a user scrolls, there is a "momentum" that the browser implements, and you'll be battling with that.
Regardless: You don't need to wrap this in a setTimeout. Right now, your javascript is creating a new setTimeout function that is being fired every 2ms. Scroll events occur with every pixel of movement in the scroll, so if you scroll 100px, you're going to be firing 100 times every 2ms. (That's 50,000 times).
Instead, have a a variable (isScrolling) track the state, so, if you're in the middle of scrolling, the function won't fire.
var isScrolling = false;
var locator = 0;
$(window).scroll(function () {
if (isScrolling) return false;
if (locator == 0) {
id = $("#boxes");
locator = 1;
} else if (locator = 1) {
id = $("#header");
locator = 0;
}
// target element
var $id = $(id);
if ($id.length === 0) {
return;
}
// top position relative to the document
var pos = $id.offset().top;
// animated top scrolling
isScrolling = true;
$('html, body').animate({scrollTop: pos}, 1500, function () {
$('html, body').clearQueue();
$('html, body').stop();
isScrolling = false;
});
});
Here's a JSbin: http://jsbin.com/jugefup/edit?html,css,js,output
i have a page with an iframe...
currently i used this code to load iframe on click..
here is my code
$('.a').click(function(){
var iframe = $("#b");
iframe.attr("src", iframe.data("src"));
});
html:
<button class='a'>Load</button>
<iframe id='b' src='' data-src='index.php'></iframe>
but i also i want to load iframe on scroll down (500px from top)
can someone please help me how i can do this...
Thanks
Try this:
$(window).scroll(function() {
var height = $(window).scrollTop();
if(height > 500) {
var iframe = $("#b");
iframe.attr("src", iframe.data("src"));
}
});
If you want to only load one time after scroll with more than 500
you can add flag and set it to false on page load. Then set it true inside scrolling event and check for this flag before you load iframe
Example:
var isLoaded = false;
$(window).scroll(function() {
var height = $(window).scrollTop();
if(height > 500) {
if(!isLoaded){
var iframe = $("#b");
iframe.attr("src", iframe.data("src"));
isLoaded = true;
}
}
});
The idea is to add a callback to the scroll event dispatched on the window object every time the user scrolls the page. This callback is used to load the iframe if it's not loaded yet and if the scroll value is higher than 500px.
(function () {
var iframeLoaded = false;
function loadIframeOnScroll() {
if (window.scrollY >= 500 && !iframeLoaded) {
loadIframe();
}
};
function loadIframe() {
if (!iframeLoaded) {
var $iframe = $('#b');
$iframe.attr('src', $iframe.data('src'));
window.removeEventListener('scroll', loadIframeOnScroll);
iframeLoaded = true; // could be placed in the onload callback of the iframe
}
}
window.addEventListener('scroll', loadIframeOnScroll);
document.querySelector('.a').addEventListener('click', loadIframe);
})();
I have a single page site:
http://chiaroscuro.telegraphbranding.com/
Each section is dynamically sized based on the user's window. I'm trying to figure out how to have a jQuery smooth scroll function scroll to the top of each section when the link is clicked. It is working great for the first section, funding areas, where I just used a simple offset().top, but the others are not working because they don't know how far to scroll because the window size is always different.
I've been trying to get offset() or position() to work, but no dice. I appreciate any advice.
Here's my jQuery:
`
$(document).ready(function () {
var slowScrollFunding = $('#funding-areas').offset().top;
var slowScrollAbout = $('#about-us').offset().top;
var slowScrollProjects = $('#our-projects').offset().top + 600;
panelOpen = true;
$('#anchor-funding-areas').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollFunding}, 1000);
};
});
$('#anchor-aboutus').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #aboutus-wrap').animate({scrollTop:slowScrollAbout}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollAbout}, 1000);
};
});
$('#anchor-ourprojects').click(function(event) {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content').stop(true, true).animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
// Scroll down to 'slowScrollTop'
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
panelOpen = false;
});
}else{
$('html, body, #home-wrap').animate({scrollTop:slowScrollProjects}, 1000);
};
});
$('#header-logo').add('.homelink').click(function() {
if(panelOpen == false) {
$('.scrollableArea').css('z-index', '0');
$('#panel-content-container').show();
$('#slide-panel-content').stop(true, true).animate({height: '389px'}, 600, function() {
// Scroll down to 'slowScrollTop'
panelOpen = true;
});
};
});
});
`
$.offset and $.position can be a little unreliable, especially if you have lots of complicated layouts going on - as your page does. What I've used in the past is the following trick:
var de = document.documentElement ? document.documentElement : document.body;
var elm = $('get_your_anchor_element').get(0);
var destScroll, curScroll = de.scrollTop;
/// check for the function scrollIntoView
if ( elm.scrollIntoView ) {
/// get the browser to scrollIntoView (this wont show up yet)
elm.scrollIntoView();
/// however the new scrollTop is calculated
destScroll = de.scrollTop;
/// then set the scrollTop back to where we were
de.scrollTop = curScroll;
/// you now have your correct scrollTop value
$(de).animate({scrollTop:destScroll});
}
else {
/// most browsers support scrollIntoView so I didn't bother
/// with a fallback, but you could just use window.location
/// and jump to the anchor.
}
The above can occur on the click event. The only thing that needs to be improved is that different browsers scroll on different base elements (body or html). When I used this I had my own element that was scrollable so I didn't need to work out which one the agent was using... When I get a second I'll see if I can find a good bit of code for detecting the difference.
The above has worked in all the modern browsers I've tested (Firefox, Safari, Chrome) however I didn't need to support Internet Explorer so I'm not sure with regard to that.
update:
I'm not quite sure what is going on with your implementation - it is possible that the page is so heavy with content that you actually can see the .scrollIntoView() happening - this has never been my experience, but then I didn't have so much going on on-screen. With that in mind, I've implemented a bare bones system that I would advise you use and build each extra part you need into it:
http://pebbl.co.uk/stackoverflow/13035183.html
That way you know you have a working system to start with, and will easily detect what it is that stops it from working. With regards to chiaro.js your implementation seems to be ok - if a little exploded over many different areas of the file - however this part is slightly erroneous:
$('#anchor-aboutus').click(function() {
event.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
elm.scrollIntoView(true).animate({scrollTop:destScroll});
};
});
In the code above you will only get the correct value of destScroll if panelOpen === true. Ahh, actually I've also spotted another problem - which will explain why it's not working:
elm.scrollIntoView(true)
.animate({scrollTop:destScroll}, 1000);
The above code is mixing pure JavaScript and jQuery, the elm var is a normal DOM element (this supports the scrollIntoView method). But you are then attempting to chain the animate method of jQuery into the mix - you should also be triggering the animate method on the element responsible for the scrollbar. What you should use is as follows:
$('#anchor-aboutus').click(function(e) {
var currentScroll, destScroll;
e.preventDefault();
if(panelOpen == true) {
$('#slide-panel-content')
.stop(true, true)
.animate({height: '0px'}, 600, function() {
$('#panel-content-container').hide();
$('.scrollableArea').css('z-index', '11');
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
panelOpen = false;
});
}else{
currentScroll = de.scrollTop;
elm.scrollIntoView(true);
destScroll = de.scrollTop;
de.scrollTop = currentScroll;
$(de).animate({scrollTop:destScroll}, 1000);
};
});
However, what you will also need to do is make sure your de element points to the right element - either html or body depending on the browser - for this you can use this:
var de;
/// calculate which element is the scroller element
$('body, html').each(function(){
if ( this.scrollHeight > this.offsetHeight ) {
de = this;
return false;
}
});
alert( $(de).is('body') ) /// will be true for Chrome, false for Firefox.
You will need to use this code in place of the following code:
var de = document.documentElement ? document.documentElement : document.body;
The reason for changing the code you were using is as follows:
/// store the current scroll position from the de element
currentScroll = de.scrollTop;
/// get the browser to do the scrollTo calculation
elm.scrollIntoView(true);
/// store where the browser scrolled to behind the scenes
destScroll = de.scrollTop;
/// reset our scroll position to where we were before scrollIntoView()
/// if you don't reset then the animation will happen instantaneously
/// because that is what scrollIntoView does.
de.scrollTop = currentScroll;
/// wrap the normal dom element de with jquery and then animate
$(de).animate({scrollTop:destScroll}, 1000);