Determine whether a section with class is visible or not, jQuery - javascript

This is a variation of others topics, the idea is to assign a .js-visible to any element in the DOM, and only when it is visible assign to it a .visible class.
The tricky part is that as all of the elements are using the same class name .js-visible I need to assign the class .visible to only the visible element and ignore all the other DOM elements with the same class name. If it was visible and is not anymore then remove the class name .visible
<style>
.visible {
background: green;
}
</style>
<div class="js-visible" style="height:800px">I am 1st</div>
<div class="js-visible" style="height:800px">I am 2nd</div>
<div class="js-visible" style="height:800px">I am 3rd</div>
<div class="js-visible" style="height:800px">I am 4th</div>
This is not working as desired
$(window).scroll(function() {
var hT = $('.js-visible').offset().top,
hH = $('.js-visible').outerHeight(),
wH = $(window).height(),
wS = $(this).scrollTop();
if (wS > (hT+hH-wH) && (hT > wS) && (wS+wH > hT+hH)){
$('.js-visible').addClass('visible')
} else {
$('.js-visible').removeClass('visible')
}
});
Any suggestions?

Based on your code, this function seems to work.
You need to check each element individually.
$(window).scroll(function() {
var wH = $(this).height(),
wS = $(this).scrollTop();
$('.js-visible').each(function() {
var hT = $(this).offset().top,
hH = $(this).outerHeight();
if (wS >= (hT+hH-wH) && (hT >= wS) && (wS+wH >= hT+hH)){
$(this).addClass('visible')
} else {
$(this).removeClass('visible')
}
});
});
.visible {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
.visible {
background: green;
}
</style>
<div class="js-visible" style="height:200px">I am 1st</div>
<div class="js-visible" style="height:200px">I am 2nd</div>
<div class="js-visible" style="height:200px">I am 3rd</div>
<div class="js-visible" style="height:200px">I am 4th</div>

I would like to post a demo of the solution for who needs the same solution, you can adapt to your project
$.fn.isInViewport = function() {
var elementTop = $(this).offset().top;
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
$(window).on('resize scroll', function() {
$('.js-visible').each(function() {
var activeColor = $(this).attr('id');
if ($(this).isInViewport()) {
$(this).addClass('visible');
} else {
$(this).removeClass('visible');
}
});
});
.visible {
background: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<div class="js-visible" style="height:800px">I am 1st</div>
<div class="js-visible" style="height:800px">I am 2nd</div>
<div class="" style="height:800px">I am something else</div>
<div class="" style="height:800px">I am something else</div>
<div class="js-visible" style="height:800px">I am 3rd</div>
<div class="js-visible" style="height:800px">I am 4th</div>

Related

How to hide/show a fixed element when scrolling some sections into view vertically?

I want a fixed element #logoimode3 to hide/show when some sections scroll into view vertically.
For example:
Show #logoimode3 when #section1 and #section3 scroll into view
Hide #logoimode3 when #section2 scrolls into view
So the fixed element should disappear when the blue section scrolls into view. And then show again when the green section scrolls into view.
I want my logo to disappear while scrolling through #section2.
What am I doing wrong?
Here is my HTML code:
<img id="logoimode3" class="logo3" style="position:fixed;top:0px;left:0px;" src="https://imode.info/imode/slike/ikone/IMODE_znak-01.svg" alt="logo" height="" width="30px">
<section id="section1" style="background: red; height:100vh;"></section>
<section id="section2" style="background: blue; height:100vh;"></section>
<section id="section3" style="background: green; height:100vh;"></section>
<footer></footer>
Here is my JavaScript code:
jQuery(document).ready(function($) {
$('#logoimode4').css({
'display': 'none'
});
$(function() {
var $window = $(window);
var logo = $('#logoimode4');
var div1 = $('#section1stran');
var div2 = $('#section2stran');
var div3 = $('#section3stran');
var div4 = $('#section4stran');
var div5b = $('#section5bstran');
var div1_height = div1.height();
var div2_height = div2.height();
var div3_height = div3.height();
var div4_height = div4.height();
var div5b_height = div5b.height();
$window.on('scroll', function() {
var scrollTop = document.documentElement.scrollTop;
var viewport_height = $window.height();
var scrollTop_bottom = scrollTop + viewport_height;
// if (scrollTop >= 0 && (scrollTop_bottom <= div1_height * 1.9 )) {
// logo.css({'display' : 'none'});
// }
if (scrollTop >= div1_height * 0 + div1_height * 1 + div2_height + div3_height + div4_height + div5b_height && (scrollTop_bottom <= div1_height * 5 + div1_height + div2_height + div3_height + div4_height + div5b_height)) {
logo.css({
'display': 'block'
});
} else {
logo.css({
'display': 'none'
});
}
// Work with Class
/* if (scrollTop > div1_height && (scrollTop_bottom <= div1_height * 3)) {
logo.addClass('hidden');
} else {
logo.removeClass('hidden');
} */
});
});
});
get height of section and when the top of section hits 0 it hides and when the bottom of section hits 0 it shows again
<!DOCTYPE html>
<html>
<head>
<style></style>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
jQuery(document).ready(function() {
var sec2 = document.getElementById("section2");
var pos = sec2.getBoundingClientRect();
var height1 = pos.height * -1;
if (pos.top < 1 && pos.top > height1) {
jQuery('#logoimode3').hide();
}
else if(pos.top < height1 || pos.top > 1) {
jQuery('#logoimode3').show();
}
});
jQuery(window).scroll(function() {
var sec2 = document.getElementById("section2");
var pos = sec2.getBoundingClientRect();
var height1 = pos.height * -1;
if (pos.top < 1 && pos.top > height1) {
jQuery('#logoimode3').hide();
}
else if(pos.top < height1 || pos.top > 1) {
jQuery('#logoimode3').show();
}
});
</script>
</head>
<body>
<img id="logoimode3" class="logo3" style="position:fixed;top:0px;left:0px;" src="https://imode.info/imode/slike/ikone/IMODE_znak-01.svg" alt="logo" height="" width="30px">
<section id="section1" style="background: red; height:100vh;"></section>
<section id="section2" style="background: blue; height:100vh;"></section>
<section id="section3" style="background: green; height:100vh;"></section>
<section id="section4" style="background: pink; height:100vh;"></section>
</body>
<footer></footer>
</html>
There is what you need with the full code:
$(function() {
var $window = $(window);
var logo = $('#logoimode3');
var div1 = $('#section1');
var div1_height = div1.height();
$window.scroll(function() {
var scrollTop = $(window).scrollTop();
var viewport_height = $window.height();
var scrollTop_bottom = scrollTop + viewport_height;
if (scrollTop > div1_height && (scrollTop_bottom <= div1_height * 3)) {
logo.css({
'display': 'none'
});
} else {
logo.css({
'display': 'block'
});
}
// Work with Class
/* if (scrollTop > div1_height && (scrollTop_bottom <= div1_height * 3)) {
logo.addClass('hidden');
}
else {
logo.removeClass('hidden');
} */
});
});
.hidden {
display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<img id="logoimode3" class="logo3" style="position:fixed;top:0px;left:0px;" src="https://imode.info/imode/slike/ikone/IMODE_znak-01.svg" alt="logo" height="" width="30px">
<section id="section1" style="background: red; height:100vh;"></section>
<section id="section2" style="background: blue; height:100vh;"></section>
<section id="section3" style="background: green; height:100vh;"></section>

Change CSS of inner div when scroll reaches that div

I am attempting to implement a scroll function where the CSS of the inner div's change when it reaches a certain height from the top.
var $container = $(".inner-div");
var containerTop = $container.offset().top;
var documentTop = $(document).scrollTop();
var wHeight = $(window).height();
var minMaskHeight = 0;
var descriptionMax = 200;
var logoMin = -200;
var maskDelta = descriptionMax - minMaskHeight;
var $jobOverview = $container.find(".right");
var $jobLogo = $container.find(".left");
var curPlacementPer = ((containerTop - documentTop) / wHeight) * 100;
var topMax = 85;
var center = 20;
var bottomMax = -15;
//console.log("Placement: " + curPlacementPer);
function applyChanges(perOpen) {
var maskHeightChange = maskDelta * (perOpen / 100);
var opacityPer = perOpen / 100;
var newDescriptionLeft = descriptionMax - maskHeightChange;
var newLogoLeft = logoMin + maskHeightChange;
if (newDescriptionLeft <= 0) newDescriptionLeft = 0;
if (newLogoLeft >= 0) newLogoLeft = 0;
if (opacityPer >= 1) opacityPer = 1;
$jobOverview.css({
transform: "translate(" + newDescriptionLeft + "%,-50%)",
opacity: opacityPer
});
$jobLogo.css({
transform: "translate(" + newLogoLeft + "%,-50%)",
opacity: opacityPer
});
}
if (window.innerWidth > 640) {
$container.removeClass("mobile");
// console.log("Placement: " + curPlacementPer);
if (curPlacementPer <= topMax /*&& curPlacementPer >= center*/ ) {
var perOpen = ((topMax - curPlacementPer) / 25) * 100;
applyChanges(perOpen);
} else if (curPlacementPer < center /*&& curPlacementPer >= bottomMax*/ ) {
var perOpen = (((bottomMax - curPlacementPer) * -1) / 25) * 100;
applyChanges(perOpen);
} else {
$jobOverview.css({
transform: "translate(200%,-50%)",
opacity: "0"
});
$jobLogo.css({
transform: "translate(-300%,-50%)",
opacity: "0"
});
}
<div class="outer-div">
<div class="inner-div first">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div second">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div third">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div fourth">
<div class="left"></div>
<div class="right"></div>
</div>
</div>
Currently, all of the inner div's gets changed at the same time.
I noticed that when I change the $container class to equal '.first' and specify it more, it works.
Is there any way to make the inner div's change separately, relative to its height from the top? Any way I can iterate the scroll function so I can add more inner div's in the future and not have to worry about changing my scroll function?
In raw JavaScript, this is my answer:
// Define the element -- The '#fooBar' can be changed to anything else.
var element = document.querySelector("#fooBar");
// Define how much of the element is shown before something happens.
var scrollClipHeight = 0 /* Whatever number value you want... */;
// Function to change an element's CSS when it is scrolled in.
const doSomething = function doSomething() {
/** When the window vertical scroll position plus the
* window's inner height has reached the
* top position of your element.
*/
if (
(window.innerHeight + window.scrollY) - (scrollClipHeight || 0) >=
element.getBoundingClientRect().top
)
// Generally, something is meant to happen here.
element.style = "/* Yay, some CSS! */"
};
// Call the function without an event occurring.
doSomething();
// Call the function when the 'window' scrolls.
addEventListener("scroll", doSomething, false)
This is the method I use. If there are other methods, I'd love to see them as well but this is my answer for now.
consider using 3rd party jQuery plugin for easier job, like one of these:
https://github.com/xobotyi/jquery.viewport
or
https://github.com/zeusdeux/isInViewport
then you can have additional element selector e.g.: ":in-viewport"
so you can:
$(window).on('scroll',function() {
$('div').not(':in-viewport').html('');
$('div:in-viewport').html('hello');
});
Check if current scroll offset from top is bigger than the element offset from the top:
$(window).scroll(function() {
var height = $(window).scrollTop();
var element = $('#changethis'); //change this to your element you want to add the css to
if(height > element.offset().top) {
element.addClass('black'); //add css class black (change according to own css)
}
});
Html:
<div id="changethis">Test</div>
Css:
body
{
height:2000px;
}
.black
{
background-color:black;
color:white;
padding:20px;
}
Demo:
https://codepen.io/anon/pen/WZdEap
You could easily implement this in your existing code.
Below is the sample snippet code, Hope it'll work for you:
$(document).ready(function(){
topMax = 100;
topMin = 25;
$(document).scroll(function(){
$('.inner-div').each(function(){
if($(this).offset().top-$(window).scrollTop()<=topMax && $(this).offset().top-$(window).scrollTop()>=topMin){
$(this).css({'background':'#c7c7c7'});
}else{
$(this).css({'background':'inherit'});
}
});
});
});
div{
width:100%;
border:1px solid red;
padding:5px;
}
div.inner-div{
border: 1px dashed green;
height: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="outer-div">
<div class="inner-div first">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div second">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div third">
<div class="left"></div>
<div class="right"></div>
</div>
<div class="inner-div fourth">
<div class="left"></div>
<div class="right"></div>
</div>
</div>
Happy to help you! :)

Crossbrowser solution for disable/enable scroll

Long time ago I found somewhere (on stackoverflow I think) code to scroll one window height per scroll. I tried many libraries but that script works just like I want. But it's jumpy when scrolling during animation. So I disable scroll during animation but it works only in Firefox.
I made a fiddle: https://jsfiddle.net/msoys5gc/1/
if( $(window).scrollTop() < $(window).height() * 6 ) {
window.onwheel = function(){ return false; };
}
$('html,body').stop().animate({
scrollTop: divs.eq(div).offset().top
}, 600, function() {
window.onwheel = function(){ return true; };
});
I don`t understand this:
if( $(window).scrollTop() < $(window).height() * 6 )
this will be true until you pass the six slide...
UPDATED: If you want to stop triggering the animation while it is running you can just delete the stop(). Then if you don't want to enqueue animations(and then get strange behaviors), you can just call clearQueue() when the animation has finished.
var divs = $('.section');
var dir = 'up'; // wheel scroll direction
var div = 0; // current div
$(document.body).on('DOMMouseScroll mousewheel', function (e) {
if (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
dir = 'down';
}
else {
dir = 'up';
}
// find currently visible div :
div = -1;
divs.each(function(i){
if (div<0 && ($(this).offset().top >= $(window).scrollTop())) {
div = i;
}
});
if (dir == 'up' && div > 0) {
div--;
}
if (dir == 'down' && div < divs.length) {
div++;
}
$('html,body').animate({
scrollTop: divs.eq(div).offset().top
}, 1600, function() {
$('html,body').clearQueue();
});
return false;
});
$(window).resize(function () {
$('html,body').scrollTop(divs.eq(div).offset().top);
});
.section {
height: 100vh;
}
body{
margin: 0px !important;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="section" style="background: yellow;"></div>
<div class="section" style="background: green;"></div>
<div class="section" style="background: blue;"></div>
<div class="section" style="background: red;"></div>
<div class="section" style="background: violet;"></div>
<div class="section" style="background: orange;"></div>
<div class="section" style="background: black;"></div>

Show/hide a div 500 px from top and 500 px before bottom

I have a page where I want an image to appear after scrolling say 500px and I used the "If you want to show a div after scrolling a number of pixels, WITHOUT jquery" code snippet from apaul34208 (show div after 800px scroll). My adapted code is like this:
<!DOCTYPE html>
<html>
<body>
<div id="myID" class="pointer hide">
<img src="image.png">
</div>
<script>
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400) {
myID.className = "pointer show"
} else {
myID.className = "pointer hide"
}
};
window.addEventListener("scroll", myScrollFunc);
</script>
</body>
</html>
and CSS:
.hide {
display: none;
}
.show {
display: block;
margin-top: -80px;
}
Only problem is that I would also like it to DISAPPEAR again lets say 400 px from the bottom of the page. the page-height differs from page to page so I cant just set a range like underneath from say 400-1000 px.
<script>
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400 & y <= 1000 ) {
myID.className = "pointer show"
} else {
myID.className = "pointer hide"
}
};
window.addEventListener("scroll", myScrollFunc);
</script>
</body>
</html>
Anyone have any idea how I can make this happen?
Thanks guys!
$(document).ready(function() {
$(window).scroll(function() {
console.log('scrolling ', $(window).scrollTop(), $(document).height());
if ($(window).scrollTop() >= 400 && $(window).scrollTop() <= ($(document).height() - 600)) {
$('#myID').removeClass('hide');
}
else {
$('#myID').addClass('hide');
}
});
});
.hide {
display: none;
}
.body {
height: 2000px;
}
#myID {
background-color: lightgray;
position: fixed;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="body">
<div id="myID" class="pointer hide">
STUFF HERE
</div>
</div>
use document.height to get the height of the document and rest the desired value:
myID = document.getElementById("myID");
var myScrollFunc = function () {
var y = window.scrollY;
if (y >= 400 & y <= document.height - 400) {
myID.className = "pointer show";
} else {
myID.className = "pointer hide";
}
};
window.addEventListener("scroll", myScrollFunc);

Show Div when scrolled to top edge not bottom edge

I am using the code from here but i need it to show the div when the top scrolls into view not the bottom, how can i achieve this?
JS Fiddle
$(document).ready(function() {
$(window).scroll( function(){
$('.hide').each( function(i){
var bottom_of_object = $(this).position().top + $(this).outerHeight();
var bottom_of_window = $(window).scrollTop() + $(window).height();
if( bottom_of_window > bottom_of_object ){
$(this).animate({'opacity':'1'},500);
}
});
});
});
Simple fix. The trick is to .animate() when you actually hit the top. Right now, you're using
var bottom_of_object = $(this).position().top + $(this).outerHeight()
You don't need $(this).outerHeight() because that increases the y position to which you need to scroll by the height of the div. Just remove it so that you have
var top_of_object = $(this).position().top
$(document).ready(function() {
$(window).scroll(function() {
$('.hide').each(function(i) {
var bottom_of_object = $(this).position().top
var bottom_of_window = $(window).scrollTop() + $(window).height()
if (bottom_of_window > bottom_of_object)
$(this).animate({ opacity: '1' }, 500)
})
})
})
#container { height: 2000px }
#container div { background-color: gray; margin: 20px; padding: 80px }
.hide { opacity: 0 }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<div>shown</div>
<div>shown</div>
<div>shown</div>
<div>shown</div>
<div>shown</div>
<div>shown</div>
<div class="hide">Fade In</div>
<div class="hide">Fade In</div>
<div class="hide">Fade In</div>
<div class="hide">Fade In</div>
<div class="hide">Fade In</div>
</div>
fiddle (for posterity)

Categories