Sticky element that stops when reaches a element - javascript

I want to make a fixed element (like sticky) when I scroll and reach the top of another element. The fixed element will increase the bottom property of css to don't pass the top of the element I set as bound (the element you can't pass the point, like a ground). I did a pen that shows what I want, hope that helps: https://codepen.io/vendramini/pen/xNWpPK. I really don't know which calculation I need to do to achieve this. Please, help me.
https://codepen.io/vendramini/pen/xNWpPK
The best I could do to exemplify this.
*{
margin: 0;
padding: 0;
}
section{
height: 100vh;
width: 100vw;
background: #eee;
position: relative;
max-width: 100%;
}
.a{
background: #faa;
}
.b{
background: #ffa;
}
.c{
background: #afa;
}
.d{
background: #aaf;
}
.sticky{
width: 100%;
position: fixed;
height: 100px;
background: blue;
opacity: 0.5;
bottom: 0;
z-index: 1;
}
.ground{
height: 2000px;
background: black;
}
//jQuery required
(function($){
$('[data-bound]').each(function(){
const $elem = $(this);
const $bound = $( $elem.data('bound') );
$(window).scroll(function(){
const scrollTop = $(window).scrollTop();
const boundTop = $bound.offset().top;
const boundHeight = $bound.height();
const delta = (scrollTop - boundTop); //+ boundHeight;
console.log({
scrollTop,
boundTop,
delta,
});
if( delta > 0 ){
$elem.css('bottom', delta);
}
else{
$elem.removeAttr('style');
}
});
});
})(jQuery);
<div class="sticky" data-bound="#ground"></div>
<section class="a"></section>
<section class="b"></section>
<section class="c"></section>
<section class="d"></section>
<footer class="ground" id="ground"></footer>
<section class="a"></section>
<section class="b"></section>
<section class="c"></section>
<section class="d"></section>
I expect to have a fixed element that doesn't pass the ground element. That's it.

I'm not sure I understand exactly what you want, but I think you can achieve this with only CSS using position: sticky on the footer.
https://codepen.io/anon/pen/jozzPq
the relevante changes:
add a wrapper to the elements with the sticky footer:
<div>
<section class="a"></section>
<section class="b"></section>
<section class="c"></section>
<section class="d"></section>
<footer class="ground" id="ground"> </footer>
</div>
position the footer at the bottom and set it to sticky
.ground{
height: 100px;
background: black;
position: sticky;
bottom: 0;
}
Check the codepen cause a lot of CSS and (all) JS can be removed.

I finally found the answer:
https://codepen.io/vendramini/pen/xNWpPK
The solution is add the window's height in to the delta calculation:
const windowHeight = $(window).height();
const delta = (scrollTop - boundTop) + windowHeight;
Thanks everyone that contributed to this thread!

Replace
if( delta > 0 ){
$elem.css('bottom', delta);
}
else{
$elem.removeAttr('style');
}
with
$elem.css('bottom', 0);
to stick the element always to the bottom.

The thing that I want is next to what UIKit does:
https://getuikit.com/docs/sticky
But the problem is that UIKit uses top instead of bottom.

Related

Opacity reduction script does not working

