Making the scrolling div stop at the bottom - javascript

I'm trying to get this div to stop at the bottom but for some reason once it reaches the bottom it starts jumping around.
Any ideas? It seems like even when bottom_offset < 181 it still keeps changing the css top property.
<script>
jQuery(document).ready(function() {
var el = jQuery('#contactBox');
top_offset = jQuery('#contactBox').offset().top - 60;
var box_height = el.height();
jQuery(window).scroll(function() {
var scroll_top = jQuery(window).scrollTop();
var bottom_offset = jQuery(document).height() - scroll_top - box_height;
var new_top_offset = jQuery(document).height() - box_height - 100;
if ((scroll_top > top_offset) && (bottom_offset > 180)) {
el.css('top', scroll_top - top_offset);
}
else if ((scroll_top > top_offset) && (bottom_offset < 181)) {
el.css('top', new_top_offset);
}
else {
el.css('top', '');
}
});
});
</script>

Not sure how the html and css is setup so I'm taking a guess.
If the div has a fixed position, you can remove the following code and it should stop at the bottom.
The new_top_offset made the div jump down when i scrolled near the bottom.
else if ((scroll_top > top_offset) && (bottom_offset < 181)) {
el.css('top', new_top_offset);
}
else {
el.css('top', '');

Well I went ahead and changed it so that it worked a bit differently. It would just calculate body height minus footer height and also do scroll top + height of the scrolling div, and then it only changes css if total_height < body_height.
Here's the code if anyone needs it in the future.
jQuery(document).ready(function() {
var el = jQuery('#contactBox');
top_offset = jQuery('#contactBox').offset().top - 60;
var box_height = el.height();
jQuery(window).scroll(function() {
var scroll_top = jQuery(window).scrollTop();
var total_height = scroll_top + box_height;
var body_height = jQuery('body').outerHeight() - 150;
if ((scroll_top > top_offset) && (total_height < body_height)) {
el.css('top', scroll_top - top_offset);
}
});
});

Related

How to check if div reaches top of page for each div?

This is my current solution to check if a specific div reaches the top of the page, which i got from here https://stackoverflow.com/a/5279537/4671165
document.addEventListener("scroll", Scroll, false);
function Scroll() {
var top = $('.element').offset().top - $(document).scrollTop();
if (top < 150){
var textvariable = $('.text').text();
}
}
But i want this to do something each time a different div reaches the top of the page, therefore i currently have
var top1 = $('.element1').offset().top - $(document).scrollTop();
var top2 = $('.element2').offset().top - $(document).scrollTop();
var top3 = $('.element3').offset().top - $(document).scrollTop();
if (top1 < 150 && top2 > 150){
var textvariable = $('.text1').text();
}
if (top1 < 150 && top2 < 150 && top3 > 250){
var textvariable = $(.text2').text();
}
if (top2 < 150 && top3 < 250){
var textvariable = $(.text3').text();
}
However, this doesn't seem the most effective way but i can't figure out what is. Especially since i have more elements then just 3 in the project. So i am looking for a more effective way.
I put this together using ES6. I believe this should work. It's been a while since I've used getBoundingClientRect() though.
var divs = document.querySelectAll('div');
document.addEventListener("scroll", Scroll, false);
function Scroll() {
divs.forEach((memo,index) => {
let divTop = memo.getBoundingClientRect().top;
if (divTop <= 0) {
var textvariable = $('.text' + index).text();
});
}
Hope this helps. It should be easier to use and it has a lot of bugs already fixed for you. It's a 1.82 kb file so there's not really much useless stuff into it if added.
I found a jquery solution
function ScrollStart() {
var scrolled = $(this).scrollTop();
/*filter current element at the top with a certain class & give it active class*/
$('.step').removeClass('activetext').filter(function() {
return scrolled <= $(this).offset().top + $(this).height() - 50 && scrolled >= $(this).offset().top - 50;
}).addClass('activetext');
/* make exclusion for first element */
var boven = $('.first').offset().top - $(document).scrollTop();
if (boven > 0){
$('.first').addClass('activetext');
}
/*make exclusion for last element*/
var bottom = $('.last').offset().top - ($('.last').height()/5) - $(document).scrollTop();
if (bottom < 150){
$('.step').removeClass('activetext')
$('.last').addClass('activetext');
}
else{
$('.last').removeClass('activetext')
}
/* give variable 'text' the text of the active class & append it */
var text = $('.activetext .headertekst').text();
$('.dropbtn').empty();
$('.dropbtn').append(text);
$('.dropbtn').append('<img src="images/downarrow.svg" galleryimg="no"></img>');
}

Replace fixed image at scroll down and change it to relative after

What I'm trying to do is a onepage website where the first "section" is a big background image (actually 4 of them, same size and same position) which should change when the user scrolls ( Just accessed the website - image1 ; Scrolled down once - image2; Scrolled down once again: image3 and so on). I tried with the js from http://jsfiddle.net/WTkqn/, but the problem is the images are fixed, though I need the webpage to scroll down as usually after the last image. I'm pretty new to javascript so any help would be highly appreciated.
As an example is http://airnauts.com/, after all the scrolling to the top area is done, the website scrolls down to the rest of the content.
$(document).ready(function(){
var offset2 = $(document).height();
var lineHF = offset2 - $("#bottommark").position().top;
$(window).scroll(function(){
var offset1 = $(document).height();
var offset = $(window).scrollTop();
var lineH = offset1 - $("#bottommark").position().top - offset;
var lineHpart = lineHF/5;
$("span").html(lineH);
if (lineH > lineHpart*4) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful1.jpg");
}
if ((lineH < lineHpart*4) && (lineH > lineHpart*3)) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful2.jpg");
}
if ((lineH < lineHpart*3) && (lineH > lineHpart*2)) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful3.jpg");
}
if (lineH < lineHpart*2 && lineH > lineHpart*1) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful4.jpg");
}
if (lineH < lineHpart) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful5.jpg");
}
});
});
Try this. I've added an additional condition lineH > lineHpart/2 in the last if-else statement which coincides with the height of the image. Also, in the last else, i've changed the css property from position:fixed to position:relative. On the way up, once the condition matches for last if-else, it would set the property from position:relative to position:fixed.
$(document).ready(function(){
var offset2 = $(document).height();
var lineHF = offset2 - $("#bottommark").position().top;
var changeRelative = false;
$(window).scroll(function(){
var offset1 = $(document).height();
var offset = $(window).scrollTop();
var lineH = offset1 - $("#bottommark").position().top - offset;
var lineHpart = lineHF/5;
$("#animation").css("position","fixed"); // set position:fixed by default
$("span").html(lineH);
if (lineH > lineHpart*4) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful1.jpg");
}
else if ((lineH < lineHpart*4) && (lineH > lineHpart*3)) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful2.jpg");
}
else if ((lineH < lineHpart*3) && (lineH > lineHpart*2)) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful3.jpg");
}
else if (lineH < lineHpart*2 && lineH > lineHpart*1) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful4.jpg");
}
else if (lineH < lineHpart && lineH > lineHpart/2) {
$("#animation").attr("src", "http://coverjunction.s3.amazonaws.com/manual/low/colorful5.jpg");
}
else
{
$("#animation").css("position","relative");
}
});
});
Here's a working example : https://jsfiddle.net/WTkqn/301/

