Change scrollTop offset when scrolling up, and different offset on scrollDown - javascript

I got an issue, where I have an dynamic header that gets bigger when scrolling up and smaller when scrolling down and therefore needs to change scrollTop offsets.
So i've been looking around and tried with my no existent java skills with no success.
This jquery code:
$(document).on('click', 'a[href^="#"]', function(e) {
var id = $(this).attr('href');
var $id = $(id);
if ($id.length === 0) {
return;
}
e.preventDefault();
// top position relative to the document
var pos = $(id).offset().top-500; // move this one
$('body, html').animate({scrollTop: pos});
});
var iScrollPos = 0;
$(window).scroll(function () {
var iCurScrollPos = $(this).scrollTop();
if (iCurScrollPos > iScrollPos) {
var pos = $(id).offset().top-500; //here when scrolling down
} else {
var pos = $(id).offset().top-100; // Here when scrolling up
}
iScrollPos = iCurScrollPos;
});
I made a JS fiddle to show what I'm trying to achieve: https://jsfiddle.net/zq9y7nge/1/
So, Is it possible to change offset depending on scrolling up and down?

Related

Add class when element is at top of window

I'm trying to create sticky headers that when you scroll to a div the head state becomes fixed and stays in view, when the div has come to an end and scrolls out of view I want the title to then become absolute and stay at the bottom of its parent.
I've got the initial part working only I'm struggling on adding the 'absolute' class...
https://jsfiddle.net/yw313vf2/1/
function fixTitle() {
$('.service-pane').each(function() {
var $this = $(this);
var offset = $this.offset().top;
var scrollTop = $(window).scrollTop();
if (scrollTop > offset) {
$this.addClass('fixed');
} else {
$this.removeClass('fixed');
}
});
}
$(window).scroll(fixTitle);
So I had to run another check within the function to see if when scrolled the end of my div had reached the top of the window and if so add an additional class...
function fixTitle() {
$('.service-pane').each(function() {
var $this = $(this);
var offset = $this.offset().top - 50;
var scrollTop = $(window).scrollTop();
if (scrollTop > offset) {
$this.addClass('fixed');
if ($this[0].getBoundingClientRect().bottom < $('.manifesto').height() + 50) {
$this.addClass('absolute');
} else {
$this.removeClass('absolute');
}
} else {
$this.removeClass('fixed');
}
});
}

jQuery: clone div multiple times on scroll

I'm trying to figure out how to repeatedly clone the contents of a div on scroll, thus giving the impression that the page goes on forever and ever. My markup thus far is as follows and a fiddle here too https://jsfiddle.net/guht49La/:
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800 && inserated == false) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
inserated = true;
} else {
}
});
Although this only inserts it once, as I want to keep inserting it every 800px (for example) thus giving the impression that the page goes on forever and ever. Any suggestions on this would be greatly appreciated!
This will work
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
inserated = true;
} else {
}
});
This is a complete guess, but perhaps give this a go:
var nextInsert = 800;
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= nextInsert) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
nextInsert += 800;
} else {
}
});
It is working, but it clones the div just once because you changed the inserated variable to true after inserting the first clone. It will work indefinitely if you delete it:
var inserated = false
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800 && inserated == false) {
var $button = $('.hd').clone();
($button).insertBefore('.ap');
// inserated = true;
} else {
}
});
Notice that inserated = true; is commented out.
That code, however, can (and almost certainly) creates a huge amount of clones, so I'd suggest controlling the scrolling insertion point using something along the lines of Nat Karmios answer
My suggestion is similar to jbmartinez answer, except I would drop the inserated variable altogether and use classes to determine elements to be cloned:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 800) {
var $button = $('.hd').not(".cloned").clone();
$button.addClass("cloned");
($button).insertBefore('.ap');
} else {
}
});
Would still need to adjust the scrolling mark as noted above tho.

Turning jQuery event listener on after off

