Change margin top of div based on window scroll - javascript

I have a bar at the top of my page that is position fixed. When the user scrolls to a certain point I want the bar to start moving up as if it was relatively or absolutely positioned.
Right now the css of the bar changes from fixed to absolutely positioned but of course this sets the div straight to the top of the page.
I have been looking at this for ages and cannot get my head around how I would push the bar up one pixel at a time for every pixel scrolled past the _triggerOffset
Can anyone enlighten me?
function banner(){
var _barOffset = $('#top-bar').outerHeight(),
_navOffset = $('#navigation').offset().top,
_triggerOffset = _navOffset-_barOffset;
$(window).scroll(function() {
var _scroll = $(window).scrollTop();
if (_scroll >= _triggerOffset) {
$('#top-bar').css({'position':'absolute'});
}
});
}
banner();

I have done a fiddle.
Check this fiddle
Working Demo
$(document).ready(function() {
var postionToTriggerMove = 500;
var positioninitial = $(window).scrollTop();
var positioninitialLine = $(".line").offset().top;
$(window).scroll(function() {
var _scroll = $(window).scrollTop();
if(_scroll > positioninitial) {
if(_scroll >= (postionToTriggerMove - 5) && _scroll <= (postionToTriggerMove + 5) )
{
var topBarPostion = $(".line").offset().top;
$('.line').css({'position':'absolute',"top":topBarPostion});
}
}
else {
if(_scroll >= (postionToTriggerMove - 5) && _scroll <= (postionToTriggerMove + 5) )
{
var topBarPostion = $(".line").offset().top;
$('.line').css({'position':'fixed',"top":positioninitialLine});
}
}
positioninitial = _scroll;
});
});

You could try something like the below:
function banner(){
var _barOffset = $('#top-bar').outerHeight(),
_navOffset = $('#navigation').offset().top,
_triggerOffset = _navOffset-_barOffset;
$(window).scroll(function() {
var _scroll = $(window).scrollTop();
if (_scroll >= _triggerOffset) {
$('#top-bar').css({'position':'absolute','top':_triggerOffset - (_scroll-_triggerOffset)});
}
});
}
banner();
This code is highly untested, however what we are doing is initially setting the element to an absolute position and defining the top of this element as the _triggerOffset, then we take the difference between the current scroll and the triggerOffset and subtract this from the top position to make the bar move up the more you scroll down.
Not sure if that's what you had in mind, but I'd look at a solution like this. You might want to add some conditions in there to ensure that top never goes below 0 or the nav will go off the screen.

Thanks, had a play around with both examples and they worked pretty good.
In the end I tweaked my code and instead of making the bar position top 0px I made it position top with the pixels equal to the offset distance. Don't know why I didn't think of this before.
On another note I am using Shinov's code for anoher project as I quite like it :)
Thanks
function banner(){
var _barOffset = $('#top-bar').outerHeight(),
_navOffset = $('#navigation').offset().top,
_triggerOffset = _navOffset-_barOffset;
$(window).scroll(function() {
var _scroll = $(window).scrollTop();
if (_scroll >= _triggerOffset) {
$('#top-bar').css({'position':'absolute', 'top':_triggerOffset+'px'});
}else if (_scroll <= _triggerOffset){
$('#top-bar').css({'position':'fixed', 'top':'0px'});
}
});
}

Related

How to re-run an event function after a condition has been met?

I'm trying to have a sidebar scroll at a slower rate until it reaches a certain point. The sidebar is then supposed to stop scrolling as the user reaches that set point. Here's my jQuery code:
$(window).on("scroll", function() {
var sidebar = $('.sidebar');
var stopPoint = $('#stop-point');
var sidebarBottom = sidebar.offset().top + sidebar.height();
var stopPointBottom = stopPoint.offset().top + stopPoint.height() - 30;
if (sidebarBottom > stopPointBottom) {
$('.sidebar').css({'top' : "288px"});
}
else {
$('.sidebar').css({'top' : ($(this).scrollTop()/3)+"px"});
}
});
Everything is working great while the ELSE condition is the case. The issue is when the IF condition is met, then the sidebar stays stuck at its lowest point even if I scroll back up and the ELSE condition is again met.
I'd be grateful if someone could help me understand what I'm doing wrong, and if there's a smarter way to achieve the same.
Thanks in advance.
In case anyone is interested here's how I've fixed it:
$(window).on("scroll", function() {
var sidebar = $('.sidebar');
var stopPoint = $('#stop-point');
var sidebarBottom = sidebar.offset().top + sidebar.height();
var stopPointBottom = stopPoint.offset().top + stopPoint.height() - 30;
$('.sidebar').css({'top' : ($(this).scrollTop()/3)+"px"});
if (($(this).scrollTop()/3) > 284 ) {
$('.sidebar').css({'top' : "284px"});
}
});
When scrolling back to the top the sidebarBottom was bigger by a few pixels than stopPointBottom so the condition was impossible to meet.

