Sticky div at bottom of viewport after scroll - javascript

I'm trying to create a sticky footer element in a left hand column of a webpage. The right hand column will have dynamic content so I can't put an exact height to any element(except for viewport height). What I'd like to happen is the footer is placed below the viewport until a user starts scrolling and then the footer element is fixed at the bottom of the viewport.
I have a forked Fiddle that works but breaks the content if it is taller than navigation. I've also tried using Sticky Footer, but I can't wrap everything together because of the same issue.
What I've found so far.
var $buzz = $('#buzz'),
viewportHeight = $(window).height(),
buzzHeight = 182,
buzzTop = $buzz.offset().top + buzzHeight,
buzzPosition = buzzTop - viewportHeight;
$(window).bind("resize.browsersize", function () {
var viewportHeight = $(window).height(),
buzzHeight = 182,
buzzTop = $buzz.offset().top + buzzHeight,
buzzPosition = buzzTop - viewportHeight;
}).trigger("resize.browsersize");
$(window).scroll(function () {
if ($(window).scrollTop() >= buzzPosition) {
$buzz.css({
position: 'fixed',
bottom: 0
});
} else {
$buzz.removeAttr("style");
}
});

In the events that cause the divs on the left to resize, call $(window).scroll(); and it will reposition the sticky footer.
$('.change').on('click', function () {
$(this).css("height", "+=50px");
$(window).scroll();
return false;
});

Related

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;
}

A cleaner way for a fixed div at bottom of the window but stays above the footer and triggers on page width