So I want to turn off a jQuery event under a certain condition (if the user scrolls down) but if they do the opposite (scroll up) then I want the event turned to on so that it will fire.
This is my code but as I am new to jQuery, I am pretty sure I'm missing something in the handler - I just don't know what it should be.
Here is the code:
function myFunction() {
var handler = function(e){
//code here
}
var position = $(window).scrollTop();
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if(scroll > position) {
// scrolling downwards
$(window).off("scroll", handler);
}
if(scroll < position) {
//scrolling upwards
$(window).on("scroll", handler);
hypeDocument.showPreviousScene(hypeDocument.kSceneTransitionPushTopToBottom, 1.1)
}
position = scroll;
});
}
try using an if-else statement instead of two ifs
$(function()
{
var handler = function(e){
// hypeDocument.showPreviousScene(hypeDocument.kSceneTransitionPushTopToBottom, 1.1)
console.log('handler');
}
var position = $(window).scrollTop();
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll > position) {
// scrolling downwards
// NOTHING
}
if(scroll < position) {
//scrolling upwards
handler();
}
position = scroll;
});
});
Open console and you'll see "handler" in output each time you scroll up.
You need to add scroll handler after document.ready event:
$(function() {
/* YOUR CODE HERE */
});
I think you doing wrong trying to subscribe and unsubscribe your handler.
You should just determine the direction of scroll as you do.
Then if it is right direction – call your handler:
if (scroll < position) {
//scrolling upwards
handler();
}
Update 3: in future you could do this instead.
var nT = $(window).scrollTop, pos = nT(), func = function(e){ /*code here*/ };
$(window).scroll(()=>(nT()<pos)&&(pos=nT(),func())); //make people hate you.
Update 2: and to make it even smaller..
var newTop = $(window).scrollTop, position = newTop(),
handler = function(e){ /*code here*/ };
$(window).scroll(function() {
(newTop()<position)&&(position=newTop(),handler());
});
Update: Or you could make it even better
var newTop = $(window).scrollTop, position = newTop();
var handler = function(e){
//code here
};
$(window).scroll(function() {
var scroll = newTop();
if(scroll < position) handler();
position = scroll;
});
Use Boolean variable instead of attaching/detaching event.
var disabled= false,
newTop = $(window).scrollTop,
position = newTop();
var handler = function(e){
if (disabled) return;
//code here
};
$(window).scroll(function() {
var scroll = newTop();
if(scroll > position) disabled=true;
else disabled=false;
position = scroll;
});

Sticky Sidebar that only sticks when sidebar bottom is at window bottom

I have a 2 column layout. The left column is way longer than the sidebar. I want the sidebar only to stick when its bottom reaches the bottom of the browser window. So the user can continue to scroll down the left column content while the right sidebar sticks. I've seen a lot of sticky questions here, however this particular situation still stumps me. I also have a sticking headline bar on the left column that i've successfully gotten to stick.
Here's a demo of what I've done in jsfiddle!
and here's a quick look at the js I am trying out.
$(function(){
var headlineBarPos = $('.headlineBar').offset().top; // returns number
var sidebarHeight = $('.sticky-sidebar-wrap').height();
var sidebarTop = $('.sticky-sidebar-wrap').offset().top;
var windowHeight = $(window).height();
var totalHeight = sidebarHeight + sidebarTop;
$(window).scroll(function(){ // scroll event
var windowTop = $(window).scrollTop(); // returns number
// fixing the headline bar
if (headlineBarPos < windowTop) {
$('.headlineBar').addClass('sticky').css('top', '0');
}
else {
$('.headlineBar').removeClass('sticky').removeAttr('style');
}
if(sidebarHeight < windowTop) {
$('.sticky-sidebar-wrap').addClass('sticky').css('top', '0');
} else {
$('.sticky-sidebar-wrap').removeClass('sticky').removeAttr('style');
}
console.log(windowTop);
});
console.log(headlineBarPos);
console.log(sidebarHeight);
console.log(sidebarTop);
});
I hope I got it right, when the bottom of the sidebar comes into the view, then stick?
I created another div at the bottom of the sidebar (inside the sidebar).
When that comes into view, it sticks.
http://jsfiddle.net/Z9RJW/10/
<div class="moduleController"></div> //inside the sidebar
and in js
$(function () {
var headlineBarPos = $('.headlineBar').offset().top; // returns number
var moduleControllerPos = $('.moduleController').offset().top; // returns number
var sidebarHeight = $('.sticky-sidebar-wrap').height();
var sidebarTop = $('.sticky-sidebar-wrap').offset().top;
var windowHeight = $(window).height();
var totalHeight = sidebarHeight + sidebarTop;
$(window).scroll(function () { // scroll event
var windowTop = $(window).scrollTop(); // returns number
// fixing the headline bar
if (headlineBarPos < windowTop) {
$('.headlineBar').addClass('sticky').css('top', '0');
} else {
$('.headlineBar').removeClass('sticky').removeAttr('style');
}
if (moduleControllerPos < windowTop + windowHeight) {
$('.sticky-sidebar-wrap').addClass('sticky').css('top', '0');
} else {
$('.sticky-sidebar-wrap').removeClass('sticky').removeAttr('style'); }
console.log(windowTop);
});
console.log(headlineBarPos);
console.log(sidebarHeight);
console.log(sidebarTop);
});
I hope it helps.
Something like:
if (sidebar.top + sidebar.height < window.scrolltop + window.height) {
// set sticky
}
and set sticky needs to take into account that the sidebar may be higher than the viewport, so:
sidebar.top = sidebar.height - window.height // this will be a negative number

