Detect when a div with fixed position crosses over another element
You have to take the div heights in account.
There is two "moments" to caculate, the enter and the leave.
So when the bottom of the fixed div enters the top of the scrolled one...
And when the bottom of the scrolled one leaves the top of the fixed.
Here is an example to run:
$(window).scroll(function(){ var fixed = $("div.fixed"); var fixed_position = $("div.fixed").offset().top; var fixed_height = $("div.fixed").height();
var toCross_position = $(".div-to-cross").offset().top; var toCross_height = $(".div-to-cross").height();
if (fixed_position + fixed_height < toCross_position) { fixed.removeClass('white'); } else if (fixed_position > toCross_position + toCross_height) { fixed.removeClass('white'); } else { fixed.addClass('white'); }
});
.fixed{ position:fixed; top:calc(50% - 50px); left:0; background-color:black; height:100px; width:100%;}.white{ background-color:white;}.div-to-cross{ height:100px; background-color:blue;}
/* just for this demo */.spacer{ height:400px;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="fixed"></div><div class="spacer"></div><div class="div-to-cross"></div><div class="spacer"></div>
Detect when a position: fixed; element crosses over another element
$(window).scroll(function () {
if ($(".fixedposition").offset().top < ($(".footer").offset().top - 30)) {
$(".fixedposition").css("top", "30px");
$(".fixedposition").css("display", "block");
} else {
$(".fixedposition").css("display", "none");
}
});
see fiddle here: http://jsfiddle.net/flish/T6x4R/
Of course you should probably do something else other than set display:none;
for your fixed div
Detect when multiple static elements overlaps fixed element position on scroll
for (var i = 0; i < images.length; i++) {
var item = images[i]
let b = item.getBoundingClientRect();
if (a.top <= (b.top + b.height) && (a.top + a.height) > b.top) {
logo.style.color = 'white';
break;
} else {
logo.style.color = 'black';
}
};
Updated content:
1. For this solution, I need using break
statement in loop, so I am using for
instead of foreach
2. We need break
if logo is inside in every image.
WHY?:
If logo
is inside image1
, then its' color can be white
, but next step, its' color can be black
, because logo
is not inside image2
.
Below code is more readable for this solution:
const logo = document.querySelector('.logo');
const images = document.querySelectorAll('.image');
function isInsideInImages(images, logoPos) {
for (var i = 0; i < images.length; i++) {
let imagePos = images[i].getBoundingClientRect();
if (logoPos.top <= (imagePos.top + imagePos.height) && (logoPos.top + logoPos.height) > imagePos.top) {
return true;
}
};
return false;
}
window.addEventListener('scroll', function () {
const a = logo.getBoundingClientRect();
if (isInsideInImages(images, a)) {
logo.style.color = 'white';
} else {
logo.style.color = 'black';
}
});
Show/Hide (Toggle) a Fixed Element Depending on Other Elements When Scrolling?
Is this what you want?
If yes, the solution is that you should consider the distance of the window's top to #div2(the center part)
Edited
Add the feature that the comments metioned
$(document).ready(function() { var $window = $(window); var div2 = $('#div2'); var div1 = $('#div1'); $window.on('scroll', function() { var scrollTop = document.documentElement.scrollTop; var viewport_height = $window.height(); var scrollTop_bottom = scrollTop + viewport_height; var window_top_to_div2 = ($window.height()-div2.height())/2; var div1_top = div1.offset().top; var div1_height = div1.height(); var div1_bottom = div1_top + div1_height; div2.toggleClass('show', scrollTop >= (div1_top-window_top_to_div2) && (scrollTop + window.innerHeight) <= (div1_bottom+window_top_to_div2)); });});
body { background: #ccffcc; padding: 0; margin: 0; border: 0; text-align: center;}
#div1 { background: #0099ff; height: 1500px; color: #fff;}
#div2 { width: 100px; height: 100px; text-align: center; position: fixed; margin: auto; top: 0; left: 0; bottom: 0; right: 0; background: #ffff00; color: #000; display: none;}
#div2.show { display: block;}
#div3 { height: 1500px; color: #000;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<br><br><br><br><br> Scroll area before <b>div1</b> appears<br><br><br><br><br><br><div id="div1"> <div id="div2">This is <b>div2</b></div> This is <b>div1</b> <br> <i>(Toggle show/hide <b>div2</b> when the top of <b>div2</b> passes the top of <b>div1</b>)</i></div><div id="div3"> This is <b>div3</b> <br> <i>(Toggle show/hide <b>div2</b> when the bottom of <b>div2</b> reaches the top of <b>div3</b>)</i></div>
Detect whether an element has position:fixed (possibly by parent element) via jQuery
Here is a solution based on walking through the element's parents, checking the CSS position value for each in turn.
Is this the most efficient way, or is there a way to detect the effective positioning by only examining the element itself?
http://jsfiddle.net/Q4mSJ/
CSS
.trigger-event {background:#ccc}
#one {position:relative; height:50px; width:50px}
#two-wrapper {position:fixed; bottom:0; height:50px; width:50px}
#two {height:50px; width:50px}
HTML
<div id="one" class="trigger-event">element one</div>
<div id="two-wrapper">
<div id="two" class="trigger-event">element two</div>
</div>
JS
function elementOrParentIsFixed(element) {
var $element = $(element);
var $checkElements = $element.add($element.parents());
var isFixed = false;
$checkElements.each(function(){
if ($(this).css("position") === "fixed") {
isFixed = true;
return false;
}
});
return isFixed;
}
$(document).ready(function(){
$('.trigger-event').on('mouseenter', function(event){
var isFixed = elementOrParentIsFixed(event.target);
if (isFixed) {
$(event.target).css('background','red');
} else {
$(event.target).css('background','green');
}
});
});
Is there a way to know when an element pass over another element?
You can listen on an event that fires every time the page is scrolled and then check if it's location is past your hr#line-before-related-article.
Here's an example:
$(window).on('scroll', function() {
if ($(this).scrollTop() + $(this).height() >= $('#line-before-related-article').position().top) {
$('.sticky-footer').hide();
} else if ($('#line-before-related-article').position().top >= $(this).scrollTop()) {
$('.sticky-footer').show();
}
})
If you want something that's a little more performant, you can use something called a debounce function...
For those of you who don't know what a debounce function does, it limits the rate at which a function can fire. A quick example: you have a resize listener on the window which does some element dimension calculations and (possibly) repositions a few elements. That isn't a heavy task in itself but being repeatedly fired after numerous resizes will really slow your site down. Why not limit the rate at which the function can fire?
More on that here: https://davidwalsh.name/javascript-debounce-function
Fixed position but relative to container
Short answer: no. (It is now possible with CSS transform. See the edit below)
Long answer: The problem with using "fixed" positioning is that it takes the element out of flow. thus it can't be re-positioned relative to its parent because it's as if it didn't have one. If, however, the container is of a fixed, known width, you can use something like:
#fixedContainer {
position: fixed;
width: 600px;
height: 200px;
left: 50%;
top: 0%;
margin-left: -300px; /*half the width*/
}
http://jsfiddle.net/HFjU6/1/
Edit (03/2015):
This is outdated information. It is now possible to center content of an dynamic size (horizontally and vertically) with the help of the magic of CSS3 transform. The same principle applies, but instead of using margin to offset your container, you can use translateX(-50%)
. This doesn't work with the above margin trick because you don't know how much to offset it unless the width is fixed and you can't use relative values (like 50%
) because it will be relative to the parent and not the element it's applied to. transform
behaves differently. Its values are relative to the element they are applied to. Thus, 50%
for transform
means half the width of the element, while 50%
for margin is half of the parent's width. This is an IE9+ solution
Using similar code to the above example, I recreated the same scenario using completely dynamic width and height:
.fixedContainer {
background-color:#ddd;
position: fixed;
padding: 2em;
left: 50%;
top: 0%;
transform: translateX(-50%);
}
If you want it to be centered, you can do that too:
.fixedContainer {
background-color:#ddd;
position: fixed;
padding: 2em;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
Demos:
jsFiddle: Centered horizontally only
jsFiddle: Centered both horizontally and vertically
Original credit goes to user aaronk6 for pointing it out to me in this answer
Related Topics
How to Detect Linked PDF on a Page and Show Message to Download Adobe Reader Using Jquery
Cannot Apply Any Bootstrap Style in Using React-Bootstrap Library
Getting Values of Global Stylesheet in Jquery
Getting the Height of an Option Element with JavaScript
Cross-Browser Way to Flip HTML/Image via JavaScript/Css
I Need List of All Class Name of Font-Awesome
Bootstrap 3 Compatible with Current Angularjs Bootstrap Directives
How to Position a Bootstrap Popover
How to Make JavaScript Scrollintoview Smooth
Fading Visibility of Element Using Jquery
Full Screen Canvas on Mobile-Devices
Toggle Sidebar Div with Another Div Using CSS/Javascript
Cannot Dynamically Set Initial Element Translation Before Transition in Same Call Stack
Losing Mouseup Event If Releasing Not Over the Same Element