I've created a sticky bar to stay at the bottom of the window. As the user scrolls down to the bottom of the page the same bar will stay fixed until the footer shows, then removes its fixed position, temporarily, to stay above the footer until the user scrolls back up and it remains fixed again.
I only want to happen when the page is wider than 680px. Anything under that will keep the sticky bar in a default position (CSS: position:inherit).
This is the website: http://ttd.firefly-digital.co.uk
It works as expected. However, when I test on Chrome in Mac it triggers my CPU fan which suggests this not very efficient and with my limited JavaScript skills, wondered if there is a cleaner way to achieve this is?
This is the current js code:
$(window).scroll(function(event) {
var scroll = $(this).scrollTop();
var docHeight = $(document).height();
var windowHeight = $(window).height();
var footerHeight = $('.footer').height();
if(docHeight - (windowHeight + scroll) < footerHeight) {
$('.contact-bar').css({
bottom: footerHeight - (docHeight - (windowHeight + scroll))
});
} else {
$('.contact-bar').css({
bottom: 0
});
}
});
var windowWidth = $(window).width();
$(window).resize(function() {
windowWidth = $(window).width();
if(windowWidth > 680) {
$('.contact-bar').css({
position: "fixed"
});
} else {
$('.contact-bar').css({
position: "inherit"
});
}
});
CSS code
.contact-bar {
background: $contact-bar;
width: 100%;
height: 40px;
text-align: center;
position: fixed;
bottom: 0;
z-index: 10;
}
You can do it in reverse. Make it so that the bar, without position fixed, is above the footer without any JavaScript (incl. media queries). Than add a fixed class with position:fixed and bottom:0 that will be added accordingly. Like so:
.contact-bar.fixed { position:fixed; bottom:0; }
The jquery code that will trigger this, is as follows:
$(window).scroll(function (event) {
var windowTop = $(this).scrollTop();
if (windowTop >= $(".footer").offset().top) {
$(".contact-bar").addClass("fixed");
} else {
$(".contact-bar").removeClass("fixed");
}
});
Then add a few lines that the above code will only fire if the window width is > 680, either with jquery or pure javascript. For example with:
if ($(window).width() < 960) { // above function }
Do note I have not tested this, so please comment if it doesn't work. Credit: Preventing element from displaying on top of footer when using position:fixed
You better use classes to target your elements, at least to prevent jQuery from traversing the whole DOM using selectors appropriately which is good in performance.

Move div with window scroll not consistent

I need my sidebar to scroll up and down with the window but stop when the div is at its top or bottom. The code below works when the page is first loaded and scrolled down or when the page is scrolled up slowly, but when the page is scrolled to the very bottom of the sidebar div, the page has to reach the top (and then some) in order to trigger that margin change.
Is there some other trigger I should be looking for besides just on scroll? How can I adjust this code to properly adjust the div?
$(window).on("load scroll", function() {
var scrollYpos = $(document).scrollTop();
var sidebarinfo = $("#sidebar").offset().top + $("#sidebar").height();
var windowinfo = $(window).height() + $(window).scrollTop();
if ((windowinfo)<(sidebarinfo)){
$('#sidebar').css('margin-top', -scrollYpos);
}
});
The sidebar div is fixed position. If I use absolute position, the div scrolls fine, but it doesn't stop when the bottom of the div has been reached - it just continues to scroll with the window.
I've fixed the main part of the problem with this code.
$(window).on("load scroll", function() {
var sidebarinfo = $("#sidebar").scrollTop() + $("#sidebar").height();
var windowinfo = $(window).innerHeight() + $(window).scrollTop();
if ((windowinfo)<(sidebarinfo)){
$('#sidebar').css('top', -($(window).scrollTop()));
}
});
The only problem is on page load, the sidebar gets stuck in the wrong position until it is scrolled all the way up (and more).
I actually figured out that I needed to adjust a few things and add an else clause:
$(window).on("scroll", function() {
var scrollmargin = $(window).scrollTop() - $("#sidebar").outerHeight();
var sidebarinfo = $("#sidebar").scrollTop() + $("#sidebar").outerHeight();
var windowinfo = $(window).innerHeight() + $(window).scrollTop();
console.log($(window).scrollTop());
if ((windowinfo)<(sidebarinfo)){
$('#sidebar').css('top', (sidebarinfo + scrollmargin)*-1);
}
else {
var margintop = $(window).innerHeight() - $("#sidebar").outerHeight();
$('#sidebar').css('top', margintop);
}
});

stick div to screen if bottom of div and screen matches

Hello all I am working on a project where in a page I have to stick the div to screen (disable scrolling) when its bottom is at the bottom of screen. I have two divs in the page and both the divs are of variable height. I want to stick the div2 and scroll the div1.
<script>
var divheight
var scrolltop
var screenheight
if(divheight-scrolltop <= screenheight){
/* now stick the div wherever it is i can not
use fixed position as both the divs are floating and
fixing the position will make it to change the position*/ }
else { /*un stick the div*/ }
</script>
i dont know what to put in if and else please help me
Make a function which fire on scroll. The main aim of the function would be to see the difference between screen height and bottom of the div. Once the difference is less than or equal to zero modify the css position to fixed. This will help you
(function ($) {
$('.DIV1').scroll(function () {
var $this = $(this),
win_ht = $(window).height(),
div_ht = $this.height(),
div_bot = $this.offset().top + div_ht;
if (win_ht - div_bot <= 0) {
$this.css({
'position': 'fixed',
'bottom': '0'
})
}
});
})(jQuery);

Keep a div visible when content would push it down

I want to have a div positioned in the bottom of another div. This i can solve with just
bottom: 0px;
postion: fixed;
But, if the containing div is larger than the window, i want to freeze the inner div to the bottom of the window.
If it's easier the first condition can be scrapped and the inner div can just be positioned under the content, the important part is that the content must always be visible.
The best solution would be to detect with JavaScript if the footer is visible inside the viewport. If not, you should change it's styles to stick to the bottom of the window instead of that of the containing div.
You could use this function to see if it's in the viewport:
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top >= window.pageYOffset &&
left >= window.pageXOffset &&
(top + height) <= (window.pageYOffset + window.innerHeight) &&
(left + width) <= (window.pageXOffset + window.innerWidth)
);
}
(taken from How to tell if a DOM element is visible in the current viewport?)
Now, every time you scroll or resize the page you can do a check that runs that function. Based on that, you can decide to set a class or change a CSS property that will do what you're looking for.
Since you didn't include any code (in the future, please do) I'm going to assume your code looks something like this:
<div class="wrapper">
(contents)
<div class="footer">footer</div>
</div>
To stick the .footer to the bottom of .wrapper, it has to have a 'positon: absolute' and the wrapper will need a position: relative. However, if you change it's position property to fixed and the wrapper to static (the default for all elements), the footer is going to stick to the bottom of the window instead.
View this example http://jsfiddle.net/GMYEh/
Now, using the script above you can tell which of the two it should be. You have to use a fake element at the same position of the footer, instead of the footer itself. That way, if you move the footer to the bottom of the window, you can still measure whether or not the bottom of the wrapper is in the viewport. (If you measure the footer itself and move it you'll get stuck).
The script that does this (in jQuery):
// add a fake footer after the wrapper
$('.wrapper').after($('<div class="fakefooter" />'));
$(document).on('resize scroll', function(e){
//measure if the fake footer is in viewport
if(elementInViewport($('.fakefooter')[0])) {
// If so, it should be in the bottom of the wrapper.
$('.wrapper').css('position', 'relative');
$('.footer').css('position', 'absolute');
} else {
// else it should be in the bottom of the window
$('.wrapper').css('position', 'static');
$('.footer').css('position', 'fixed');
}
});
Working example:
http://jsfiddle.net/GMYEh/4/
Try this:
HTML:
<div id="wrapper">
<div id="innerContent"></div>
</div>
CSS:
.fixedContent {
position: fixed;
bottom: 0;
}
and the javascript:
var wrapper = document.getElementById('wrapper');
var content = document.getElementById('innerContent');
function position() {
if (wrapper.offsetHeight + wrapper.offsetTop - content.offsetHeight - window.scrollY > window.innerHeight) {
content.className += ' fixedContent';
} else {
content.className = content.className.replace('fixedContent', '');
}
}
window.onload = position;
window.onresize = position;
If you're open to jQuery you can make the javascript more simple and compatible
var $wrapper = $('#wrapper');
var $content = $('#innerContent');
$(window).on('load resize', function() {
$content.toggleClass('fixedContent', $wrapper.outerHeight(true) $content.offset().top - $content.outerHeight(true) - $(document).scrollTop() > $(window).height());
});
EDIT:
I modified the conditions a bit adding the vertical scroll value and top offset.

Categories

Resources