How to make an element become fixed when 50px from the top of the screen

I have a html div element that scrolls with the page but I would like it to become fixed once it reaches 50px from the top of the screen...
How is this done?
My div id is #box
Thanks!
-Ina
If you want it to be fixed at the top of the page at some distance from the top, you can check the top offset of the element and change the class when it reach the distance you want.
Here is the jquery code for your reference
jQuery(document).scroll(function() {
var documentTop = jQuery(document).scrollTop();
console.log('this is current top of your document' + documentTop );
//box top is 891
if (documentTop > 841) {
//change the value of the css at this point
jQuery("#box").addClass("stayfix");
}
else
{
jQuery("#box").removeClass("stayfix");
}
});
You need to be more specific about what have you done so far. For eg, how did you make the div element to scrolls inside the page. using css or js/jquery animation features?That will help us to give more specific answer.
**Edited According to your fiddle.
They are right, this question is duplicate. Here is a code I made with answers from the forum.
var box_top = $("#box").offset().top;
$(window).scroll(function (event) {
if ($(window).scrollTop() >= (box_top - 50)) {
$("#box").css({position:"fixed",top:"50px"});
} else {
$("#box").css({position:"relative"});
}
});
Hope it helps anyway.
https://jsfiddle.net/ay54msd5/1/
Try something like this. It's a solution using jquery (hopefully not a problem) that checks the scrollHeight of the page every time the page scrolls. If the scrollHeight is greater than a certain threshold, the element becomes fixed. If not, the element is positioned relatively (but you can do whatever you want in that case.
$(document).ready(function() {
var navFixed = false;
var $box = $("#box");
var topHeight = 50;
$(document).scroll(function() {
if ($(document).scrollTop() >= topHeight && !navFixed) {
$box.css("position", "fixed");
navFixed = true;
}
else if ($(document).scrollTop() < topHeight && navFixed) {
$box.css("position", "relative");
navFixed = false;
}
});
});
You would have to write some additional CSS targeting the #box element that tells it what coordinates you'd like it to be fixed to.

Having the same nav bar become fixed after scrolling past a certain element

I currently have a nav bar within my header that I would like to become fixed after the user scrolls past a certain element. I would also like to achieve the same animation effect as seen at http://pixelmatters.com
When I say 'same' I mean using the same nav bar/header element that I'm using at the top, rather than using a duplicate somewhere else in my document.
I've tried to achieve he result with my own code shown below. I've also included a jsFiddle link of my current setup.
jQuery
var bottomElement = $('.dividerWrap').offset().top + $('.dividerWrap').height();
$(window).on('scoll', function() {
var stop = Math.round($(window).scrollTop());
if (stop > bottomElement) {
$('.header').addClass('isFixed');
} else {
$('.header').removeClass('isFixed');
}
});
https://jsfiddle.net/npfc8wsx/1/
I answered something like that few days ago. please take a look at this code:
$(window).scroll(function () {
var scrollTop = $(window).scrollTop();
var scrollToVid = $('#test').offset().top
console.log(scrollTop); //see window scroll distance //
console.log(scrollToVid); //see scroll to div offest//
if ($(window).scrollTop() >= scrollToVid) {
alert('You reached to the video!');
}
});
jSFiddle
Main Question
now for you some code must change:
$(window).scroll(function () {
var scrollToElem = $('.dividerWrap').offset().top
if ($(window).scrollTop() >= scrollToElem) {
$('.header').addClass('isFixed');
} else {
$('.header').removeClass('isFixed');
}
});

jQuery: Using scroll() and offset() to change background

