Move element on page as user scrolls up and down - javascript

I am struggling to achieve what should be a simple task.
Page Loads
User freely scrolls down through different sections.
When a specific DIV reaches the centre of the page I would like to pause/prevent scrolling down until the DIV has been moved horizontally across to the left a fixed number of pixels.
Then the user can be allowed to continue scrolling down the page.
Also, I would like to achieve the opposite effect if the user scrolls up i.e. scroll the div to the right a fixed number of pixels before continuing up.
Below is a sample of my code.
$(window).scroll(function() {
sD = $(this).scrollTop();
// $('.features-2-item').width();
if (sD > (f2Pos.top + 100) && sD < f2Pos.top + 2000 + 100) {
// if scroll distance is greater than the top position of
// the statements when they are centred in the viewport,
// and less than the top position of statements centred
// plus the height of 4 statements, prevent user from
// scrolling, then run function to change statements.
sD = f2Pos.top + 100;
var scroll = $(window).scrollTop();
// console.log(('up or down: ' + xSlide + ' > - ' + statementWidth + ' || ' + scroll + ' < ' + position));
if (xSlide > -statementWidth || scroll < position) {
slideStatements();
}
}
if (sD > f2Pos.top + 2000) {
// if scroll distance is greater than the top positon of
// the statements, centred in the viewport, plus the
// height of 4 statements, the user has scrolled through
// all of the statements and should be allowed to resume
// scrolling. Scrolling should be adjusted to take away
// the distance equal to the height of 4 statements.
sD = sD - 2000 + 100;
}
});
var statementWidth = $('.features-2-item').width();
var xSlide = statementWidth;
var position = $(window).scrollTop();
function slideStatements() {
var st = $(this).scrollTop();
if (st > lST) {
// Going Down
if (cS) {
// disallow scrolling until after statement slides
cS = false;
xSlide = Math.floor(xSlide + 32);
$(window).one('scroll.slideStatements', function() {
$(".features-2-container").css("transform", "translateX(" + xSlide + "px)");
});
// allow scrolling after statement slides
cS = true;
}
} else {
// Going Up
if (cS) {
// disallow scrolling until after statement slides
cS = false;
xSlide = Math.floor(xSlide - 32);
$(window).one('scroll.slideStatements', function() {
// $sS.slick("slickPrev");
$(".features-2-container").css("transform", "translateX(" + xSlide + "px)");
});
// allow scrolling after statement slides
cS = true;
}
}
lST = st - 1;
}
Any suggestion swould be great.
regards

Hi I'm not an expert here but I would like to share my method.
In my opinion the hardest part is how to prevent the scrolling. So we are not going to prevent it, instead we are going to take some advantage of it.
Let's say we have 3 sections like
<section>...</section>
<section class='stuart'>
<div class='kevin'></div>
</section>
<section>...</section>
And style like
.stuart {
height: 600px;
}
.kevin {
position: absolute;
width: 50px;
height: 50px;
background: tomato;
}
So stuart is a our container and kevin is a box inside.
Our goal is simple, when kevin goes up and pass the middle of window we will keep it at that middle (vertical) and move it from left to right (horizontal) until the end of stuart pass.
Code will be like
if (stuart.top < windowHeight / 2 &&
stuart.top + stuart.height - kevin.height > windowHeight / 2) {
let distance = windowHeight / 2 - stuart.top
kevin.classList.add('fixed')
kevin.style.left = distance + 'px'
}
The important part is the distance which always relate to the position of stuart, so you will no need to do anything about opposite effect.
Final example here.
Bad news, you need to calculate the height of container by yourself or a fixed position may not work in your case or other things but I hope this idea will help you in some way. Thanks.

Related

How to check bottom of child div touching parent bottom

i'm trying to change position of a child element(with varying height based on text) using range input,i would like to stop applying top position once the child div touches the bottom of the parent having fixed height.
$('#change_position').on('input', function () {
var val = +$(this).val(),
ScrSize = parseInt($('.screen').css('height')),
Stop = $('.screentip').offset().top,
h = parseInt($('.screentip').css('height')),
tofsset = Stop - h;
if (tofsset < ScrSize) {
$('.screentip').css('top', val + "%");
}
});
The height you are expecting jQuery to return is actually a string with the ending "px". You can use the function .height(). This will return you the height of the element as integer. I have tried a slightly modiefied version of your code:
$('#input').on('input', function () {
var val = parseInt($(this).val()),
ScrSize = parseInt($('#container').height()),
TxtSize = parseInt($("#text").height()),
Stop = ScrSize - TxtSize,
valInPixel = ScrSize * val / 100;
if (valInPixel < Stop) {
$('#text').css('top', val + "%");
}
else
{
$("#text").css("top", Stop + "px");
}
});
The else part will position your element to the bottom, if the number exceeds the frame. You may also have to be aware of padding and margin. This could also lead to mispositioning.
Hope this helps.

run animation once while scroll down and up