How to find Multiple div reach top?

I have a survey page divided into sections. As the user scrolls, each section's header sticks to the top of the screen until the next section is reached. I was able to do it for the first and second section but I am not sure how to do it for the third one. There must be a better way to do this.
Here is my code and a jsfiddle
Thank you
var s = $("#block2 .question-title-block");
var pos = s.position();
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
if ($(this).scrollTop() > 404) {
$('#block1 .question-title-block').addClass("sticky");
if (windowpos >= pos.top) {
$('#block2 .question-title-block').addClass("sticky");
$('#block1 .question-title-block').removeClass("sticky");
}
else{
$('#block2 .question-title-block').removeClass("sticky");
}
}
else{
$('#block1 .question-title-block').removeClass("sticky");
$('#block2 .question-title-block').removeClass("sticky");
}
})
If you want it to be applied to as many elements as you want, don't use them individually, use their class. Here is what you can do:
var titleBlocks = $(".question-title-block");
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
titleBlocks.each(function(){
$(this).toggleClass('sticky', $(this).parent().offset().top <= windowpos);
});
});
JS Fiddle Demo
try this (allows for any number of question blocks):
var containers = $('.question-block-container');
$(window).scroll(function () {
var windowpos = $(window).scrollTop();
containers.each(function () {
var container = $(this),
title = container.find('.question-title'),
contOffsetTop = container.offset().top,
conOffsetBottom = contOffsetTop + container.outerHeight() + 60; // 60 is margin bottom
if (windowpos >= contOffsetTop && windowpos <= conOffsetBottom) {
if (!title.hasClass("sticky")) {
title.addClass("sticky");
}
} else if (title.hasClass("sticky")) {
title.removeClass("sticky");
}
});
});
Example

