jQuery code keeps running after scroll - javascript

I want to show an page element after header element will be out ofthe viewport. To achieve this, I created simple JS:
var scrollHeight = $(document).scrollTop(),
headerHeight = $('.big-header').outerHeight(true),
setHead = 0;
console.log(scrollHeight +' / '+ headerHeight);
if(scrollHeight >= headerHeight) {
if(setHead == 0) {
alert(setHead);
setHead = 1;
}
}
My problem is, alert(setHead) is running constantly. There's propably some minor thing I forgot, but I can't seem to get it done.
Fiddle here.

Move your sethead out of the scroll function,
var setHead = 0;
$(window).scroll(function () {
var scrollHeight = $(document).scrollTop(),
headerHeight = $('.big-header').outerHeight(true);
console.log(scrollHeight + ' / ' + headerHeight);
if (scrollHeight >= headerHeight) {
if (setHead == 0) {
alert(setHead);
setHead = 1;
}
} else {
setHead = 0;
}
});
http://jsfiddle.net/9P36u/1/

define var setHead = 0; before $(window).scroll(function().
In your function setHead is always being 0.

Related

apply function on all elements with same class

I have a simple function which detects if an element is in the viewport or that it is visible. If that element is visible, on every scroll I move that element down with .css() and change the top property to achieve some parallax effect. This element on which I check is in the viewport and when it moves it is repeated X times on the page. Everything works but only on the first element has this problem, all other elements inherit top position from the first.
Demo: http://codepen.io/riogrande/pen/RRVVwq (scroll down for effect).
EDIT: Some who answered had the wrong idea what I want, so I want the title (element) to move on scroll but only when its in viewport(visible). So when the first element with same class is visible its moving with scroll, then when you scroll below it its not visible anymore it should not move but the other one which is visible should be moving etc etc.
Jquery:
(function($) {
'use strict';
$.prototype.isVisible = function() {
var rect = this[0].getBoundingClientRect();
return (
(rect.height > 0 || rect.width > 0) &&
rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
);
};
function doCheck() {
var elementToDetect = $('.text');
var scrolled = $(window).scrollTop();
if (elementToDetect.isVisible()) {
elementToDetect.css('top', (-100 + (scrolled * 0.2)) + 'px');
}
}
$(document).ready(function() {
doCheck();
});
$(window).scroll(function() {
doCheck();
});
})(jQuery);
jQuery applies operations like css() on each element matching the selector.
So if you iterate the jQuery object, you get this:
function doCheck() {
var elementToDetect = $('.text');
var scrolled = $(window).scrollTop();
for (var index = 0; index < elementToDetect.length; index++) {
var element = $(elementToDetect[index]);
if (element.isVisible()) {
element.css('top', (-100 + (scrolled * 0.2)) + 'px');
}
}
}
Which still has a problem, in that all the text maintain the same top relative to their image.
Edit:
Actually, the way I understand what you're doing, you want to let them all move in the same way as you scroll, so each starts above the image when it comes into view. This is closer to what you need:
function doCheck() {
var elementToDetect = $('.text');
for (var index = 0; index < elementToDetect.length; index++) {
var text = elementToDetect[index];
var parent = text.parentElement;
var parentTop = parent.getBoundingClientRect().top;
var scrolled = (window.innerHeight - parentTop);
if (scrolled < 0) {
scrolled = 0;
}
if (parentTop < window.innerHeight) {
$(text).css('top', (-100 + (scrolled * 0.2)) + 'px');
}
}
}
Basically, looking at scrollTop() is wrong, because you really want the position of the parent div to determine the placement of your text.
Here you need to check for each .text on the scroll:
function doCheck() {
var elementToDetect = $('.text');
var scrolled = $(window).scrollTop();
elementToDetect.each(function(i, txtEl) {
if (txtEl.isVisible()) {
txtEl.css('top', (-100 + (scrolled * 0.2)) + 'px');
}
});
}
And most likely you want to have a debouce there in the window.scroll:
var timer;
$(window).scroll(function() {
if(timer){ clearTimeout(timer); }
timer = setTimeout(function(){
doCheck();
}, 900);
});
$('.text') returns an array of elements. You need to apply the css transform to each item rather than the array of items. The below code may require an update to get the output you would like but I think it should get you going.
function doCheck() {
var scrolled = $(window).scrollTop();
$('.text').each(function() {
if($(this).isVisible()) {
$(this).css('top', (-100 + (scrolled * 0.2)) + 'px');
}
})
}

Function not starting when scroll point is over top of the div

I use a scrollTop function to start animations, delays, etc when the div is scrolled to. It works for other things on my page, but for some reason, this function is not working and it loads on page load.
Does anyone see anything wrong in my code? This can be seen live here:
<div class="blue-box-container">
</div>
$(function() {
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});
$('.fadeBlock').css('display', 'none');
blueBoxDelays();
function blueBoxDelays() {
var delay = 0;
$('.fadeBlock').each(function(i) {
$(this).delay(400 + delay).fadeIn(1000);
delay = 200 * (i + 1);
});
};
I extracted your code to a fiddle and it works correctly https://jsfiddle.net/26jw7Low/3/, you just need to remove the call to blueBoxDelays() which is outside of the initial function as seen below.
$(function() {
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});
$('.fadeBlock').css('display', 'none');
// REMOVE THIS blueBoxDelays();
function blueBoxDelays() {
var delay = 0;
$('.fadeBlock').each(function(i) {
$(this).delay(400 + delay).fadeIn(1000);
delay = 200 * (i + 1);
});
};
Function $('.fadeBlock').css('display', 'none'); maybe not yet execute
You can put it to $(function(){}) end try again:
$(function() {
$('.fadeBlock').css('display', 'none');
var oTop = $('.blue-box-container').offset().top - window.innerHeight;
$(window).scroll(function() {
var pTop = $('body').scrollTop();
console.log(pTop + ' - ' + oTop);
if (pTop > oTop) {
blueBoxDelays();
}
});
});

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

Making the scrolling div stop at the bottom

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

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