I have a problem with my jQuery plugin, I want to display footer in specific way right before end of page. For this I get actual bottom position and compare it with height of entire body.
But there is a problem jQuery function height() return bad value. For example I know that site has height of 5515px but function returns to me a value: 8142px
I use the plugin mCustomScrollbar in few places on page, and I think that it may cause the problem. I can't disable it, because page has elements which require it to look good.
My code:
(function($){
$.fn.scrollingElements = function(){
var height = $(window).height();
var max_height = $(document).height();
var prev_top = $(window).scrollTop();
var prev_bottom = top + height;
$(window).scroll(function(){
var top = $(window).scrollTop();
var bottom = top + height;
console.log(max_height, bottom);
if(prev_top < height && top > height){
// console.log('show header', 'show sticky', 'show footer small');
}
if(prev_top > height && top < height){
// console.log('hide header', 'hide sticky', 'hide footer');
}
if(prev_top < 2*height && top > 2*height){
// console.log('show sroll top');
}
if(prev_top > 2*height && top < 2*height){
// console.log('hide scroll top');
}
if(prev_bottom < max_height - 100 && bottom > max_height - 100){
// console.log('show footer large');
}
if(prev_bottom > max_height - 100 && bottom < max_height - 100){
// console.log('show footer small');
}
prev_top = top;
prev_bottom = bottom;
});
$(window).resize(function(){
height = $(window).height();
});
}
})(jQuery);
Answering to Tommy Riordan:
changing $(document).height() to document.body.clientHeight didn't work still getting bad results. Tried using $('body').height() with same effect.
Please use
document
instead of window
for example :
$(window).resize(function(){
height = $(document).height();
});
Related
I'm trying to write a script that has several variable and functions. The script is for a navbar and it should do the following:
On scroll:change bg from transparent to solid, and change logo img.
On small screens:change bg from transparent to solid, and change logo img.
The problem is that I can get it to work with one or the other but not both.
What happens is the resize works on small screen UNTIL you scroll down and back up. When it hits the top it the background goes back to transparent.
Is there a way to remove the scrollTop function on smaller screens? I feel like removing/disabling this function would fix the problem.
*** Is there a way to do something like this? ***
if (width < 786) {
//REMOVE scrollTop;//?
}
I'm just trying to figure out how to remove the scrollTop function if the screen is small.
I have tried placing the functions in separate scripts, and also using #media css, which comes the closest to working so far, but the "green" logo disappears when scroll hits top.
$(document).ready(function() {
$(window).scroll(function() {
$(window).resize(function() {
var height = $('.first-container').height();
var scrollTop = $(window).scrollTop();
var width = $(window).width();
if (scrollTop >= 0 || width < 768) {
$('.nav-container').addClass('solid-nav') &&
$('.navbar-brand img').attr('src','images/new-green-sm.png');
} else {
$('.nav-container').removeClass('solid-nav') &&
$('.navbar-brand img').attr('src','images/new-white-sm.png');
}
});
});
});
Just run this when you want to test the width to remove the function.
if (width < 768) {
scrollTop = function(){};
};
You could just always set scrollTop to 0 if width < 768 instead of calling the scrollTop method :
$(document).ready(function() {
$(window).scroll(function() {
$(window).resize(function() {
var height = $('.first-container').height();
var width = $(window).width();
// Set scrollTop always to 0 if width < 768
var scrollTop = (width < 768) ? 0 : $(window).scrollTop();
if (scrollTop >= 0 || width < 768) {
$('.nav-container').addClass('solid-nav') &&
$('.navbar-brand img').attr('src','images/new-green-sm.png');
} else {
$('.nav-container').removeClass('solid-nav') &&
$('.navbar-brand img').attr('src','images/new-white-sm.png');
}
});
});
});
This way if will never execute the second part of your if-statement if width < 768, no matter what the value of scrollTop is.
My site is www.to-hawaii.com. The length of the right panel is controlled by the length of the middle panel. In other words the middle panel will adjust to the length of the right panel which is naturally shorter. In some cases though the right panel is longer, see here http://www.to-hawaii.com/bg/ and this creates a strange scroll on the right. Is there a way to fix that? In other words if there is a way to have the script work like this: if the middle panel is longer than the right panel, match the right's panel width so it is as long as the middle panel and if the right panel is longer, match the middle panel's width so it is the same length as the right panel.
The function I am currently using to make the right panel width match the middle panel width is:
$(document).on('ready',function(){
if($(window).width() > 768){
var heightLeft = $(".leftpanel").height();
var heightMiddle = $(".midpanel").height();
if(heightLeft >= heightMiddle){
$(".rightpanel").css("height",heightLeft - 10);
$(".midpanel").css("height",heightLeft - 10);
}else{
$(".rightpanel").css("height",heightMiddle +2);
}
}
$(window).resize(function(){
if($(window).width() >= 768){
$(".rightpanel").css("height", "auto");
$(".midpanel").css("height", "auto");
var heightLeft = $(".leftpanel").height();
var heightMiddle = $(".midpanel").height();
if(heightLeft >= heightMiddle){
$(".rightpanel").css("height",heightLeft - 10);
$(".midpanel").css("height",heightLeft - 10);
}if(heightLeft < heightMiddle){
$(".rightpanel").css("height",heightMiddle +2);
}
}
if($(window).width() < 561){
$(".rightpanel").css("height", "auto");
$(".midpanel").css("height", "auto");
}
})
})
you could try something like this:
$(document).on('ready',function(){
var rightHeight = $('.rightPanel').height();
var leftHeight = $('.leftPanel').height();
var midHeight = $('.midPanel').height();
if (rightHeight > midHeight) {
midHeight = rightHeight;
$('.midPanel').css('height', midHeight);
}
else if (midHeight > rightHeight) {
rightHeight = midHeight;
$('.rightPanel').css('height', rightHeight);
}
// If window is resized
window.addEventListener("resize", adjustPanes);
function adjustPanes(rightHeight, midHeight) {
if (rightHeight > midHeight) {
midHeight = rightHeight;
$('.midPanel').css('height', midHeight);
}
else if (midHeight > rightHeight) {
rightHeight = midHeight;
$('.rightPanel').css('height', rightHeight);
}
}
});
Alternatively, you could set all three panels to the height of the wrapper div that you have created.
This would make them each the same length.
$(document).on('ready',function(){
var wrapperHeight = $('#wrapper').height();
$('.midPanel').height(wrapperHeight);
$('.leftPanel').height(wrapperHeight);
$('.righttPanel').height(wrapperHeight);
});
I need to retrieve the visible height of a div within a scrollable area. I consider myself pretty decent with jQuery, but this is completely throwing me off.
Let's say I've got a red div within a black wrapper:
In the graphic above, the jQuery function would return 248, the visible portion of the div.
Once the user scrolls past the top of the div, as in the above graphic, it would report 296.
Now, once the user has scrolled past the div, it would again report 248.
Obviously my numbers aren't going to be as consistent and clear as they are in this demo, or I'd just hard code for those numbers.
I have a bit of a theory:
Get the height of the window
Get the height of the div
Get the initial offset of the div from the top of the window
Get the offset as the user scrolls.
If the offset is positive, it means the top of the div is still visible.
if it's negative, the top of the div has been eclipsed by the window. At this point, the div could either be taking up the whole height of the window, or the bottom of the div could be showing
If the bottom of the div is showing, figure out the gap between it and the bottom of the window.
It seems pretty simple, but I just can't wrap my head around it. I'll take another crack tomorrow morning; I just figured some of you geniuses might be able to help.
Thanks!
UPDATE: I figured this out on my own, but looks like one of the answers below is more elegant, so I'll be using that instead. For the curious, here's what I came up with:
$(document).ready(function() {
var windowHeight = $(window).height();
var overviewHeight = $("#overview").height();
var overviewStaticTop = $("#overview").offset().top;
var overviewScrollTop = overviewStaticTop - $(window).scrollTop();
var overviewStaticBottom = overviewStaticTop + $("#overview").height();
var overviewScrollBottom = windowHeight - (overviewStaticBottom - $(window).scrollTop());
var visibleArea;
if ((overviewHeight + overviewScrollTop) < windowHeight) {
// alert("bottom is showing!");
visibleArea = windowHeight - overviewScrollBottom;
// alert(visibleArea);
} else {
if (overviewScrollTop < 0) {
// alert("is full height");
visibleArea = windowHeight;
// alert(visibleArea);
} else {
// alert("top is showing");
visibleArea = windowHeight - overviewScrollTop;
// alert(visibleArea);
}
}
});
Calculate the amount of px an element (height) is in viewport
Fiddle demo
This tiny function will return the amount of px an element is visible in the (vertical) Viewport:
function inViewport($el) {
var elH = $el.outerHeight(),
H = $(window).height(),
r = $el[0].getBoundingClientRect(), t=r.top, b=r.bottom;
return Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H));
}
Use like:
$(window).on("scroll resize", function(){
console.log( inViewport($('#elementID')) ); // n px in viewport
});
that's it.
jQuery .inViewport() Plugin
jsFiddle demo
from the above you can extract the logic and create a plugin like this one:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
Use like:
$("selector").inViewport(function(px) {
console.log( px ); // `px` represents the amount of visible height
if(px > 0) {
// do this if element enters the viewport // px > 0
}else{
// do that if element exits the viewport // px = 0
}
}); // Here you can chain other jQuery methods to your selector
your selectors will dynamically listen to window scroll and resize but also return the initial value on DOM ready trough the first callback function argument px.
Here is a quick and dirty concept. It basically compares the offset().top of the element to the top of the window, and the offset().top + height() to the bottom of the window:
function getVisible() {
var $el = $('#foo'),
scrollTop = $(this).scrollTop(),
scrollBot = scrollTop + $(this).height(),
elTop = $el.offset().top,
elBottom = elTop + $el.outerHeight(),
visibleTop = elTop < scrollTop ? scrollTop : elTop,
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
$('#notification').text(`Visible height of div: ${visibleBottom - visibleTop}px`);
}
$(window).on('scroll resize', getVisible).trigger('scroll');
html,
body {
margin: 100px 0;
}
#foo {
height: 1000px;
background-color: #C00;
width: 200px;
margin: 0 auto;
}
#notification {
position: fixed;
top: 0;
left: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="foo"></div>
<div id="notification"></div>
The logic can be made more succinct if necessary, I've just declared separate variables for this example to make the calculation as clear as I can.
Here is a version of Rory's approach above, except written to function as a jQuery plugin. It may have more general applicability in that format. Great answer, Rory - thanks!
$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
return visibleBottom - visibleTop
}
Can be called with the following:
$("#myDiv").visibleHeight();
jsFiddle
Here is the improved code for jquery function visibleHeight: $("#myDiv").visibleHeight();
$.fn.visibleHeight = function() {
var elBottom, elTop, scrollBot, scrollTop, visibleBottom, visibleTop, height;
scrollTop = $(window).scrollTop();
scrollBot = scrollTop + $(window).height();
elTop = this.offset().top;
elBottom = elTop + this.outerHeight();
visibleTop = elTop < scrollTop ? scrollTop : elTop;
visibleBottom = elBottom > scrollBot ? scrollBot : elBottom;
height = visibleBottom - visibleTop;
return height > 0 ? height : 0;
}
i've been looking for this for a couple of days but still no joy!
I would like to have a div scroll in a fixed position until it gets to the top of the footer.
Here is a fiddle of what i have so far: http://jsfiddle.net/danieljoseph/uk4mC/
I'm using this JQuery code but this uses pixels to determine when the div stops. I would like to use the top of the footer as the stop point:
$(document).scroll(function() {
var scrollVal = $(document).scrollTop();
$('#floating-container').css('top',scrollVal+'px');
if (scrollVal < 50) {
$('#floating-container').css('top','50px');
}
if (scrollVal > 2347) {
$('#floating-container').css('top','2347px');
}
});
The issue is that i am using a CMS and the client will be adding text to the page so the second value will change depending on what they add.
I hope i've been clear enough! please let me know if you require more details.
Thanks,
You have to check in the scroll event if the bottom edge of your div is lower than the footer. If it is, place the div at the position of the footer minus the height of the div.
$(function(){
var container = $('#floating-container');
var minTop = $('header').outerHeight();
var maxTop = $('footer').offset().top - container.outerHeight();
$(document).scroll(function() {
var scrollVal = $(document).scrollTop();
container.css('top', scrollVal);
if (scrollVal < minTop) {
container.css('top', minTop);
}
if (container.offset().top > maxTop ) {
container.css('top', maxTop );
}
});
});
Fiddle
And, a much shorter variant of the script above:
$(function(){
var container = $('#floating-container');
var minTop = $('header').outerHeight();
var maxTop = $('footer').offset().top - container.outerHeight();
$(document).scroll(function() {
container.css('top', Math.min( Math.max(minTop, $(document).scrollTop()), maxTop ));
});
});
Short version fiddle.
Just read the position of the footers top when you load the page:
http://jsfiddle.net/uk4mC/1/
var footerTop = $('#text-block').position().top;
and then use that as a trigger:
if (scrollVal < footerTop) { }
I'm trying create an alert saying "True" when the user scrolls past the "#topp" element, yet it isn't doing anything, the element is just supposed to be a tiny div at the top of the page.
HTML
<div id="topp"></div>
jQuery
$(window).scroll(function() {
var vpH = $(window).height(),
st = $(window).scrollTop(),
y = $('#topp').offset().top;
if(y > (st + vpH)) alert('true');
});
Why do you need the window height? If you have the top and the scroll to top variables then theirs no need for the height of the window.
$(document).scroll(function()
{
var scrollTop = $(window).scrollTop();
var toppOffset = $('#topp').offset().top;
if(toppOffset > scrollTop)
alert('true');
});
A clearer representation http://jsfiddle.net/zDpw3/1/