I'm trying to create a simple scroll effect where the page header hides when the page scrolls down and reappears on scroll up. The HTML:
<header class="siteHeader">...</header>
...is hidden by applying the CSS class "siteHeader--up."
I'm using jQuery. Here is my code:
$(function () {
var $siteHeader = $('.siteHeader');
var $window = $(window);
// to determine scroll direction. initializes to 0 on page load
var scrollReference = 0;
function fixedHeader () {
var scrollPosition = $window.scrollTop();
// if page is scrolling down, apply the CSS class
if (scrollPosition > scrollReference)
{
$siteHeader.addClass('siteHeader--up');
}
// otherwise, page is scrolling up. Remove the class
else
{
$siteHeader.removeClass('siteHeader--up');
}
// update reference point to equal where user stopped scrolling
scrollReference = scrollPosition
}
$window.scroll(function () {
fixedHeader();
});
});
This works fine for the most part. The problem is when I scroll down the page and then refresh the page. Somehow the scroll function is being triggered. The header will be visible for a moment and then hide (as though the page thinks it's being scrolled down). The function is being triggered on page load (confirmed with a console.log), but I don't understand why, because it's only supposed to fire on scroll.
Can someone help me understand what's going on and how I can prevent it?
Thanks!
That is the expected behavior. When the page is refreshed, the browser remembers the scroll position and it scrolls the page to that position, later on the scroll event is fired.
I think that this could be a workaround to solve your problem:
When the jQuery scroll event is fired you can get the timeStamp property and if this timeStamp is very close to the window.onload timeStamp, surely it can't be an event triggered by the user:
I've used a value of 50 milliseconds, test if it is sufficient, I think that it is.
var startTime = false;
$(function () {
var $siteHeader = $('.siteHeader');
var $window = $(window);
// to determine scroll direction. initializes to 0 on page load
var scrollReference = 0;
function fixedHeader () {
var scrollPosition = $window.scrollTop();
// if page is scrolling down, apply the CSS class
if (scrollPosition > scrollReference)
{
$siteHeader.addClass('siteHeader--up');
}
// otherwise, page is scrolling up. Remove the class
else
{
$siteHeader.removeClass('siteHeader--up');
}
// update reference point to equal where user stopped scrolling
scrollReference = scrollPosition
}
$window.on("load", function (evt) {
startTime = evt.timeStamp;
});
$window.on("scroll", function (evt) {
if(!startTime || evt.timeStamp - startTime < 50) return;
fixedHeader();
});
});
Try Loading the function on window load as well as in the scroll function:
$window.load(function(){
fixedHeader();
});
Or on document ready maybe:
$(document).ready(function () {
fixedHeader();
});
This should trigger and reset the values in the Variables you made and therefore determine whether to set the header to fixed or not, regardless of the scroll position.
Let me know if it works because i'm kinda curious too :)
Related
I have a javascript that enables autorotating tabs on my website. my tabs are in the bottom of the page and by the moment when you reach this section almost the last tab is opened so the portfolio sort of starts not from the first item.
is there a way to enable this script only when the section with tabs scrolls into view?
the code snippet is here:
<script>
var Webflow = Webflow || [];
Webflow.push(function() {
var tabTimeout;
clearTimeout(tabTimeout);
tabLoop();
// define loop - cycle through all tabs
function tabLoop() {
tabTimeout = setTimeout(function() {
var $next = $('.tabs-menu').children('.w--current:first').next();
if ($next.length) {
$next.removeAttr("href").click(); // click resets timeout, so no need for interval
} else {
$('.tab-link:first').removeAttr("href").click();
}
}, 15000);
}
// reset timeout if a tab is clicked
$('.tab-link').click(function() {
clearTimeout(tabTimeout);
tabLoop();
});
});
</script>
Detect how much the user has scrolled from top to determine when to run the function.With JavaScript:
var scrollTop = window.pageYOffset || (document.documentElement || document.body.parentNode || document.body).scrollTop;With jQuery:
var scrollTop = $(window).scrollTop();
Compare scrollTop with the position of the parent element of your Tabs.Here is a method to get that, if you need to calculate it:
How can I get an object's absolute position on the page in Javascript?
I have a long list of items and when I clicked into each item and return to the main list, the scroll position was lost.
How can I return to the same exact scroll position using jQuery? Is there any easy way to do it?
$(document).ready(function() {
$('.update-button').click(function (){
sessionStorage.scrollPos = $(window).scrollTop();
console.log(sessionStorage.scrollPos);
});
});
var init = function () {
//get scroll position in session storage
$(window).scrollTop(sessionStorage.scrollPos || 0)
};
window.onload = init;
Above is what my code looks like. I tried to log the position and sessionStorage.scrollPos was 0. I am pretty sure I scrolled the page to somewhere.
Help is greatly appreciated.
You need to store value of scroll position in sessionStorage (or any storage) and re use it again on page load.
$(window).scroll(function () {
//set scroll position in session storage
sessionStorage.scrollPos = $(window).scrollTop();
});
var init = function () {
//get scroll position in session storage
$(window).scrollTop(sessionStorage.scrollPos || 0)
};
window.onload = init;
Just modifying #Rayon Answer if it doesn't work someone.
$("body").on("scroll", function () {
//set scroll position in session storage
sessionStorage.scrollPos = $(window).scrollTop();
});
var init = function () {
//get scroll position in session storage
$("body").scrollTop(sessionStorage.scrollPos || 0)
};
window.onload = init;
You can replace the $("body") with the top most element in your HTML. I am using framework7 mobile applicaiton and I need to use $(".page-content"). It worked for me.
No easy solution, but on the click event where the redirect takes place, get the current scroll position using
var scroll = $(window).scrollTop();
Then store the value of the scroll variable into the localstorage (cookies if localstorage is not available).
Then on page load look for the scroll position from local storage if available and if so move to that position.
this work for readmore article or hide article, for get current position height of readmore clicked.
#note: you need toggle button readmore and hide
let readhide = document.querySelectorAll('.read-hide');
let readmore = document.querySelectorAll('.read-more');
readmore.forEach((more,key) => {
let height, moreHeight;
window.addEventListener('scroll', function(event){
height = Math.floor(event.target.scrollingElement.scrollTop);
});
more.addEventListener('click', function(){
moreHeight = height;
});
readhide[key].addEventListener('click', function(){
window.scrollTo(0, moreHeight);
});
});
Return Text
Try This.
<button onclick="goBack()">Go Back</button>
function goBack() {
window.history.go(-1);
}
I am trying to detect a scroll on my page using JavaScript. So that I can change classes and attributes of some elements when user has scrolled certain amount of page. This is my JS function:
function detectScroll() {
var header = document.querySelector(".headerOrig"),
header_height = getComputedStyle(header).height.split('px')[0],
fix_class = "changeColor";
if( window.pageYOffset > header_height ) {
header.classList.add(fix_class);
}
if( window.pageYOffset < header_height ) {
header.classList.remove(fix_class);
}
var change = window.setInterval(detectScroll, 5000);
}
and I am calling it when the page is loaded:
<body onload="detectScroll();">
However, I have this problem - I need to set up a really small interval so that the function gets called and the class is changed immediately. BUT then the page freezes and everything except the JS function works very slowly.
Is there any better way of achieving this in JavaScript?
Thanks for any advice/suggestion.
You are going to want to change a couple things. First, we can use onscroll instead of an interval. But you are also going to want to cache as much as possible to reduce the amount of calculations on your scroll. Even further, you should use requestAnimationFrame (or simply "debounce" in general for older browsers -- see the link). This ensures your work only happens when the browser is planning on repainting. For instance, while the user scrolls the actual scroll event may fire dozens of times but the page only repaints once. You only care about that single repaint and if we can avoid doing work for the other X times it will be all the more smoother:
// Get our header and its height and store them once
// (This assumes height is not changing with the class change).
var header = document.querySelector(".headerOrig");
var header_height = getComputedStyle(header).height.split('px')[0];
var fix_class = "changeColor";
// This is a simple boolean we will use to determine if we are
// waiting to check or not (in between animation frames).
var waitingtoCheck = false;
function checkHeaderHeight() {
if (window.pageYOffset > header_height) {
header.classList.add(fix_class);
}
if (window.pageYOffset < header_height) {
header.classList.remove(fix_class);
}
// Set waitingtoCheck to false so we will request again
// on the next scroll event.
waitingtoCheck = false;
}
function onWindowScroll() {
// If we aren't currently waiting to check on the next
// animation frame, then let's request it.
if (waitingtoCheck === false) {
waitingtoCheck = true;
window.requestAnimationFrame(checkHeaderHeight);
}
}
// Add the window scroll listener
window.addEventListener("scroll", onWindowScroll);
use onscroll instead of onload so you don't need to call the function with an interval.
Your dedectScroll function will be triggered automatically when any scroll appers if you use onscroll
<body onscroll="detectScroll();">
Your function is adding an interval recursively, you should add an event listener to the scroll event this way :
function detectScroll() {
var header = document.querySelector(".headerOrig"),
header_height = getComputedStyle(header).height.split('px')[0],
fix_class = "changeColor";
if( window.pageYOffset > header_height ) {
header.classList.add(fix_class);
}
if( window.pageYOffset < header_height ) {
header.classList.remove(fix_class);
}
}
window.addEventListener("scroll",detectScroll);
I'm currently trying to change my header logo when the user scrolls past the dark background to a lighter background. I got the add/remove class working, but right when the user loads the page the image doesn't show because it executes when the scroll is greater than 0 pixels scroll. How do I show the initial conditions from page load without the user having scrolled already?
$(function() {
var header = $(".logo");
var about = $(".angle").offset().top;;
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= about) {
header.removeClass('lightLogo').addClass('darkLogo');
} else {
header.removeClass('darkLogo').addClass('lightLogo');
}
});
});
The simplest might be to just add the class initially, like so:
$(function() {
var header = $(".logo").addClass('lightLogo');
var about = $(".angle").offset().top;;
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= about) {
header.removeClass('lightLogo').addClass('darkLogo');
} else {
header.removeClass('darkLogo').addClass('lightLogo');
}
});
});
Now the header will start out with .lightLogo at page load.
I've been working on a scroll to top function for my website, and that part of it works fine. My problem is however that I have a fixed div that is overlapping my footer when it hits the bottom of the page.
Here is the function that I have working.
$(document).scroll(function (e) {
if (document.body.scrollTop >= 800) {
$('#beamUp').show(1000);
} else {
$('#beamUp').hide(1000);
return false;
}
});
Is there somehow I could detect when I hit that part of the page and stop the div from moving past that.Help is much appreciated!
jsFiddle: http://jsfiddle.net/zazvorniki/RTDpw/
Just get the height of the page, minus the height of the div in question, as well as the footer... make sure the top is never greater than that value... you'll also need an onresize event handler re-evaluate that value.
looking at your jsfiddle... here are my edits
In your scroll listener, I am checking for the position of the page, and adjusting the bottom position of the floater appropriately. I also set the initial display:none, so you don't need to call .hide() in your initial script. In addition, resizing the window has the effect of scrolling for your use, so I changed the listener for both events.
$(document).on('scroll resize', function (e) {
var viewHeight = $(window).height();
var viewTop = $(window).scrollTop();
var footerTop = $("footer").offset().top;
var baseline = (viewHeight + viewTop) - footerTop;
var bu = $("#beamUp").css({bottom: (baseline < 0 ? 0 : baseline) + 'px'});
if (viewTop >= 50) {
bu.show(1000);
} else {
bu.hide(1000);
}
});