jQuery fixed sidebar that moves with content if overflow - javascript

I have the following fiddle: http://jsfiddle.net/yFjtt/1/
The idea is that the user can scroll PAST the header to make the sidebar 'stick' in place while they scroll further down the page.
As they near the bottom of the page it should then work out how much space is left and how much space the sidebar needs and the add some negative margin to move the sidebar upwards whilst maintaining the fixed position.
Upto here it all works fine.
The next problem is making sure that the sidebar only moves up as far as it needs to and should remain about 10 pixels from the bottom. This way the sidebar will be fixed until it needs to move upward to reveal its content and then once it's all shown become stuck again about 10 pixels from the bottom.
Here is where I have tried to achieve this (see fiddle for full code):
if( $(window).scrollTop() > (documentHeight - sidebarHeight) ) {
if( offsetBottom < 10) {
}
else {
$('div.sidebar').stop(true,false);
$('div.sidebar').animate({'margin-top':offset}, 300);
}
} else {
$('div.sidebar').stop(true,true);
$('div.sidebar').css({'margin-top':'0'});
}
However the sidebar STILL moves too far up the page... Can anyone help? I'm sure it's just a simple mistake working out the offset from the bottom.

I think you had a good try, except I'm not sure what those animations are doing there. Basically you need 3 checks, first to see if the use is above the header, second to check if they're between the header and the bottom most limit for the sidebar, and lastly if they're below that point. Then simply swap and change classes and modify top value as necessary.
jsFiddle
var sidebarHeight = $('div.sidebar').height();
var documentHeight = $(document).height();
var headerHeight = $('div.header').height();
$(window).scroll(function() {
var margin = 10;
var sidebar_offset = documentHeight - sidebarHeight - (margin * 2); // double margin to account for top and bottom margins
if ($(window).scrollTop() > headerHeight && $(window).scrollTop() < sidebar_offset ) {
// below header, but above the sidebar offset limit
$('div.sidebar').addClass('fixed');
$('div.sidebar').css('top', '');
}
else if ( $(window).scrollTop() <= headerHeight ) {
// above header
$('div.sidebar').removeClass('fixed');
$('div.sidebar').css('top', '');
}
else {
// past the sidebar offset limit
$('div.sidebar').removeClass('fixed');
$('div.sidebar').css('top', documentHeight - sidebarHeight - margin);
}
});​

Related

Fixed Side Bar with appearing image

I've got my side bar working almost as I want it, but am having issues at certain page heights:
The side bar should work as follows:
When the "menu" hits the top of the page, an image appears about the menu and the entire side is fixed - working!
If the footer collides with the bottom of the sidebar when fixed, it starts to scroll up - working!
If the window height is smaller than the sidebar height, it never fixes - not quite working.
For point 3, there is an area of about 170 pixels between 581px and 751px (height) where the sidebar starts to jump around. In the example, if the browser height is ~580 or less then it works fine, but if it falls into that zone it starts to become jittery.
I've mimicked the behaviour here:
https://jsbin.com/wokupacebu/edit?html,css,js,console
doesn't quite fit the window sizes in jsbin, so to see a full screen working copy, see here:
https://output.jsbin.com/wokupacebu
here's my JS - the CSS and HTML can be found in the jsbin.
$(function() {
$sideBarContainer = $("#side-bar-container");
$sideBar = $("#side-bar");
$sideImageContainer = $("#side-image-container");
$sideImage = $("#side-image")
$footer = $("#footer");
$window = $(window);
$(window).on("scroll.sidebar resize.sidebar",function() {
setSideBarFixable();
});
function setSideBarFixable() {
if ($window.height() < $sideBar.height() + $sideImage.outerHeight()) {
$sideBar.removeClass("fixed");
$sideBarContainer.css("width","auto");
$sideImageContainer.css("height","0");
return;
} else {
if ($window.scrollTop() >= $sideBarContainer.position().top) {
$sideBar.addClass("fixed");
$sideBarContainer.css("width",$sideBar.outerWidth() + "px");
$sideImageContainer.css("height",$sideImage.outerHeight() + +"px");
} else {
$sideBar.removeClass("fixed");
$sideBarContainer.css("width","auto");
$sideImageContainer.css("height","0");
}
var diff = $footer.position().top - $window.scrollTop() - $sideBar.outerHeight();
if (diff <= 0) {
$sideBar.css("top",diff+"px");
} else {
$sideBar.css("top","0");
}
}
}

Calculate screen size in a sticky header

There are tonnes of tutorials / examples of making a header stick on scroll for fixed height headers. However, I am working on a one page website and the initial section is a full screen image. The user then scrolls down to reveal the header and other content areas.
So my question is, how can I change my code to take into account the viewport / screen size - rather than use a fixed header size?
My existing code is:
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 65) {
$(".main").addClass("sticky");
} else {
$(".main").removeClass("sticky");
}
});
You could use the height of the window instead of a fixed value (since you're talking about a full screen image, I'm guessing its height is equal to the window height):
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= $(window).height()) {
$(".main").addClass("sticky");
} else {
$(".main").removeClass("sticky");
}
});
You could also get the height of the first section, if it's smaller than the window
I don't know if there's a better solution, but here's my solution :
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= $(window).height()*0.2) { //0.2 for 20% of the viewport height, you can change this value if you need to
$(".main").addClass("sticky");
} else {
$(".main").removeClass("sticky");
}
});
I just used $(window).height() to get the viewport height.