Button Fade In/Out glitching/not working.

I want to make a button that will appear after the user scrolls screen.availheight but disappear after the user hits the bottom, which I want it to be (screen.availheight * 5).
My button seems to be glitching and not working occasionally. Here's my code;
jQuery(document).ready(function(){
var offset1 = (screen.availHeight);
var offset2 = (screen.availHeight * 5);
var duration2 = 500;
jQuery(window).scroll(function(){
if (jQuery(this).scrollTop() > offset1){
jQuery('.gdb').fadeIn(duration2);
} else {
jQuery('.gdb').fadeOut(duration2);
}
});
});
NOTE: I removed the code that made by button glitch. With the code above the button only appears after the user scrolls offset1
May be this piece of code works for you.
if($(document)[0].scrollHeight>0 && $(document)[0].scrollHeight < $(document).height()){
$('.gdb').fadeIn();
}
elseif($(document)[0].scrollHeight == $(document).height()){
$('.gdb').fadeOut();
}
try this code:
var btn_visible = 0;//used this variable so that button fadeIn/fadeOut does not fire unnecessary
$( window ).scroll(function(e) {
var offset1 = (screen.availHeight);
var offset2 = (screen.availHeight * 2);
var duration2 = 500;
if ($(this).scrollTop() > offset1 && $(this).scrollTop() < offset2 && btn_visible==1){
jQuery('.gdb').fadeOut(duration2);
btn_visible = 0;
} else if($(this).scrollTop() > offset2 && btn_visible==0){
$('.gdb').fadeIn(duration2);
btn_visible = 1;
}
});

Scroll if element is not visible