I have a problem with a script that until recently worked, but now seems not to want to work.
I want to reduce the opacity of the green spheres when scrolling down, it seems to be working until recently, but now I can't figure out what the problem is.
The website is this: https://attiliosantomo.com/PROVA/
The script is this:
$(document).ready(function() {
$(window).scroll(function(event) {
let scroll = $(this).scrollTop();
let opacity = 1 - (scroll / 1300);
if (opacity > 0.2) {
$('.bg-bubble').css('opacity', opacity);
}
});
});
</script>
Thank you so much for you help
The issue is that it's not the window that is scrolling. It's the .main-desktop element that is being scrolled. Targeting the scroll event of the .main-desktop as per below should solve the issue.
$(document).ready(function() {
// \/ Changed \/ selector from window to '.main-desktop'
$('.main-desktop').scroll(function(event) {
let scroll = $(this).scrollTop();
let opacity = 1 - (scroll / 1300);
if (opacity > 0.2) {
$('.bg-bubble').css('opacity', opacity);
}
});
});
html,
body {
height: 100%;
margin: 0;
}
.main-desktop {
overflow: scroll;
height: 100%;
}
.inner {
height: 3000px;
}
.bg-bubble {
height: 100px;
width: 100px;
background-color: blue;
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="bg-bubble"></div>
<div class="main-desktop">
<div class="inner"></div>
</div>

How do I prevent scroll back up with JavaScript or jQuery?

I have a webpage where there is a full height intro image. Underneath this image is the main body of the site with a regular site header at the top, I'm trying to create an effect where once the user scrolls down to the site header, they cannot scroll back up to view the intro image.
CSS Classes:
Main Intro Image: .cq-fullscreen-intro
Site Header: .nav-down
I had a poke around on StackOverflow but I can't find anything that addresses this circumstance, can anyone point me in the right direction to achieve this using jQuery?
you can use JQuery scrollTop function like this
$(function() {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
// set the height in pixels
if (scroll >= 200) {
// after the scroll is greater than height then you can remove it or hide it
$(".intro-image").hide();
}
});
});
So instead of scrolling, I personally think it would be better to have it be actionable. Forcing the user to manually do the transition (and all in between states) is a bad idea. If the user scrolls half way, and see's something actionable (menu, button, input field) is it usable? If it is, what happens if they submit... very awkward. If it isn't usable, how do they know when it is? How do they know it's because they haven't scrolled all the way. It's very poor user experience.
In the following example, I've created a pseudo-screenport for you to see what's actually going on. The .body container in your real site would be the body element.
Code Pen Example
$(document).ready(function(){
$('.splash-screen').on('click', function(){
$('.splash-screen').addClass("is-hidden");
});
})
html, body{
background: #eee;
margin: 0;
padding: 0;
}
.flex-root {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
}
.web-container {
width: 640px;
height: 480px;
background: #fff;
}
.body {
font-size: 0; // this is only to prevent spacing between img placholders
position: relative;
}
.splash-screen{
position: absolute;
transition: transform 1s ease-in-out;
}
.splash-screen .fa {
position: absolute;
z-index: 1;
font-size: 24px;
color: #fff;
left: 50%;
bottom: 15px;
}
.splash-screen.is-hidden {
transform: translateY(-110%);
transition: transform 1s ease-in-out;
}
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="flex-root">
<div class="web-container">
<div class="body">
<div class="splash-screen">
<img src="https://via.placeholder.com/640x480?text=Splash+Screen"/>
<i class="fa fa-chevron-circle-up"></i>
</div>
<img src="https://via.placeholder.com/640x60/cbcbcb?text=Menu"/>
<img src="https://via.placeholder.com/640x420/dddddd?text=Site Body"/>
<div>
</div>
</div>
While its not direclty preventing you from scrolling up and its not jQuery, I would suggest to remove/hide the element once its out of view.
You could get the current scroll position, relative to the top of the page, and check if its greater than the elements height:
const target = document.getElementById('my-target')
const targetHeight = target.getBoundingClientRect().height
const scrollEventListener = () => {
if (
document.body.scrollTop > targetHeight ||
document.documentElement.scrollTop > targetHeight
) {
target.remove()
window.removeEventListener('scroll', scrollEventListener)
document.documentElement.scrollTop = 0
}
}
window.addEventListener('scroll', scrollEventListener)
Here is a codepen https://codepen.io/bluebrown/full/aboagov

keep the background image fixed position and centered

In my project, I need to show a small image in center of the visible part of the container, with respect to the window i.e .loader. Even when the user scrolls the page, the image should be visible in center of .loader.
I successfully implemented this but now I am facing a edgecase which is when user scrolls the page "up to the header" or "down to the footer", the small image is hiding. demo.
This is actually normal behaviour but in these edgecases, I want the image to stick to top/bottom end of the .loader container.
What I want:
Keep the small image always at center of .loader container. (I already implemented this)
when scrolled to any end of .loader container, the image should stick to that end instead of hiding behind the container.
Fiddle
A solution using just css is preferred. I am looking for browser support in IE9+, chrome and firefox.
.header {
height: 600px;
width: 650px;
background-color: grey;
}
.left-side {
height: 300px;
width: 150px;
float: left;
background-color: red;
}
.loader {
background-image: url('http://i.imgur.com/U2njI.jpg');
margin-left: 150px;
height: 1500px;
width: 500px;
background-position: 345px center;
background-repeat: no-repeat;
background-attachment: fixed;
background-color: cornflowerblue;
}
.footer {
height: 600px;
width: 650px;
background-color: silver;
}
<div class="header"></div>
<div class="left-side"></div>
<div class="loader"></div>
<div class="footer"></div>
Here is a working solution with javascript, I hope its behaviour is how you expect it to be. I'm unfortunately not able to test it on IE9 right now but it should work (DEMO):
document.addEventListener('DOMContentLoaded',function() {
var loader = document.querySelector('.loader'),
loaderRect = loader.getBoundingClientRect(),
loaderTop = loaderRect.top + document.body.scrollTop,
loaderBottom = loaderTop + loader.offsetHeight,
initialBgPos = loader.style.backgroundPosition,
imageHeight = 141;
function onScroll() {
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
if(loaderTop >= (scrollTop + (window.innerHeight - imageHeight)/2)) {
loader.style.backgroundPosition='345px ' + (loaderTop - scrollTop) + 'px';
} else if(loaderBottom <= (scrollTop + (window.innerHeight + imageHeight)/2)) {
loader.style.backgroundPosition='345px ' + (loaderBottom - scrollTop - imageHeight) + 'px';
} else {
loader.style.backgroundPosition = initialBgPos;
}
}
window.addEventListener('scroll', onScroll);
onScroll();
});
To achieve what I think you want. We have to set the position of the .loader div to fixed, then it'll always stay where it's placed, regardless of whether the user scrolls the page, the div will scroll too. In here's how to set the position of loader to fixed in CSS (you may also have to get the position of your fixed div):
.loader{
position: fixed;
left: 100px;
top: 300px;
}
Here's your upadted JSFiddle: http://jsfiddle.net/Ezhb4/4/