Div to follow scrollbar proportionally on a page

I'm now struggling on a sticky element that should scroll proportionally on a page. From top to the footer despite the page's height. So it's actually stick to the top of the scrollbar in the beginning and then to the bottom at the end. Or it just follows the scroll wheel.
Is there any chance to do it with jQuery ?
Below is the starting code with usual "sticky" div.
$(window).scroll(function(){
$("#sticky")
.animate({"marginTop":($(window).scrollTop())+"px"}, "fast");});
https://jsfiddle.net/flakessp/cxr78xc8/
Do you mean something like this?
$(window).scroll(function() {
// calculate the percentage the user has scrolled down the page
var scrollPercent = 100 * $(window).scrollTop() / ($(document).height() - $(window).height());
// get the height of the sticky element
var stickyHeight = $('.sticky').height();
// calculate the margin top of the sticky element
var marginTop = (($(window).height() - stickyHeight) / 100) * scrollPercent;
// set margin top of sticky element
$('.sticky').css('marginTop', marginTop);
});
Fiddle
So, this one was a little tricky, but here it is:
JSFiddle example
Basically, we're using a couple things here:
Scroll direction detection with this section:
var lastScrollPos = 0,
...
lastScrollPos < $window.scrollTop()
Then, you forgot to factor in things like document and window height. scrollTop does exactly what it says and only gives you the number from the top of the viewport to the top of the document. So we add in the visible height as well with $(window).height().
Then it's just a matter of whether we factor in the height of the element too (hence the ternary operator adding 0 or $('#sticky').height() depending on our scroll direction detection from the earlier section.
Anyhow, here's the full JS:
var lastScrollPos = 0,
$window = $(window),
$document = $(document),
$sticky = $('#sticky');
$(window).scroll(function(){
$sticky
.animate({"top":((($window.scrollTop() + (lastScrollPos < $window.scrollTop() ? $window.height() - $sticky.height() : 0))/$document.height()) * 100)+"%"}, "fast");
});

Scrolling Two Divs Using JQuery/Javascript