how to determine, using jquery, if the element is visible on the current page view. I'd like to add a comment functionality, which works like in facebook, where you only scroll to element if it's not currently visible. By visible, I mean that it is not in the current page view, but you can scroll to the element.
Live Demo
Basically you just check the position of the element to see if its within the windows viewport.
function checkIfInView(element){
var offset = element.offset().top - $(window).scrollTop();
if(offset > window.innerHeight){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset}, 1000);
return false;
}
return true;
}
Improving Loktar's answer, fixing the following:
Scroll up
Scroll to a display:none element (like hidden div's etc)
function scrollToView(element){
var offset = element.offset().top;
if(!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = $(window).scrollTop();
var visible_area_end = visible_area_start + window.innerHeight;
if(offset < visible_area_start || offset > visible_area_end){
// Not in view so scroll to it
$('html,body').animate({scrollTop: offset - window.innerHeight/3}, 1000);
return false;
}
return true;
}
After trying all these solutions and many more besides, none of them satisfied my requirement for running old web portal software (10 years old) inside IE11 (in some compatibility mode). They all failed to correctly determine if the element was visible. However I found this solution. I hope it helps.
function scrollIntoViewIfOutOfView(el) {
var topOfPage = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
var heightOfPage = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
var elY = 0;
var elH = 0;
if (document.layers) { // NS4
elY = el.y;
elH = el.height;
}
else {
for(var p=el; p&&p.tagName!='BODY'; p=p.offsetParent){
elY += p.offsetTop;
}
elH = el.offsetHeight;
}
if ((topOfPage + heightOfPage) < (elY + elH)) {
el.scrollIntoView(false);
}
else if (elY < topOfPage) {
el.scrollIntoView(true);
}
}
I made a slightly more generic version of digitalPBK's answer that minimally scrolls an element contained within a div or some other container (including the body). You can pass DOM elements or selectors to the function, as long as the element is somehow contained within the parent.
function scrollToView(element, parent) {
element = $(element);
parent = $(parent);
var offset = element.offset().top + parent.scrollTop();
var height = element.innerHeight();
var offset_end = offset + height;
if (!element.is(":visible")) {
element.css({"visibility":"hidden"}).show();
var offset = element.offset().top;
element.css({"visibility":"", "display":""});
}
var visible_area_start = parent.scrollTop();
var visible_area_end = visible_area_start + parent.innerHeight();
if (offset-height < visible_area_start) {
parent.animate({scrollTop: offset-height}, 600);
return false;
} else if (offset_end > visible_area_end) {
parent.animate({scrollTop: parent.scrollTop()+ offset_end - visible_area_end }, 600);
return false;
}
return true;
}
You can take a look at his awesome link from the jQuery Cookbook:
Determining Whether an Element Is Within the Viewport
Test if Element is contained in the Viewport
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
if (
(elementOffset.top > minTop && elementOffset.top + elementHeight < maxTop) &&
(elementOffset.left > minLeft && elementOffset.left + elementWidth < maxLeft)
) {
alert('entire element is visible');
} else {
alert('entire element is not visible');
}
});
Test how much of the element is visible
jQuery(document).ready(function() {
var viewportWidth = jQuery(window).width(),
viewportHeight = jQuery(window).height(),
documentScrollTop = jQuery(document).scrollTop(),
documentScrollLeft = jQuery(document).scrollLeft(),
$myElement = jQuery('#myElement'),
verticalVisible, horizontalVisible,
elementOffset = $myElement.offset(),
elementHeight = $myElement.height(),
elementWidth = $myElement.width(),
minTop = documentScrollTop,
maxTop = documentScrollTop + viewportHeight,
minLeft = documentScrollLeft,
maxLeft = documentScrollLeft + viewportWidth;
function scrollToPosition(position) {
jQuery('html,body').animate({
scrollTop : position.top,
scrollLeft : position.left
}, 300);
}
if (
((elementOffset.top > minTop && elementOffset.top < maxTop) ||
(elementOffset.top + elementHeight > minTop && elementOffset.top +
elementHeight < maxTop))
&& ((elementOffset.left > minLeft && elementOffset.left < maxLeft) ||
(elementOffset.left + elementWidth > minLeft && elementOffset.left +
elementWidth < maxLeft)))
{
alert('some portion of the element is visible');
if (elementOffset.top >= minTop && elementOffset.top + elementHeight
<= maxTop) {
verticalVisible = elementHeight;
} else if (elementOffset.top < minTop) {
verticalVisible = elementHeight - (minTop - elementOffset.top);
} else {
verticalVisible = maxTop - elementOffset.top;
}
if (elementOffset.left >= minLeft && elementOffset.left + elementWidth
<= maxLeft) {
horizontalVisible = elementWidth;
} else if (elementOffset.left < minLeft) {
horizontalVisible = elementWidth - (minLeft - elementOffset.left);
} else {
horizontalVisible = maxLeft - elementOffset.left;
}
var percentVerticalVisible = (verticalVisible / elementHeight) * 100;
var percentHorizontalVisible = (horizontalVisible / elementWidth) * 100;
if (percentVerticalVisible < 50 || percentHorizontalVisible < 50) {
alert('less than 50% of element visible; scrolling');
scrollToPosition(elementOffset);
} else {
alert('enough of the element is visible that there is no need to scroll');
}
} else {
// element is not visible; scroll to it
alert('element is not visible; scrolling');
scrollToPosition(elementOffset);
}
The following code helped me achieve the result
function scroll_to_element_if_not_inside_view(element){
if($(window).scrollTop() > element.offset().top){
$('html, body').animate( { scrollTop: element.offset().top }, {duration: 400 } );
}
}
Here is the solution I came up with, working both up and down and using only Vanilla Javascript, no jQuery.
function scrollToIfNotVisible(element) {
const rect = element.getBoundingClientRect();
// Eventually an offset corresponding to the height of a fixed navbar for example.
const offset = 70;
let scroll = false;
if (rect.top < offset) {
scroll = true;
}
if (rect.top > window.innerHeight) {
scroll = true;
}
if (scroll) {
window.scrollTo({
top: (window.scrollY + rect.top) - offset,
behavior: 'smooth'
})
}
}
There is a jQuery plugin which allows us to quickly check if a whole element (or also only part of it) is within the browsers visual viewport regardless of the window scroll position. You need to download it from its GitHub repository:
Suppose to have the following HTML and you want to alert when footer is visible:
<section id="container">
<aside id="sidebar">
<p>
Scroll up and down to alert the footer visibility by color:
</p>
<ul>
<li><span class="blue">Blue</span> = footer <u>not visible</u>;</li>
<li><span class="yellow">Yellow</span> = footer <u>visible</u>;</li>
</ul>
<span id="alert"></span>
</aside>
<section id="main_content"></section>
</section>
<footer id="page_footer"></footer>
So, add the plugin before the close of body tag:
<script type="text/javascript" src="js/jquery-1.12.0.min.js"></script>
<script type="text/javascript" src="js/jquery_visible/examples/js/jq.visible.js"></script>
After that you can use it in a simple way like this:
<script type="text/javascript">
jQuery( document ).ready(function ( $ ) {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
$(window).scroll(function() {
if ($("footer#page_footer").visible(true, false, "both")) {
$("#main_content").css({"background-color":"#ffeb3b"});
$("span#alert").html("Footer visible");
} else {
$("#main_content").css({"background-color":"#4aafba"});
$("span#alert").html("Footer not visible");
}
});
});
</script>
Here a demo
No-JQuery version.
The particular case here is where the scroll container is the body (TBODY, table.body) of a TABLE (scrolling independently of THEAD). But it could be adapted to any situation, some simpler.
const row = table.body.children[ ... ];
...
const bottomOfRow = row.offsetHeight + row.offsetTop ;
// if the bottom of the row is in the viewport...
if( bottomOfRow - table.body.scrollTop < table.body.clientHeight ){
// ... if the top of the row is in the viewport
if( row.offsetTop - table.body.scrollTop > 0 ){
console.log( 'row is entirely visible' );
}
else if( row.offsetTop - table.body.scrollTop + row.offsetHeight > 0 ){
console.log( 'row is partly visible at top')
row.scrollIntoView();
}
else {
console.log( 'top of row out of view above viewport')
row.scrollIntoView();
}
}
else if( row.offsetTop - table.body.scrollTop < table.body.clientHeight ){
console.log( 'row is partly visible at bottom')
row.scrollIntoView();
}
else {
console.log( 'row is out of view beneath viewport')
row.scrollIntoView();
}
I think this is the complete answer. An elevator must be able to go both up and down ;)
function ensureVisible(elementId, top = 0 /* set to "top-nav" Height (if you have)*/) {
let elem = $('#elementId');
if (elem) {
let offset = elem.offset().top - $(window).scrollTop();
if (offset > window.innerHeight) { // Not in view
$('html,body').animate({ scrollTop: offset + top }, 1000);
} else if (offset < top) { // Should go to top
$('html,body').animate({ scrollTop: $(window).scrollTop() - (top - offset) }, 1000);
}
}
}

Categories

Resources