Getting a floating div to stop upon reaching another div

I have a floating div on the sidebar that scrolls with the page. Is there a way to add code that makes it stop when it reaches the footer?
See code in action: http://openbayou.staging.wpengine.com
jQuery code used to float div:
$j=jQuery.noConflict();
$j(document).ready(function($) {
//this is the floating content
var $floatingbox = $('#one');
if($('#primary').length > 0){
var bodyY = parseInt($('#primary').offset().top) - 20;
var originalX = $floatingbox.css('margin-left');
$(window).scroll(function () {
var scrollY = $(window).scrollTop();
var isfixed = $floatingbox.css('position') == 'fixed';
if($floatingbox.length > 0){
$floatingbox.html();
if ( scrollY > 1561 && !isfixed ) {
$floatingbox.stop().css({
position: 'fixed',
top: 10,
});
} else if ( scrollY < 1561 && isfixed ) {
$floatingbox.css({
position: 'relative',
top: 0,
});
}
}
});
}
});
Why not just set the z-index of the sidebar behind the z-index of the footer?
EDIT: I didn't like the result of this so I went and made this work in jquery the way you want it...
try this for your scroll function:
$(window).scroll(function () {
floatingbox = $("#one");
if(floatingbox.length > 0){
//get our current scroll position
var scrollY = $(window).scrollTop();
//get the position of the tag cloud relative to the document
var contentY = ($("#sidebar .sidebar-tag-cloud").offset().top + $("#sidebar .sidebar-tag-cloud").outerHeight(false));
//calculate the largest possible top margin size before it starts to overlap the footer
var lastY = $("#footer").offset().top - $("#one").outerHeight(false);
//check if our scroll location is past the bottom of the tag cloud
if ( scrollY > contentY )
{
//check if the current top position is less than the maximum position
if(floatingbox.offset().top<lastY)
{
//keep scrolling
floatingbox.stop().animate({"marginTop":scrollY-contentY});
}else
{
//check if we have scrolled back up and have a space at the top
if(scrollY<floatingbox.offset().top)
{
floatingbox.stop().animate({"marginTop":scrollY-contentY});
}else
{
// hard set to the maximum position
floatingbox.stop().css({"marginTop":lastY-contentY});
}
}
}
}
});
I also made it a little more dynamic by getting the location of the bottom of the tag cloud and using that instead of your hard-coded number.
Alright, after looking at your latest jsfiddle. I have modified that code to work with yours. http://jsfiddle.net/Tgm6Y/4430/ This will not have the animate lag and should work well for you.
$('#one').followTo('#two','#pointFive');
just replace #two with #footer and #pointFive with "#sidebar .sidebar-tag-cloud" and this should work in your code.
UPDATE: Found a solution to my problem.
$(function () {
var msie6 = $.browser == 'msie' && $.browser.version < 7;
if (!msie6) {
var top = $('#one').offset().top;
$(window).scroll(function (event) {
var y = $(this).scrollTop() + 20;
if (y >= top) {
$('#one').addClass('fixed');
}
else {
$('#one').removeClass('fixed');
}
// don't overlap the footer - pull sidebar up using a negative margin
footertotop = ($('#footer').position().top);
scrolltop = $(document).scrollTop() + 760;
difference = scrolltop - footertotop;
if (scrolltop > footertotop) {
$('#one').css('margin-top', 0 - difference);
}
else {
$('#one').css('margin-top', 0);
}
});
}
});
What this does is it stops before the footer and I can configure the stopping point.
I appreciate all the help in solving my problem!

Categories

Resources