I have a div #HangerLeft that the css.right is automatically generated via jQuery to sit on the left side of the page based on the body width. It is absolute positioned.
function hangerLeft() {
var hangerPosition = (jQuery("body").innerWidth() / 2) + (990 / 2);
jQuery("#HangerLeft").css("position","absolute").css("right", hangerPosition +"px").css("top","20px");
}
Inside the #HangerLeft div I have a #scrollWrapper div with no positioning and inside the #scrollWrapper i have a #scrollBox. The #scrollBox is absolute positioned.
#scrollWrapper { width:130px; height:400px; border:1px solid #fff;}
#scrollBox { position: absolute; top: 100; margin-top: 25px; padding-top: 0px;}
#scrollBox.fixed { position: fixed; top: 0;}
The #scrollBox sits until you scroll. Once you scroll past the top of the #scrollBox div javascript adds a class to make the #scrollBox position:fixed instead of absolute.
<script>
$(function () {
var msie6 = $.browser == 'msie' && $.browser.version < 7;
if (!msie6) {
var top = $('#scrollBox').offset().top - parseFloat($('#scrollBox').css('margin-top').replace(/auto/, 0));
$(window).scroll(function (event) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y >= top) {
// if so, ad the fixed class
$('#scrollBox').addClass('fixed');
} else {
// otherwise remove it
$('#scrollBox').removeClass('fixed');
}
});
}
});
</script>
In Firefox and IE this works fine.
In Safari and Chrome once the #scrollBox javascript hits, the #scrollBox div jumps out of the #HangerLeft div into the middle of the page and ignores the positioning of the #HangerLeft div.
I have been battling this for 2 weeks and am at a loss.
Any help would be appreciated.
Ok, so I reworked your code. I kept it to your liking.. I would set this up in a different way but this works for your approach. You can see a live version here
JavaScript:
<script type="text/javascript">
function setupScrollBox(){
// cache box element and use wrapper as your position element
var hanger = $("#HangerLeft"),
position = $("#wrap").offset();
hanger.css({
position: 'absolute',
left: position.left - $("#scrollWrapper").outerWidth(),
marginTop: '25px'
});
}
$(document).ready(function(){
// check if IE6
var msie6 = $.browser.msie && $.browser.version < 7;
setupScrollBox();
// attach resize event to window
$(window).resize(function(){
setupScrollBox();
});
// check browser
if(!msie6){
// attach scroll event
$(window).scroll(function (event) {
// get scroll position and cache element so we only access it once
var y = $(this).scrollTop(),
wrap = $('#HangerLeft');
// if scroll position is greater than 100 adjust height else do nothing
if(y > 100)
// you can animate the position or not, your call
wrap.stop().animate({top: y}, 250);
//wrap.css('top', y+'px');
});
}
});
</script>
CSS:
#HangerLeft {
top: 100px;
}
#scrollWrapper {
width: 130px;
}
#scrollBox {
position: relative;
margin-top: 25px;
padding-top: 0px;
z-index: 10;
}
HTML:
<div id="HangerLeft">
<div id="scrollWrapper">
<div id="scrollBox">
<div id="mainContainer">
<div id="shareContainer">
<div class="moduleShareHeader">SCROLL BOX</div>
</div>
</div>
</div>
</div>
</div>
Related
I have an element, that I wish to stick on top after it reaches the top of the screen.
<div id="HeaderWrapper">
...
<div id="Navigation">
Navigation
</div>
...
</div>
I am adding an event listener on scroll, which would call a function to check the posting of the element by using getBoundingClientRect() method. If the top or the y of the element is less then 0 relative to the viewport, then I would like to fix/stick the header. Again if its more than 0 then I would like to remove the fix position. In both the cases, I am adding and removing a class name of fixed_navbar which has the property of fix position.
document.addEventListener("scroll", function() {
const el = document.getElementById("Navigation");
let rect = el.getBoundingClientRect();
if (rect.top <= 0) {
el.classList.add("fixed_navbar");
} else {
el.classList.remove("fixed_navbar");
}
});
You can also the check the codepen demo.
When the position top of the element is more than zero it works fine. Also when scrolling down to the position where the element's top position is less than 0 it sticks to the page and has the fixed propery. But again when scrolling back to the position when the element's top is more than 0, the element still has the fixed propery and stick's to the top of the screen. How can I make the element stick to the top when it reaches the top of the screen and again when the element is below the top of the screen remove the fixed postion?
You can achieve this with CSS alone, by using:
position: sticky
When declaring position: sticky; you will also need to declare a top style (eg. top: 0;) to indicate at which point you want the element to become "stuck".
Working Example:
header {
height: 600px;
}
.navigation {
position: sticky;
top: 0;
margin-top: 150px;
}
<header>
<div class="navigation">Navigation</div>
</header>
Further Information:
position: sticky works in the following browsers:
https://caniuse.com/#feat=css-sticky
Try This
if (rect.top <= 0) {
In if condition you write rect.top < 0 that is wrong for your requirement
#Rounin provide an awesome solution. Although I fix your issue in JavaScript. you can check this
document.addEventListener("scroll", function() {
const el = document.getElementById("Navigation");
let rect = el.getBoundingClientRect();
if (rect.top <= 0) {
el.classList.add("fixed_navbar");
} else {
window.onscroll = function() {myFunction()};
function myFunction() {
if ( document.body.scrollTop < 100 ) {
el.classList.remove("fixed_navbar");
}
}
}
});
* {
margin: 0;
padding: 0;
}
#HeaderWrapper {
background: lightgrey;
height: 1500px;
}
.box {
background: skyblue;
width: 100%;
height: 100px;
}
#Navigation {
background: green;
}
.fixed_navbar {
position: fixed;
z-index: 1000;
width: 100%;
left: 0;
top: 0;
}
<div id="HeaderWrapper">
<div class="box"></div>
<div id="Navigation">
Navigation
</div>
</div>
<div id="wrapper">
<div id="left-panel"></div>
<div id="long-right-panel></div>
</div>
<footer></footer>
Upon scrolling, I am dealing with a problem when the #wrapper top position is <= 0 and when the footer top position subtracted from the #left-panel bottom position is >=0, I'd like the #left-panel to have the style position of fixed. Else it should have position of relative.
I'm running into a problem where once the above conditions are met, the #left-panel flips between a position of relative and fixed.
Here's some code for clarification:
// creates event listener
window.addEventListener('scroll', handleScroll);
// get DOM elements outside of scroll event
const wrapperRect = document.getElementById('wrapper').getBoundingClientRect();
const leftPanel = document.getElementById('left-panel');
const leftPanelRect = leftPanel.getBoundingClientRect();
const rightPanel = document.getElementById('long-right-panel');
const rightPanelRect = rightPanel.getBoundingClientRect();
const footerRect = document.querySelector('footer').getBoundingClientRect();
function handleScroll () {
/* if the #wrapper has scrolled past the top of the viewport and the space between the top of the footer and the bottom of the #left-panel is greater than 0, set #left-panel to position fixed */
if (wrapperRect.top <= 0 && (footerRect.top - leftPanelRect.bottom) > 0) {
leftPanel.setAttribute("style", "position: fixed; top: 3rem;");
rightPanel.setAttribute("style", "margin-left: 45%;");
}
/* else set the #left-panel position to relative */
else {
leftPanel.setAttribute("style", "position: relative;");
rightPanel.setAttribute("style", "");
}
}
The code works except, I need some sort of flag or means of breaking out of it because as it stands, when the conditions are true, its fixed, but when they're false, the #left-panel jumps back to its original position and the #wrapper top is < 0, and the space between the footerRect.top and leftPanelRect.bottom is > 0 and changes it to fixed ... then scrolling changes back to relative ... this causes jumps and flickering.
Any advice on how to fix?
Your code actually works fine, I tested it with latest Chrome on Windows 8.1. But if you mean that page jumps when you scroll 1st time, try to add
window.addEventListener('load', handleScroll);
on top of the script - to check conditions and set styles on page load:
<style>
#wrapper {
height: 200vh;
width: 100%;
}
#left-panel {
background-color: #f90;
height: 200px;
width: 45%;
}
#long-right-panel {
background-color: #f09;
height: 500px;
margin-top: 3rem;
width: 55%;
}
#footer {
background-color: #9f9;
height: 100px;
width: 100%;
}
</style>
<div id="wrapper">
<div id="left-panel"></div>
<div id="long-right-panel"></div>
</div>
<footer id="footer"></footer>
<script>
// creates event listener
window.addEventListener('load', handleScroll);
window.addEventListener('scroll', handleScroll);
// get DOM elements outside of scroll event
const wrapperRect = document.getElementById('wrapper').getBoundingClientRect();
const leftPanel = document.getElementById('left-panel');
const leftPanelRect = leftPanel.getBoundingClientRect();
const rightPanel = document.getElementById('long-right-panel');
const rightPanelRect = rightPanel.getBoundingClientRect();
const footerRect = document.querySelector('footer').getBoundingClientRect();
function handleScroll () {
/* if the #wrapper has scrolled past the top of the viewport
and the space between the top of the footer and the bottom of the #left-panel
is greater than 0, set #left-panel to position fixed */
if (wrapperRect.top <= 0 && (footerRect.top - leftPanelRect.bottom) > 0) {
leftPanel.setAttribute("style", "position: fixed; top: 3rem;");
rightPanel.setAttribute("style", "margin-left: 45%;");
}
/* else set the #left-panel position to relative */
else {
leftPanel.setAttribute("style", "position: relative;");
rightPanel.setAttribute("style", "");
}
}
</script>
https://codepen.io/svitch/pen/yzEzmz
Usually sticky panel scripts have three conditions:
panel.top < wrapper.top
panel.top > wrapper.top && panel.bottom < wrapper.bottom
panel.bottom > wrapper.bottom
In that case, your panel will stick when wrapper is going beyond the screen and unstick when panel is no longer needed.
On a webpage I have multiple sections. In one of this sections I show lots of content blocks. These blocks can be filtered via a panel that floats on the right side.
Currently this floating panel is visible on all the sections of the webpage but I want it to only be visible within the section that I assign it to.
Ideally I would want it to have it stuck in the top right corner of the section on page load. Then when the user gets to the section it needs to keep scrolling with the user until it reaches the end then it needs to stay there.
When the user is finished on the page and scrolls back upwards it needs to do the same as above only in reverse order.
What needs to be done
Make it only visible within the section (assigning a specific section)
Make it stuck in the top right corner on page load
Disallow continuing to the next section after reaching the end of the assigned section.
jsFiddle
https://jsfiddle.net/nfuL86hg/
HTML:
<div id="section-aaa"></div>
<div id="section-bbb">
<div id="content"></div>
<div id="scroller">
Hello<br>
World<br>
</div>
</div>
<div id="section-aaa"></div>
JS:
(function ($) {
$(document).ready(function() {
$(window).scroll(function(){
$("#scroller").stop().animate({"marginTop": ($(window).scrollTop()) + "px", "marginLeft":($(window).scrollLeft()) + "px"}, "slow" );
});
});
})(jQuery);
CSS:
#section-aaa{
position:relative;
height:500px;
background:red;
}
#section-bbb {
position:relative;
height:1000px;
background:grey;
}
#content {
height:100%;
}
#scroller {
background-color: #fca9a9;
width: 250px;
position: absolute;
top: 50px;
right: 0;
z-index: 1;
}
Thanks everyone for helping.
PS: If you know a better title please post it in the comment area. At the moment I could not think of a better one.
here is one demo
https://jsfiddle.net/nfuL86hg/2/
(function ($) {
$(document).ready(function() {
$(window).scroll(function(e){
if(getIsInArea()){
console.log('animate');
$("#scroller").stop().animate({
"marginTop": ($(window).scrollTop()) + "px",
"marginLeft":($(window).scrollLeft()) + "px"
}, 100 );
}
});
function getIsInArea(){
var w = $(window).scrollTop();
var p = $('#section-bbb').position();
var top = p.top;
var down = top+$('#section-bbb').innerHeight();
if(w>=top && w<=down) {
return true
}
return false;
}
});
})(jQuery);
Expect goes near you need it
Another solution wihtout the animation, in case you want it simpler.
Check it on this JSFiddle.
HTML
<div id="section-aaa"></div>
<div id="section-bbb">
<div id="content"></div>
<div id="scroller">
Hello<br>
World<br>
</div>
</div>
<div id="section-aaa"></div>
CSS
body {
padding: 0;
margin: 0;
}
#section-aaa{
position:relative;
height:500px;
background:red;
}
#section-bbb {
position:relative;
height:1000px;
background:grey;
}
#content {
height:100%;
}
#scroller {
background-color: #fca9a9;
width: 250px;
position: absolute;
top: 50px;
right: 0;
z-index: 1;
}
JavaScript
(function ($) {
$(document).ready(function() {
$(window).scroll(function(){
if ($(window).scrollTop() > $('#section-bbb').offset().top) {
if ($(window).scrollTop() < $('#section-bbb').offset().top + $('#section-bbb').height() - 100 - $('#scroller').height() ){
$('#scroller').css({"position":"fixed", "top":"50px", "bottom":"auto"});
} else {
$('#scroller').css({"position":"absolute", "top":"auto", "bottom":"50px"});
}
} else {
$('#scroller').css({"position":"absolute", "top":"50px", "bottom":""});
}
});
});
})(jQuery);
In Javascript it checks if the scroll top of the window is in the section-bbb div and if it is, it changes the css of the scroller div to have position: fixed. If the scroll top of the window is below the section-bbb div, it changes back the css of the scroller div to have position: absolute and be on the bottom of the section-bbb div (top:auto, bottom:50px). If the scroll top of the window is above the section-bbb div, it changes the css of the scroller div to have position: absolute and be on the top of the section-bbb div (top:50px, bottom:auto).
I'm trying to build a right box who follows the user scrolling:
CSS:
.clearfix:after {
content: " ";
display: block;
font-size: 0;
height: 0;
clear: both;
visibility: hidden;
}
.wrapper {
border: 1px solid black;
}
.column {
float: left;
border: 1px solid red;
}
.relative {
position: relative;
margin-top: 0px;
}
HTML:
<div class="wrapper clearfix">
<div class="column">
small or big text
</div>
<div class="column">
<div class="dmap relative">a</div>
<span>some other crazy stuff</span>
</div>
</div>
Javascript:
referencey = $(".dmap").offset().top;
$(window).scroll(function (event) {
var y = $(this).scrollTop();
if (y >= referencey) {
$(".dmap").css("margin-top", y - referencey)
} else {
$(".dmap").css("margin-top", 0);
}
});
The code works just fine. The columns sizes are irrelevant, because all I do is change the margin-top, it means the columns and wrapper always gets a new size. The downside of the code is little smalls jumps while the user is scrolling.
An alternative to avoid the small jumps while scrolling is not to change the margin-top, but change the position of the box to fixed after y >= referencey. The downside of the solution is a very buggy behavior relative to the columns sizes, because when I change the class to fixed, it's does not occupy space inside the right column anymore, if the left column is smaller, a whole set of new bugs appear.
I came up with a solution that don't fix the problem, but work around it. What I have done is to scroll the box after the user stop scrolling. A different effect but no little jumps (and it looks cool too).
var scrolly = $(".dmap").offset().top;
var scroll = false;
$(window).scroll(function (event) {
var y = $(this).scrollTop();
if (scroll) {
clearTimeout(scroll);
}
scroll = setTimeout(function () {
$(".dmap").animate(
{ marginTop: (y >= scrolly ? y - scrolly : 0) },
{ queue: false, duration: 200 }
);
}, 100);
});
It one simple line; position: fixed;
This means that the object is fixed to the page so it follows when you scroll.
I've got a div with position: fixed that moves with the scroll properly, but I'd like to have it stop when it reaches certain (y-axis) boundaries. What's the method to go about doing this?
Ideally the solution doesn't flicker and is performant. Twitter's right panel is close to what I'd like.
This is a more functional vetrsion of http://jsbin.com/ijexe
(updated the code to reenable the origional position... essentially once it hits its origional top position it will start scrolling again)
You can update the http://jsbin.com/ijexe code to test simply by swapping out the jquery function with the one below...
In the
<script type="text/javascript" src="Sandbox_files/jquery.min.js"></script>
in the example:
.fixedElement {
Z-INDEX: 100; POSITION: absolute; BACKGROUND-COLOR: #c0c0c0; WIDTH: 100%; HEIGHT: 30px; COLOR: #800000; FONT-SIZE: large; TOP: 200px
}
(just make sure you have your position:absolute & top: value set)
Updated function (place before the closing body tag)
<script type="text/javascript">
$(window).scroll(function(e){
var scrollTo = 200;
var scrollClass = '.fixedElement';
$el = $(scrollClass);
position = $el.position();
if ($(this).scrollTop() > scrollTo && $el.css('position') != 'fixed'){
$(scrollClass).css({'position': 'fixed', 'top': '0px'});
} else if ((position.top < scrollTo) && ($el.css('position') != 'relative')){
$(scrollClass).css({'position': 'relative', 'top': '200px'});
}
});
</SCRIPT>
You can update:
scrollTo - The offset from the top of the screen to start/stop the element scrolling
* Just make sure scroll to is set to the same value as your stylesheet decliration...
scrollClass - The class name for the element(s) to apply the function to