div to follow scroll - javascript

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.

Related

Exchanging seamlessly between Fixed and Relative position

I'm developing a page where during the scroll, elements, at breakpoints, will stop on the screen and animate, once the final point in the scroll is reached they go back to normal scrolling page behavior.
Basically, once div X gets to the middle of the screen it position changes to fixed, and will stop at middle of the screen expanding, moving etc, as the user scrolls, and reached the final scroll point, it will stop and change from position fixed to relative staying in the same spot.
I did a prototype where once the element got to the point on the screen I wanted it to start animate, i would measure its position on the screen with the browser ruler and get the fixed position it should take from then on.
BUT this is a poor and ugly solution, with a lot of hand work.
We can get the scroll and sum up things to get the Y position, but the x position messes up for making the design responsive.
How to do with JS This change?
How to get the Fixed equivalent position of a Relative element dynamically?
🤔
I dont have much experience with JS, but I'm sure there are good solutions for this.
I think that IS the solution, to use js for changing instantaneously the position (x,y) and the position (absolute/fixed). Also I think there's a library for that but here's a sketch of a solution.
var div = document.querySelector(".dog");
var div_status = document.querySelector("#div_status");
var start = 100;
var stop = 800;
var swap = false;
window.addEventListener("scroll", function() {
var y = window.scrollY
var rect = div.getBoundingClientRect();
div_status.innerText = rect.top.toFixed() + " " + y.toFixed()
if (y >= start && y <= stop) {
div_status.style.background = "green"
if (!swap) {
div.style.position = "fixed";
div.style.top = rect.top + "px"
swap = true
}
} else {
div_status.style.background = "red"
if (swap) {
div.style.position = "absolute";
div.style.top = (y + rect.top) + "px"
swap = false;
}
}
})
body {
height: 2000px;
}
.dog {
height: 50px;
width: 200px;
border: 1px solid gray;
background: lightyellow;
line-height: 50px;
text-align: center;
position: relative;
}
#div_status {
background: red;
color: white;
position: fixed;
right: 100px;
}
<body>
<pre id="div_status">0 0</pre>
<br>
<br>
<br>
<br> keep scrolling
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<div class="dog">Dog</div>
</body>
Answering my own question... But just learned about position:sticky,
this seems to resolve the problem with just CSS, very easy and way more smooth.
#wrap{
margin:15px;
padding:10px;
}
.d1{
width:400px;
height:500px;
}
#d2{
//background-color:red;
height:900px;
}
#d3{
width:100px;
height:50px;
border: 10px solid black;
background-color:green;
position: sticky;
top: 70px;
}
<body>
<div id="wrap">
<div class="d1"><div>Scroll Down</div></div>
<div id="d2" >
<div id="d3" class="content">I'm the guy...</div>
</div>
<div class="d1"><div>
<br/><br/><br/><br/><br/><br/><br/><br/><br/>
<br/><br/><br/><br/><br/><br/><br/>
Scroll Up</div></div>
</div>
</body>

How do I make one div scroll slower or faster than other items on the page, using pure CSS or CSS/JS (without JQuery)?