I am working on one project and i am having difficultly to solve this issue. Here is problem:- When user scroll down and lime color div visible animation will start. when user scroll up animation will stop. But real problem is animation running multiple times when lime color div visible. I want to run animation only once when lime color div visible. Please see jsfiddle demo.
Here is javascript code snippet.
function scollPosition(){
var sotpScroll = 0;
$(window).scroll(function(){
if(sotpScroll == 0){
sotpScroll = 1;
var cPosition = $('.c').offset();
var animationStartPoint = cPosition.top - 100;
console.log(animationStartPoint);
// console.log('c class position' + cPosition.top);
var dPosition = $('.d').offset();
// console.log('d class position' + dPosition.top);
var windowPosition = window.pageYOffset;
console.log('window position:- ' + windowPosition + ' dPosition.top:- ' + dPosition.top);
if (windowPosition > animationStartPoint && windowPosition < dPosition.top){
animation();
}
}
setTimeout(function(){sotpScroll=0},10);
});
}
Thankx in advance and apologies for my english. Please help me to solve this bug
Add a global flag that indicates if the area is visible or not:
var areaVisible
[...]
if (windowPosition > animationStartPoint && windowPosition < dPosition.top) {
// Area is visible
if (!areaVisible) { // If just became visible
animation();
}
areaVisible = true; // Prevent more animations
} else {
areaVisible = false;
}
Fiddle: http://jsfiddle.net/bortao/BB2k5/

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!

How to determine if vertical scroll bar has reached the bottom of the web page?

The same question is answered in jQUery but I'm looking for solution without jQuery.
How do you know the scroll bar has reached bottom of a page
I would like to know how I can determine whether vertical scrollbar has reached the bottom of the web page.
I am using Firefox3.6
I wrote simple Javascript loop to scroll down by 200 pixel and when the scroll bar reached the bottom of the page, I want to stop the loop.
The problem is scrollHeight() is returning 1989.
And inside loop scrollTop is incremented by 200 per iteration.
200 ==> 400 ==> 600 .... 1715
And from 1715, it won't increment so this loop continues forever.
Looks like scrollHeight() and scrollTop() is not right way to compare in order to determine the actual position of scrollbar? How can I know when the loop should stop?
code:
var curWindow = selenium.browserbot.getCurrentWindow();
var scrollTop = curWindow.document.body.scrollTop;
alert('scrollHeight==>' + curWindow.document.body.scrollHeight);
while(curWindow.document.body.scrollHeight > curWindow.document.body.scrollTop) {
scrollTop = curWindow.document.body.scrollTop;
if(scrollTop == 0) {
if(window.pageYOffset) { //firefox
alert('firefox');
scrollTop = window.pageYOffset;
}
else { //IE
alert('IE');
scrollTop = (curWindow.document.body.parentElement) ? curWindow.document.body.parentElement.scrollTop : 0;
}
} //end outer if
alert('current scrollTop ==> ' + scrollTop);
alert('take a shot here');
selenium.browserbot.getCurrentWindow().scrollBy(0,200);
} //end while
When you tell an element to scroll, if its scrollTop (or whatever appropriate property) doesn't change, then can't you assume that it has scrolled as far as is capable?
So you can keep track of the old scrollTop, tell it to scroll some, and then check to see if it really did it:
function scroller() {
var old = someElem.scrollTop;
someElem.scrollTop += 200;
if (someElem.scrollTop > old) {
// we still have some scrolling to do...
} else {
// we have reached rock bottom
}
}
I just read through the jQuery source code, and it looks like you'll need the "pageYOffset". Then you can get the window height and document height.
Something like this:
var yLeftToGo = document.height - (window.pageYOffset + window.innerHeight);
If yLeftToGo is 0, then you're at the bottom. At least that's the general idea.
The correct way to check if you reached the bottom of the page is this:
Get document.body.clientHeight = the height of the ACTUAL screen shown
Get document.body.offsetHeight or document.body.scrollHeight = the height of the entire page shown
Check if document.body.scrollTop = document.body.scrollHeight - document.body.clientHeight
If 3 is true, you reached the bottom of the page
function scrollHandler(theElement){
if((theElement.scrollHeight - theElement.scrollTop) + "px" == theElement.style.height)
alert("Bottom");
}
For the HTML element (like div) add the event -- onscroll='scrollHandler(this)'.
Here is some code I've used to power infinite scrolling list views:
var isBelowBuffer = false; // Flag to prevent actions from firing multiple times
$(window).scroll(function() {
// Anytime user scrolls to the bottom
if (isScrolledToBottom(30) === true) {
if (isBelowBuffer === false) {
// ... do something
}
isBelowBuffer = true;
} else {
isBelowBuffer = false;
}
});
function isScrolledToBottom(buffer) {
var pageHeight = document.body.scrollHeight;
// NOTE: IE and the other browsers handle scrollTop and pageYOffset differently
var pagePosition = document.body.offsetHeight + Math.max(parseInt(document.body.scrollTop), parseInt(window.pageYOffset - 1));
buffer = buffer || 0;
console.log(pagePosition + "px / " + (pageHeight) + "px");
return pagePosition >= (pageHeight - buffer);
}
<span id="add"></add>
<script>
window.onscroll = scroll;
function scroll () {
if (window.pageYOffset + window.innerHeight >= document.body.scrollHeight - 100) {
document.getElementById("add").innerHTML += 'test<br />test<br />test<br />test<br />test<br />';
}
}
</script>

Categories

Resources