How to trigger the layout to change?

I've a sticked element which gets the top-alignment from current scroll-offset. Problem is, that the layout is not "retriggerd" if the space from it is free. So there stays a ghost-gap where the sticked element was...
http://fiddle.jshell.net/pPc4V/
The markup is pretty simple:
...
as well as the js:
var $win = $(this);
var sticked = document.querySelector('a.sticked');
$win.on('scroll', function () {
var scrollTop = $win.scrollTop();
sticked.style.top = scrollTop + 'px';
// $win.resize();
});
...and the css looks good so far:
a {
display: inline-block;
width: 90px;
height: 90px;
background: deepskyblue;
}
.sticked {
position: relative;
top: 0;
left: 0;
background: tomato;
}
I tried to trigger the resize-event on scroll (as you see above uncommented), but no success! Any ideas, how to retrigger the layout so that the free-gap is filled with the next floated element?
Update
To clarify what I mean I made a simple image-timelime:
Step 1
Step 2
Step 3
The issue is that you are setting position fixed on an element which is displayed inline. That will cause that space to occur. I have redid your jsFiddle with proper alignment.
To fix it, I added the class "stuck" only when the document's scrollTop position is greater than the scrollTop position of your target element.
jsFiddle: http://fiddle.jshell.net/pPc4V/44/
HMTL:
<div id="grid">
etc...
</div>
CSS:
#grid {
height:1000px;
overflow:hidden;
float:left
}
#grid > a {
display: inline-block;
width: 90px;
height: 90px;
background: deepskyblue;
}
.stuck {
position: fixed;
background: navy !important;
}
JS:
$(window).on('scroll', function () {
var $doc = $(document),
parentElement = $('#grid'),
childToGetStuck = parentElement.find('a:nth-child(5)');
if ($doc.scrollTop() > childToGetStuck.scrollTop()) {
childToGetStuck.addClass('stuck');
//console.log($('.stuck').scrollTop())
} else {
childToGetStuck.removeClass('stuck');
}
});

Sticky Header - buggy jumping on scroll

I have a specific problem on making a sticky header with jQuery. I tried the commonly used snippets around the web, but I perceived the same buggy thing everywhere.
At a specific document height (scrollable until a little more than calling of sticky-effect) the sticky header jumps between position: fixed and position: static.
HTML:
<header>
<div id="not-sticky"></div>
<div id="sticky"></div>
</header>
<div id="content"> ...
jQuery:
var $sticky = $("#sticky");
var offset = $sticky.offset();
var stickyTop = offset.top;
var windowTop = $(window).scrollTop();
$(window).scroll(function() {
windowTop = $(window).scrollTop();
if (windowTop > stickyTop) {
$sticky.css({
position: 'fixed',
top: 0
});
}
else {
$sticky.css({
position: '',
top: ''
});
}
});
CSS:
header {
width: 100%;
}
#not-sticky {
padding: 50px 0;
width: 100%;
}
#sticky {
padding: 24px 0;
position: relative;
width: 100%;
z-index: 25;
}
I also tried a margin-bottom on #not-sticky with the same height as the #sticky to keep a constant document-height, but the same jumpy-sticky-effect occurred.
Any idea to fix that thing?
Scroll fires too many times and trying to set an element style will always & inevitably create jumps (even barely noticeable but still jaggy).
The best way I've found is to
clone our element,
make that clone fixed
play with clone's visibility style.
Pure JS:
;(function(){ /* STICKY */
var sticky = document.getElementById("sticky"),
sticky2 = sticky.cloneNode(true);
sticky2.style.position = "fixed";
document.body.appendChild(sticky2);
function stickIt(){
sticky2.style.visibility = sticky.getBoundingClientRect().top<0 ? "visible" : "hidden";
}
stickIt();
window.addEventListener("scroll", stickIt, false );
}());
#sticky{
height:100px;
background:#ada;
height:50px;
position:relative;
/* needed for clone: */
top:0;
width:100%;
}
/* Just for this demo: */
*{margin:0;padding:0;}
#content{height:2000px; border:3px dashed #444;}
h1{padding:40px; background:#888;}
<h1>Logo</h1>
<div id="sticky">Sticky header</div>
<div id="content">Lorem ipsum...<br>bla bla</div>
So when you see the "header" fix, that's actually our fixed clone getting visible on-top.

Categories