I'm looking for a solution to the popular issue of stopping a fixed object at the footer of the page.
I basically have a fixed "share" box in the bottom left corner of the screen and I don't want it to scroll over the footer, so I need it to stop about 10px
above the footer.
I've looked at other questions here as well as others. The closest/most simple demo I could find is http://jsfiddle.net/bryanjamesross/VtPcm/ but I couldn't get it to work with my situation.
Here's the html for the share box:
<div id="social-float">
<div class="sf-twitter">
...
</div>
<div class="sf-facebook">
...
</div>
<div class="sf-plusone">
...
</div>
</div>
...and the CSS:
#social-float{
position: fixed;
bottom: 10px;
left: 10px;
width: 55px;
padding: 10px 5px;
text-align: center;
background-color: #fff;
border: 5px solid #ccd0d5;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
display: none;
}
The footer is #footer
and it doesn't have a fixed height, if that makes any difference.
If someone could assist me in creating a simple jQuery solution for this, I'd much appreciate it!
This question is related to
javascript
jquery
css
scroll
fixed
If your elements are glitching this is probably because when you change the position to relative
the Y position of the footer increases which tries to send the item back to fixed
which creates a loop. You can avoid this by setting two different cases when scrolling up and down. You don't even need to reference the fixed element, just the footer, and window size.
const footer = document.querySelector('footer');
document.addEventListener("scroll", checkScroll);
let prevY = window.scrollY + window.innerHeight;
function checkScroll() {
let footerTop = getRectTop(footer) + window.scrollY;
let windowBottomY = window.scrollY + window.innerHeight;
if (prevY < windowBottomY) { // Scroll Down
if (windowBottomY > footerTop)
setScrolledToFooter(true) // using React state. Change class or change style in JS.
} else { // Scroll Up
if (windowBottomY <= footerTop)
setScrolledToFooter(false)
}
prevY = windowBottomY
};
function getRectTop(el) {
var rect = el.getBoundingClientRect();
return rect.top;
}
and the position of the element in the style object as follows:
position: scrolledToFooter ? 'relative' : 'fixed'
$(window).scroll(() => {
const footerToTop = $('.your-footer').position().top;
const scrollTop = $(document).scrollTop() + $(window).height();
const difference = scrollTop - footerToTop;
const bottomValue = scrollTop > footerToTop ? difference : 0;
$('.your-fixed-element').css('bottom', bottomValue);
});
I went with a modification of @user1097431 's answer:
function menuPosition(){
// distance from top of footer to top of document
var footertotop = ($('.footer').position().top);
// distance user has scrolled from top, adjusted to take in height of bar (42 pixels inc. padding)
var scrolltop = $(document).scrollTop() + window.innerHeight;
// difference between the two
var difference = scrolltop-footertotop;
// if user has scrolled further than footer,
// pull sidebar up using a negative margin
if (scrolltop > footertotop) {
$('#categories-wrapper').css({
'bottom' : difference
});
}else{
$('#categories-wrapper').css({
'bottom' : 0
});
};
};
I ran into this same issue recently, posted the my solution also here: Preventing element from displaying on top of footer when using position:fixed
You can achieve a solution leveraging the position
property of the element with jQuery, switching between the default value (static
for divs
), fixed
and absolute
.
You will also need a container element for your fixed element. Finally, in order to prevent the fixed element to go over the footer, this container element can't be the parent of the footer.
The javascript part involves calculating the distance in pixels between your fixed element and the top of the document, and comparing it with the current vertical position of the scrollbar relatively to the window object (i.e. the number of pixels above that are hidden from the visible area of the page) every time the user scrolls the page. When, on scrolling down, the fixed element is about to disappear above, we change its position to fixed and stick on top of the page.
This causes the fixed element to go over the footer when we scroll to the bottom, especially if the browser window is small. Therefore, we will calculate the distance in pixels of the footer from the top of the document and compare it with the height of the fixed element plus the vertical position of the scrollbar: when the fixed element is about to go over the footer, we will change its position to absolute and stick at the bottom, just over the footer.
Here's a generic example.
The HTML structure:
<div id="content">
<div id="leftcolumn">
<div class="fixed-element">
This is fixed
</div>
</div>
<div id="rightcolumn">Main content here</div>
<div id="footer"> The footer </div>
</div>
The CSS:
#leftcolumn {
position: relative;
}
.fixed-element {
width: 180px;
}
.fixed-element.fixed {
position: fixed;
top: 20px;
}
.fixed-element.bottom {
position: absolute;
bottom: 356px; /* Height of the footer element, plus some extra pixels if needed */
}
The JS:
// Position of fixed element from top of the document
var fixedElementOffset = $('.fixed-element').offset().top;
// Position of footer element from top of the document.
// You can add extra distance from the bottom if needed,
// must match with the bottom property in CSS
var footerOffset = $('#footer').offset().top - 36;
var fixedElementHeight = $('.fixed-element').height();
// Check every time the user scrolls
$(window).scroll(function (event) {
// Y position of the vertical scrollbar
var y = $(this).scrollTop();
if ( y >= fixedElementOffset && ( y + fixedElementHeight ) < footerOffset ) {
$('.fixed-element').addClass('fixed');
$('.fixed-element').removeClass('bottom');
}
else if ( y >= fixedElementOffset && ( y + fixedElementHeight ) >= footerOffset ) {
$('.fixed-element').removeClass('fixed');
$('.fixed-element').addClass('bottom');
}
else {
$('.fixed-element').removeClass('fixed bottom');
}
});
I've made some changes to the second most popular answer as i found this worked better for me. The changes use window.innerHeight as it is more dynamic than adding your own height for the nav (above used + 570). this allows the code to work on mobile, tablet and desktop dynamicly.
$(window).scroll(() => {
//Distance from top fo document to top of footer
topOfFooter = $('#footer').position().top;
// Distance user has scrolled from top + windows inner height
scrollDistanceFromTopOfDoc = $(document).scrollTop() + window.innerHeight;
// Difference between the two.
scrollDistanceFromTopOfFooter = scrollDistanceFromTopOfDoc - topOfFooter;
// If user has scrolled further than footer,
if (scrollDistanceFromTopOfDoc > topOfFooter) {
// add margin-bottom so button stays above footer.
$('#floating-button').css('margin-bottom', 0 + scrollDistanceFromTopOfFooter);
} else {
// remove margin-bottom so button goes back to the bottom of the page
$('#floating-button').css('margin-bottom', 0);
}
});
This worked for me -
HTML -
<div id="sideNote" class="col-sm-3" style="float:right;">
</div>
<div class="footer-wrap">
<div id="footer-div">
</div>
</div>
CSS -
#sideNote{right:0; margin-top:10px; position:fixed; bottom:0; margin-bottom:5px;}
#footer-div{margin:0 auto; text-align:center; min-height:300px; margin-top:100px; padding:100px 50px;}
JQuery -
function isVisible(elment) {
var vpH = $(window).height(), // Viewport Height
st = $(window).scrollTop(), // Scroll Top
y = $(elment).offset().top;
return y <= (vpH + st);
}
function setSideNotePos(){
$(window).scroll(function() {
if (isVisible($('.footer-wrap'))) {
$('#sideNote').css('position','absolute');
$('#sideNote').css('top',$('.footer-wrap').offset().top - $('#sideNote').outerHeight() - 100);
} else {
$('#sideNote').css('position','fixed');
$('#sideNote').css('top','auto');
}
});
}
Now call this function like this -
$(document).ready(function() {
setSideNotePos();
});
PS - The Jquery functions are copied from an answer to another similar question on stackoverflow, but it wasn't working for me fully. So I modified it to these functions, as they are shown here. I think the position etc attributes to your divs will depend on how the divs are structured, who their parents and siblings are.
The above function works when both sideNote and footer-wraps are direct siblings.
I've just solved this problem on a site I'm working on, and thought I would share it in the hope it helps someone.
My solution takes the distance from the footer to the top of the page - if the user has scrolled further than this, it pulls the sidebar back up with a negative margin.
$(window).scroll(() => {
// Distance from top of document to top of footer.
topOfFooter = $('#footer').position().top;
// Distance user has scrolled from top, adjusted to take in height of sidebar (570 pixels inc. padding).
scrollDistanceFromTopOfDoc = $(document).scrollTop() + 570;
// Difference between the two.
scrollDistanceFromTopOfFooter = scrollDistanceFromTopOfDoc - topOfFooter;
// If user has scrolled further than footer,
// pull sidebar up using a negative margin.
if (scrollDistanceFromTopOfDoc > topOfFooter) {
$('#cart').css('margin-top', 0 - scrollDistanceFromTopOfFooter);
} else {
$('#cart').css('margin-top', 0);
}
});
A pure css solution
<div id="outer-container">
<div id="scrollable">
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in vulputate turpis. Curabitur a consectetur libero. Nulla ac velit nibh, ac lacinia nulla. In sed urna sit amet mauris vulputate viverra et et eros. Pellentesque laoreet est et neque euismod a bibendum velit laoreet. Nam gravida lectus nec purus porttitor porta. Vivamus tempor tempus auctor. Nam quis porttitor ligula. Vestibulum rutrum fermentum ligula eget luctus. Sed convallis iaculis lorem non adipiscing. Sed in egestas lectus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc dictum, lacus quis venenatis ultricies, turpis lorem bibendum dui, quis bibendum lacus ante commodo urna. Fusce ut sem mi, nec molestie tortor. Mauris eu leo diam. Nullam adipiscing, tortor eleifend pellentesque gravida, erat tellus vulputate orci, quis accumsan orci ipsum sed justo. Proin massa massa, pellentesque non tristique non, tristique vel dui. Vestibulum at metus at neque malesuada porta et vitae lectus.
</div>
<button id="social-float">The button</button>
</div>
<div>
Footer
</div>
</div>
And css here
#outer-container {
position: relative;
}
#scrollable {
height: 100px;
overflow-y: auto;
}
#social-float {
position: absolute;
bottom: 0px;
}
Here is the @Sang solution but without Jquery.
var socialFloat = document.querySelector('#social-float');_x000D_
var footer = document.querySelector('#footer');_x000D_
_x000D_
function checkOffset() {_x000D_
function getRectTop(el){_x000D_
var rect = el.getBoundingClientRect();_x000D_
return rect.top;_x000D_
}_x000D_
_x000D_
if((getRectTop(socialFloat) + document.body.scrollTop) + socialFloat.offsetHeight >= (getRectTop(footer) + document.body.scrollTop) - 10)_x000D_
socialFloat.style.position = 'absolute';_x000D_
if(document.body.scrollTop + window.innerHeight < (getRectTop(footer) + document.body.scrollTop))_x000D_
socialFloat.style.position = 'fixed'; // restore when you scroll up_x000D_
_x000D_
socialFloat.innerHTML = document.body.scrollTop + window.innerHeight;_x000D_
}_x000D_
_x000D_
document.addEventListener("scroll", function(){_x000D_
checkOffset();_x000D_
});
_x000D_
div.social-float-parent { width: 100%; height: 1000px; background: #f8f8f8; position: relative; }_x000D_
div#social-float { width: 200px; position: fixed; bottom: 10px; background: #777; }_x000D_
div#footer { width: 100%; height: 200px; background: #eee; }
_x000D_
<div class="social-float-parent">_x000D_
<div id="social-float">_x000D_
float..._x000D_
</div>_x000D_
</div>_x000D_
<div id="footer">_x000D_
</div>
_x000D_
I was working on stopping the adbanner at a certain point before footer. And played with the code I found above.
Worked for me (banner disappears right before footer and reappears on scroll to top):
<style>
#leftsidebanner {width:300px;height:600px;position: fixed; padding: 0;top:288px;right:5%;display: block;background-color: aqua}
</style>
<div id="leftsidebanner">
</div>
<script>
$.fn.followTo = function (pos) {
var stickyAd = $(this),
theWindow = $(window);
$(window).scroll(function (e) {
if ($(window).scrollTop() > pos) {
stickyAd.css({'position': 'absolute','bottom': pos});
} else {
stickyAd.css({'position': 'fixed','top': '100'});
}
});
};
$('#leftsidebanner').followTo(2268);
</script>
You can now use
#myObject{
position:sticky;
}
Hope this helps..
Source: Stackoverflow.com