Wrapper - Overflow Hidden
Div One: Sidebar
Div Two: Main Content
Div Two will have a normal scroll. Div One I wish to have no visible scroll however when you scroll Div One it scrolls Div Two.
Upon Div One's height hitting the bottom, it will no longer scroll and visa-versa for scrolling back up.
This will result in the sidebar always being visible at the side. Before you ask, I've tried all positioning types to get this to work resulting in many failed attempts.
My live demo can be seen here: http://rafflebananza.com/admin/newadmin.html#
Note I've tried to make a JSFiddle simplified but my maths does not seem to work in there the same. Please suggest whether I should fork all my page to there or whatnot for future visitors needing the same help.
Overview
Scrolling in the wrapper will scroll sidebar to point x only (x being the sidebars height) then stopping but will continue to allow the content to be scrolled. Visa-versa for scrolling back up.
Somewhat half way there...
var scrollTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop,
position = document.body.scrollTop;
function scrollD() {
var scroll = document.body.scrollTop;
if (scroll > position) {
// Scrolling Down Functions
} else {
// Scrolling Up Functions
}
position = scroll;
}
Updated the answer to match OPs requirements.
I downloaded your website in its current state and made the following changes to your code:
var scrollY = 0;
$(window).scroll(function() {
var sideNav = $('.SideNav'); // The side navigation
var wScrollY = $(this).scrollTop(); // Current scroll position of Window
var navHeight = sideNav.height(); // Height of the Navigation
var StageHeight = $(window).height() - 46; // The display space
if(sideNav.height() > StageHeight) { // Do the following if the side navigation is higher than the display space
var spaceLeft = sideNav.height() - StageHeight; // spaceLeft -> how many pixel left before fixing navigation when scrolling
if(scrollY < wScrollY) { // Scroll direction is down
if (wScrollY >= spaceLeft) // If scroll top > space left -> fixate navigation at the bottom, otherwise scroll with the content
sideNav.css({top:46-spaceLeft+wScrollY});
if (wScrollY <= 46) // Set top strict to 46. Sometimes there is white space left, caused by the scroll event.
sideNav.css({top:46});
} else { // Scroll direction is up
var sideNavTop;
if (sideNav.offset().top < 0) {
sideNavTop = Math.pow(sideNav.offset().top); // if top is negative, make it positive for comparison
} else {
sideNavTop = sideNav.offset().top;
}
if (sideNavTop > (46+wScrollY)) // Fixate the header if top of navigation appears
sideNav.css({top:46+wScrollY});
}
} else {
sideNav.css({top:46+wScrollY}); // Fixate always
}
scrollY = wScrollY;
});
This will let you scroll your side navigation up until its end. Then fixate. If you scroll up, it will still be fixated until your reach the point, where the navigation must scrolled back to its original position.
You can check the edited version here: http://pastebin.com/Zkx4pSKe
Just copy the raw code into a blank html page and try it out.
It's a bit messy and maybe not the best solution, but it works.
Ok, here you go:
var $sidebar = $('.sidebar'),
$window = $(window),
previousScroll = 0;
$window.on('scroll', function (e) {
if ($window.scrollTop() - previousScroll > 0) {
$sidebar.css({
'top': Math.max($window.scrollTop() + $window.height() - $sidebar.outerHeight(true), parseInt($sidebar.css('top'))) + 'px'
});
} else {
$sidebar.css({
'top': Math.min($window.scrollTop(), parseInt($sidebar.css('top'))) + 'px'
});
}
previousScroll = $window.scrollTop();
});
http://jsfiddle.net/7nwzcpqk/1/
i might have misunderstood your desired result incorrectly but you can see if this works for you :
.SideNav {
position: fixed; // you currently have this as position:absolute;
}
You don't need nor a wrapper element nor jQuery. I assume that you are using a wrapper because you want to have the top bar placed there. I think there is a better way to do it by using simply three divs.
The top bar has to be fixed (to be always visible) and of full width.
The side bar also has to be fixed (to be always visible) with a top margin of the height of the top bar.
The content needs just a left padding (width of side bar) and top padding (height of top bar).
Here is the example code (http://jsfiddle.net/zckfwL4p/):
HTML
<div id="top_bar"></div>
<div id="side_bar">links here</div>
<div id="content"></div>
CSS
body {
margin:0px;
padding:0px;
}
#side_bar {
width:50px;
position: fixed;
left:0px;
top:20px;
background-color:blue;
}
#top_bar {
position:fixed;
height:20px;
left:0px;
right:0px;
background-color:red;
}
#content {
position:relative;
padding-left:55px;
padding-top:25px;
}

How to make a .fixed sticky item's "margin-top" relative to the size of the sticky item?

This is my first question. I am having trouble with a image I am trying to stick when it reaches the top of the page after scrolling.
Check out this jfiddle - it is not mine but comes close to representing my question
http://jsfiddle.net/vBy5w/
(I am aware that I can input a set "margin-top" to make this work but when the browser size changes then the image size will respond and will throw off the set margin.)
So far I have achieved this by using the code below to effect the Div Id = Picture1 in my html
<div id="picture1"><img src="img/empty-restaurant.png" alt="Why do your customers not come back?" style="max-width:100%;height:auto;"> </div>
When this picture "sticks" the test below the image will jump up, I fixed this by including the last line of the .js but by stating a fixed "margin-top" it means that there will be a jump if the margin size is not correct depending on browser size.
Is there a way to make this Margin variable or relative to the height of the "stick"-ed item? And if so how?
Thanks guys!
$(document).ready(function() {
var s = $("#picture1");
var pos = s.position();
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
//$("#header_left").html("Distance from top:" + pos.top + "<br />Scroll position: " + windowpos);
if (windowpos >= pos.top) {
s.addClass("stick");
} else {
s.removeClass("stick");
}
This is the part that needs changing - the first "margin-top" needs to be relative to the size of the "stick"ed item
if (windowpos >= pos.top) { s.addClass("stick"); $("body").css("margin-top", 60); } else { s.removeClass("stick"); $("body").css("margin-top", 0); }
});
});
As comments,
$("body").css("margin-top", s.height());
Gives a dynamic margin-top css value to the <body> based on the height on the element ( #picture1 ) that is being fixed during window.scroll
As an addition, you mention that the height may change on screen resize ( rwd )
So this may be good to add also ( to keep it in check )
$(window).resize(function() {
var s = $("#picture1");
if(s.hasClass("stick") {
$("body").css("margin-top", s.height());
}
});

Categories

Resources