All I want is to do is to make one element on the page (a div is easiest) scroll slower or faster than the other items on the page. For example, when scrolling, this particular div will move at 50% or 200% of the speed of the other items, etc.
It seems like such a simple, straightforward thing, but I can't find any examples of this. Also, I don't want to use JQuery, someone else's sketchy / overly complicated 3rd party plugin, etc. Just simple, clean, CSS and JS.
Ok, so thanks #ajaypane for the answer, but I actually figured out an even simpler way of doing this. I can't believe that nobody has done this - it's far less complicated than everything else I've seen.
JS
function parallax() {
var s = document.getElementById("floater");
var yPos = 0 - window.pageYOffset/5;
s.style.top = 50 + yPos + "%"; }
window.addEventListener("scroll", function(){
parallax();
});
CSS
.section { position: relative; width: 100vw; height: 15vw; }
.object-in-3d {
margin-left: 45vw;
width: 10vw;
height: 10vw;
background-color: #41ebf4; }
.float-center {
position: absolute;
top: 50%; }
#red { background-color: #f44141; }
#yellow { background-color: #f48342; }
#green { background-color: #f4dc41; }
#floater {}
HTML
<div class="section" id="red"> </div>
<div class="section" id="yellow">
<div class="object-in-3d float-center" id="floater"> </div>
</div>
<div class="section" id="green"> </div>
It's in codepen, here:
https://codepen.io/escapetomars/pen/EeLmpp
So I have managed to come up with this which is not too complex, however, it does scroll relative to the users scroll speed, but does work with scroll wheel, scrollbars, and keyboard.
It also scrolls up and down.
You can change the speed to suit your needs, but 10 worked for keeping it pretty much in view all the way down for my scroll speed, but left it behind when faster or using Page Down.
document.addEventListener("DOMContentLoaded", function DomContentLoaded(){
//Get the element you want to slow down;
var slowDiv = document.getElementById('slowDiv');
//Set its style.top to be the offsetTop so if style.top is not set, it will still work.
slowDiv.style.top = slowDiv.offsetTop + 'px';
//set the last scrollTop to use for direction
var lastScrollTop = 0;
//Get the element you are scrolling against
var relativeSpeedDiv = document.getElementById('main');
var moveLittle = function MoveLittle(speed, scrollY) {
//Get the current top of the slow element
var topVal = parseInt(slowDiv.style.top);
//Check scroll direction
if (isScrollingDown(scrollY)) {
topVal = topVal + speed;
} else {
topVal = topVal - speed;
}
//Set new top of slow element
slowDiv.style.top = topVal + 'px';
};
var isScrollingDown = function IsScrollingDown(scrollY) {
var retVal = false;
if (scrollY > lastScrollTop) {
retVal = true;
}
lastScrollTop = scrollY;
return retVal;
};
window.onscroll = function WindowScroll() {
//Send speed and current scroll Y
moveLittle(10, this.scrollY);
}
});
.biggestBig {
margin: auto;
align-self: center;
width: 90%;
min-height: 9999em;
}
.faded {
background: linear-gradient(gray, black);
}
.slow {
width: 2em;
height: 2em;
background-color: #ee9b0b;
position: absolute;
}
<div id="mainDiv" class="biggestBig faded">
<div id="slowDiv" class="slow"></div>
</div>

Fix an element when it reaches the top of the screen using javascript and css

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>

Switch div from fixed to absolute at bottom of browser

Im trying to add a footer at the bottom of this content that doesn't overlay the content but moves it up.
The only way I can see it working would be something like, when browser is at the bottom remove 'fixed' class on the left red '#work'.
js fiddle DEMO
Updated js fiddle DEMO
HTML
<div id="header-block">
Header-block, this sits here in the background
</div>
<div id="content">
<div id="work">
This content should be fixed when at the top
</div>
<div id="description">
This content should scroll -
</div>
</div><!-- end content -->
<div id="footer">
This should appear at the bottom
</div>
CSS
body {
margin: 0px;
padding: 0px;
}
#header-block {
background: green;
width: 100%;
position: fixed;
z-index: 1;
height: 300px;
top: 0;
}
#content {
margin-top: 300px;
width: 100%;
position: relative;
z-index: 2;
}
#work {
background: red;
width: 50%;
height: 100vh;
float: left;
position: absolute;
}
#description {
background: blue;
width: 50%;
height: 1200px;
float: right;
font-size: 30px;
}
#footer {
background: black;
width: 100%;
height: 100px;
position: absolute;
z-index: 3;
bottom: 0;
}
If I understand your question correct, this should do the trick (although it depends very much on JavaScript unfortunately).
// Fix work column on scroll
contentStart = $("#content").offset().top ;
contentSize = $("#content").height() ;
window.onscroll = function(){
if( window.XMLHttpRequest ) {
var position=window.pageYOffset;
// calculate the position of the footer and the actual seen window
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $("#footer").offset().top;
if ( position > 300 && !(docViewBottom >= elemTop)) {
$('#work').css({'position':'fixed', 'top':'0', 'height':'100vh'});
} else {
// if the footer is visible on the screen
if(docViewBottom >= elemTop) {
$('#work').css({ 'top': 0 - (docViewBottom - elemTop) }); // scroll the #main div relative to the footer
} else {
$('#work').css({'position':'relative', 'top': 'auto'}) ;
}
}
}
}
For further informations about the calculations, perhaps this question on stackoverflow is useful.
Edit: Andrew Haining posted his answer in between of my answer, perhaps give his link a try and maybe it's a better (more proper) solution. Unfortunately I haven't actualised this page when I was testing your code in JSFiddle and I didn't see his answer.
If you want to use my script, make sure you can test it with different resolutions. It works just fine for my resolution in JSFiddle, I didn't test any other.
I'm not 100% sure what you want, but if you remove the position: absolute and the bottom: 0 from the footer, and put a div with class='clearboth' above the footer, it seems to do what you need.
CSS
.clearboth {
clear: both;
}
This is a drawing of what I see on your fiddle;
Do you want the red and the blue to always be touching the black?
I don't see the red overlying the black
You should use jQuery to add a class containing the position:fixed value when the scroll position of the page is less than the inline position of the #work div. Once it scrolls past the position, remove the class and have the element fall back in line.
You can achieve this using the following jQuery methods.. .scrollTop() .offset().top() and $(window).height().
This tutorial will give you an understanding of what you need to do to achieve the necessary results, you will just have to change the calculation slightly using $(window).height(), $('#footer').height() and a few other changes to get what you desire.
Based on the question you asked i think this is what you mean. The red div should be fixed when it gets to the top but be absolute when it is below the top for scrolling and the black footer should be below the red while scrolling, check this code i have done for you. just add this jquery script and run it.
<script type="text/javascript" src="js/jquery.js"></script>
<script>
$(document).ready(function() {
$(window).scroll(function () {
console.log($(window).scrollTop());
if ($(window).scrollTop() >= 322) {
$('#footer').css("z-index","1");
$('#work').css(
{
"background": "red",
"width": '50%',
'height': '100vh',
'float': 'left',
'position': 'fixed',
'top': '0'
});
}
if ($(window).scrollTop() <= 322)
{
$('#work').css(
{
"background": "red",
"width": "50%",
"height": "100vh",
"float": "left",
"position": "absolute"
});
};
});
});
</script>
If not exactly a parallax, this is somewhat close to how parallax works, containers moving at different speeds, and some containers sitting fixed or scrolling when they attain a particular top/bottom offset in the viewport.
There's plugin that can do it. Skrollr
You can use Skrollr along with skrollrcss, and it'll make sure how the containers take position on screen based on scrolltop of the window and the container specifically.

Jumping div in Safari and Chrome. jQuery/Javascript

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>

Categories

Resources