I am designing a website where the background sits in a div that has a negative z-index with position:fixed. I then have section divs that scroll over it. My goal is to change the background image when each section's top position is passed by the scrollTop function. My jQuery code currently creates an array of each sections top position using:
var secTops = [];
$('section').each(function(i) {
var t = $(this).offset();
secTops.push(t.top);
});
I then thought I would create a variable upon scroll() that was the scrollTop() position like so:
$(window).scroll(function() {
var winTop = $(this).scrollTop();
});
But here is where I am stuck. The best I can come up with (which doesn't work right) is this:
for (i = 0; i < $('section').length; i++) {
var pos = secTops[i];
if (winTop < pos) {
$('#background').css('background', bgFront + (i+1) + bgBack);
} else {
$('#background').css('background', bgFront + (i+2) + bgBack);
};
};
But this isn't right. You can disregard the second half of my .css() function. I've created variables and labeled my images appropriately, so i know that works. Right now, the for loop runs through the entire iteration and is stuck at the full section.length and thus only flips between 2 background images. I need this to constantly check my winTop variable against the top positions of my sections and change the background accordingly. I could do this with a lot of if/then, or maybe even a lengthy switch, but there has to be a cleaner way to do this. Can anyone help me out here?
Here's a JSFiddle that uses colors instead of images but shows the same problems. http://jsfiddle.net/kyleshevlin/5N5WU/1/
this has no chance to work. you need to change it to something like this (this is kinda pseudocode, just to give you a picture:
sections = [];
$(document).ready(function() {
$('section').each(function() {
sections.push($(this))
});
})
$(window).scroll(function() {
var s = $(window).scrolTop();
var currentIndex;
for ( var i = 0; i < sections.length; i++) {
if (( s > sections[i].offset().top) && ( s <= sections[i+1].offset().top)) {
currentIndex = i;
}
}
$('#background').css('background', bgFront + (i+1) + bgBack);
})

Getting Coordinates of an element on page scroll

I am having this problem where i have a set of 6 UL's having a common class x.Each of them consist of a specific section of the page.Now i have 6 menus that are related to each of the section.What i have to do is highlight the menu when its related section is in users view.
For this i thought that may be jQuery position(); or offset(); could have helped but they give the top and left of the element.I also tried using jQuery viewport plugin but apparently view port is big it can show more than one UL at a time hence i cant apply element specific logic here.I am not familliar to this but does anything changes of an element on scrolling?If yes then how to access it?
Please share your views.
Regards
Himanshu Sharma.
Is very easy to do it using jQuery and a dummy fixed HTML block that helps you find the current position of the viewport.
$(window).on("scroll load",function(){
var once = true;
$(".title").each(function(ele, index){
if($(this).offset().top > $("#viewport_helper").offset().top && once){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
once = false;
}
});
})
Check out a working example: http://jsfiddle.net/6c8Az/1/
You could also do something similar with the jQuery plugin, together with the :first selector:
$(window).on("scroll load",function(){
$(".title:in-viewport:first").each(function(){
var index = $(this).index(".title");
$(".current").removeClass('current')
$("#menu li").eq(index).addClass('current')
});
})
You can get the viewport's width and height via $(document).width() and $(document).height()
You can get how many pixels user scrolls via $(document).scrollTop() and $(document).scrollLeft
Combining 1 and 2, you can calculate where the viewport rectangle is
You can get the rectangle of an element using $(element).offset(), $(element).width() and $(element).height()
So the only thing left to you is to determine whether the viewport's rectangle contains (or interacts) the elements's rectangle
So the whole code may look like:
/**
* Check wether outer contains inner
* You can change this logic to matches what you need
*/
function rectContains(outer, inner) {
return outer.top <= inner.top &&
outer.bottom >= inner.bottom &&
outer.left <= inner.left &&
outer.right >= inner.right;
}
/**
* Use this function to find the menu related to <ul> element
*/
function findRelatedMenu(element) {
return $('#menu-' + element.attr('id'));
}
function whenScroll() {
var doc = $(document);
var elem = $(element);
var viewportRect = {
top: doc.scrollTop(),
left: doc.scrollLeft(),
width: doc.width(),
height: doc.height()
};
viewportRect.bottom = viewportRect.top + viewportRect.height;
viewportRect.right = viewportRect.left + viewportRect.width;
var elements = $('ul.your-class');
for (var i = 0; i < elements.length; i++) {
var elem = $(elements[i]);
var elementRect = {
top: elem.offset().top,
left: elem.offset().left,
width: elem.width(),
height: elem.height()
};
elementRect.bottom = elementRect.top + elementRect.height;
elementRect.right = elementRect.left + elementRect.width;
if (rectContains(viewportRect, elementRect)) {
findRelatedMenu(elem).addClass('highlight');
}
}
}
$(window).on('scroll', whenScroll);
Let's see if i understood well. You have a page long enough to scroll, and there is an element that when it appears in the viewport, you wanna do something with it. So the only event that's is triggered for sure on the time the element gets in the viewport is the 'scroll'. So if the element is on the page and the scroll is on the viewport, what you need to do is bind an action to the scroll event to check if the element is in the view each time the event is trigger. Pretty much like this:
$(window).scroll(function() {
check_element_position();
});
Now, in order for you to know if the element is in the viewport, you need 3 things. The offset top of that element, the size of the viewport and the scroll top of the window. Should pretty much look like this:
function check_element_position() {
var win = $(window);
var window_height = win.height();
var element = $(your_element);
var elem_offset_top = element.offset().top;
var elem_height = element.height();
var win_scroll = win.scrollTop();
var pseudo_offset = (elem_offset_top - win_scroll);
if (pseudo_offset < window_height && pseudo_offset >= 0) {
// element in view
}
else {
// elem not in view
}
}
Here, (elem_offset_top - win_scroll) represent the element position if there was no scroll. Like this, you just have to check if the element offset top is higher then the window viewport to see if it's in view or not.
Finally, you could be more precise on you calculations by adding the element height (variable already in there) because the code i just did will fire the event even if the element is visible by only 1 pixels.
Note: I just did that in five minutes so you might have to fix some of this, but this gives you a pretty darn good idea of what's going on ;)
Feel free to comment and ask questions

Categories

Resources