How to bind css animation duration to scroll - javascript

I want to make something like those website where you scroll down and some animation follows by your scrolling and if you scroll up it goes reverse.
I saw some libraries like this but I want to see can it be done some more simple way?
Thanks
$(document).ready(function(){
var lastScrollTop = 0;
$(document).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
$('div').removeClass('scrollUp').addClass('scrollDown');
} else {
$('div').removeClass('scrollDown').addClass('scrollUp');
}
lastScrollTop = st;
});
});
body{
height: 150vh;
overflow-y: auto;
}
div {
width: 100px;
height: 100px;
position: fixed;
}
#keyframes myfirst {
0% {background: rgba(0,0,0,0); top: 0px;}
100% {background: rgba(0,0,0,1); top: 400px;}
}
.scrollDown{
animation-name: myfirst;
animation-duration: 5s;
animation-direction: alternate;
}
.scrollUp{
animation-name: myfirst;
animation-duration: 5s;
animation-direction: alternate-reverse;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
Besides this I just tried changing keyframes on scroll so 100% or the end of animations changes by scrolling down and 0% by scrolling up but it doesnt work:
$(document).ready(function(){
var lastScrollTop = 0;
$(document).scroll(function(event){
var st = $(this).scrollTop();
$('head>style').last().remove();
if (st > lastScrollTop){
$('head').append('<style>#keyframes myfirst{0%{background: rgba(0,0,0,0); top: 0px;}100%{background: rgba(0,0,0,1); top: '+st+'px;}}</style>');
$('div').removeClass('scrollUp').addClass('scrollDown');
} else {
$('head').append('<style>#keyframes myfirst{0%{background: rgba(0,0,0,0); top: '+st+'px;}100%{background: rgba(0,0,0,1); top: '+lastScrollTop+'px;}}</style>');
$('div').removeClass('scrollDown').addClass('scrollUp');
}
lastScrollTop = st;
});
});
body{
height: 150vh;
overflow-y: auto;
}
div {
width: 100px;
height: 100px;
position: fixed;
border: 1px solid black;
}
.scrollDown{
animation-name: myfirst;
animation-duration: 0s;
animation-direction: alternate;
}
.scrollUp{
animation-name: myfirst;
animation-duration: 0s;
animation-direction: alternate-reverse;
}
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</head>
<div></div>
SOLUTION WITH TRANSITION (WITHOUT KEYFRAMES)
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div></div>
<style>
body{
height: 150vh;
overflow-y: auto;
}
div {
width: 100px;
height: 100px;
position: fixed;
border: 1px solid black;
opacity: 0;
transition: opacity 0s ease;
background: rgb(0,0,0);
}
</style>
</head>
<body>
<div></div>
<script>
$(document).ready(function(){
var lastScrollTop = 0;
$(document).scroll(function(event){
var st = $(this).scrollTop();
$('head>style').last().remove();
if (st > lastScrollTop){
$('div').css({
opacity: function() {
var opacity = ((1 - (400 - st) / 400) * 0.8);
return opacity;
}, left: st
});
} else {
$('div').css({
opacity: function() {
var opacity = ((1 - (400 - st) / 400) * 0.8);
return opacity;
}, left: st
});
}
lastScrollTop = st;
});
});
</script>
</body>
</html>

It can be done more simply and without jQuery. This is a rough take, but I made it a bit more generic by adding a container and passing ratios around to get mostly full, bounded left-to-right position and zero-to-one opacity transitions:
var locked = false;
var container = document.getElementById('container');
var animated = document.getElementById('animated');
window.addEventListener('scroll', function() {
if (!locked) {
window.requestAnimationFrame(function() {
animated.style.opacity = Math.min(window.scrollY / window.innerHeight, 1);
animated.style.left = Math.min(animated.style.opacity * container.clientWidth, container.clientWidth - animated.clientWidth).toString() + 'px';
locked = false;
});
}
locked = true;
});
#container {
border: 1px solid red;
height: 200vh;
width: 80%;
}
#animated {
width: 100px;
height: 100px;
position: fixed;
opacity: 0;
background: rgb(0, 0, 0);
}
<div id="container">
<div id="animated"></div>
</div>

Related

Trying to apply a script that should enable a floating button to appear after scrolling a certain amount of px, but it is not working

<script>
document.addEventListener
('DOMContentLoaded',
function() {
jQuery(function($){
$(document).scroll(function()
{
var y = $(this).scrollTop();
if (y > 1810 && $(window
).scrollTop() + $(window
).height() < $(document
).height() - 100) {
$('#addcartsection').addClass
('viewaddcart')
} else {
$('#addcartsection'
).removeClass
('viewaddcart')
}
});
$('#addcartbutton').click
(function(){
$('.single_add_to_cart_button'
).click();
$('html, body').animate({
scrollTop: $('.product_title'
).offset().top
}, 'slow');
});
});
});
</script>
<style>
#addcartsection{
position: fixed;
bottom: 0;
width: 100vw;
z-index: 98;
-webkit-transition: transform
0.34s ease;
transition : transform 0.34s
ease;
transform: translateY(0px); /*adjust this value to the height of your addcartsection*/
}
.viewaddcart{
transform: translateY(0px
)!important;
}
</style>
applied this in a page builder html element but the button is appearing always instead of after scrolling a certain amount of px down the page. are there any errors in the script? sorry i am not an expert at coding.
Seems to be working, make sure you are hiding it by default and display only when viewaddcart class exists on the same button:
#addcartsection {
...
display: none;
}
#addcartsection.viewaddcart {
display: block;
}
document.addEventListener('DOMContentLoaded',
function() {
jQuery(function($) {
$(document).scroll(function() {
var y = $(this).scrollTop();
if (y > 1810 && $(window).scrollTop() + $(window).height() < $(document).height() - 100) {
$('#addcartsection').addClass('viewaddcart')
} else {
$('#addcartsection').removeClass('viewaddcart')
}
});
$('#addcartbutton').click(function() {
$('.single_add_to_cart_button').click();
$('html, body').animate({
scrollTop: $('.product_title').offset().top
}, 'slow');
});
});
});
#addcartsection {
position: fixed;
bottom: 0;
width: 100vw;
z-index: 98;
-webkit-transition: transform 0.34s ease;
transition: transform 0.34s ease;
transform: translateY(0px);
/*adjust this value to the height of your addcartsection*/
}
.viewaddcart {
transform: translateY(0px)!important;
}
.veryHugeDocument {
background: grey;
height: 5000px;
}
#addcartsection {
width: 100px;
color: white;
background: blue;
right: 0;
display: none;
}
#addcartsection.viewaddcart {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="veryHugeDocument">
<h1>My document!</h1>
</div>
<button id="addcartsection">Add to cart!</button>

Uniform page load

I have two problems:
Animation issue(moving while scrolling):
My HTML:
<body>
<header class="stable">
<div id="object">
<img src="img/object.png">
</div>
</header>
</body>
My CSS:
#object{
position: absolute;
left: 0;
right: 0;
margin:auto;
bottom: 0%;
width: 45.9%;
height: auto;
animation: animation 1s ease-out;
z-index: 99;
}
#keyframes animation{
from{
left: -200%;
}
}
My JS:
var object = document.querySelector('#object');
window.addEventListener('scroll', function() {
var s = $(document).scrollTop();
var percent_from_top = s/this.innerHeight;
if(0 <= percent_from_top <= 1){
object.style.left = 150*(percent_from_top)+'%';
object.style.transition = "0.75s linear";
}
});
Problem with strip:
My HTML:
<section id="first_section">
<div class="strip"></div>
</section>
My CSS:
#first_section > .strip{
left: 0%;
right:0;
margin: auto;
margin-top:-30%;
width: 40%;
height: 130%;
transform: rotate(70deg);
background: rgba(0,0,0, 0.9);
}
It all works...
but it doesn't seem effective enough, because
it slows down, and
it partially appears
I tried to use clip-path for example, but it works the same way.
Is there a way to create a page more "evenly"?

Can someone explain why this bug happens on my navbar?

If you look closely, when you scroll down fast, the navbar turns black for a split second before it disappears. How do I prevent this bug from happening?
What I am trying to do with the navbar:
1. The navbar is supposed to become transparent at the top of the page except for the text inside the navbar.
2.when you scroll down the page the navbar should disappear fully, the text should also disappear
3. when you scroll up in the bottom part of the page, the navbar should reappear with a black background.
$(document).ready(function() {
// Transition effect for navbar
$(window).scroll(function() {
// checks if window is scrolled more than 500px, adds/removes solid class
if($(this).scrollTop() > 500) {
$('.header').addClass('solid');
} else {
$('.header').removeClass('solid');
}
});
});
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = 505;
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 350);
function hasScrolled() {
var st = $(this).scrollTop();
if(Math.abs(lastScrollTop - st) <= delta)
return;
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').addClass('no-bar').removeClass('solid');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('no-bar');
}
}
lastScrollTop = st;
}
/************************************************HEADER*********************************************************/
body {
height:500%;
padding-bottom: 500%;
background: green;
}
.header {
box-sizing: border-box;
width: 100vw
padding-top: 6%;
padding-bottom: 6%;
position: fixed;
top: 0%;
left: 0%;
padding-right: 100vw;
transition: top 0.2s ease-in-out;
z-index: 324;
border-bottom: 0%;
background-color: transparent;
transition: background-color 1s ease 0s;
}
.solid {
background-color: black;
transition: background-color 1s ease 0s;
box-shadow: 0 0 4px grey;
}
.no-bar {
opacity: 0;
}
.logo {
color: yellow;
position: inline-block;
position: absolute;
top: 38%;
margin-top: 0%;
padding: 0;
left: 37%;
}
.nav-fade {
opacity: 0;
transition: 0.5s;
}
.section-1 {
position: relative;
top:80%;
padding-top: 6%;
padding-bottom: 50%;
height: 200%;
width: 100%;
background: green;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="STACK-HEADER.CSS">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<header class="header">
<div class="logo">
<h1>HEADER</h1>
</div>
</header>
<section class="section-1">
</section>
<section class="section-1">
</section>
<script type="text/javascript" src="STACK-HEADER.JS"></script>
</body>
</html>
. How do I stop this from happening?
This is happening because you have merged two conditions in a if:
if (st > lastScrollTop && st > navbarHeight){
// Scroll Down
$('header').addClass('no-bar').removeClass('solid');
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('no-bar');
}
}
t > lastScrollTop means we're going down otherwise we're assuming we're going up.
If we're going up the solid class is added.
But since you've merged t > lastScrollTop && st > navbarHeight it now means that we're assuming to go up whenever st <= navbarHeight.
Therefore the solid bar is showing when we scroll down near the top.
You just have to rewrite this piece of code like this:
if (st > lastScrollTop){
// Scroll Down
if (st > navbarHeight) {
$('header').addClass('no-bar').removeClass('solid');
}
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('no-bar');
}
}
Be careful with else!
Working snippet below:
$(document).ready(function() {
// Transition effect for navbar
$(window).scroll(function() {
// checks if window is scrolled more than 500px,
// adds/removes solid class
if($(this).scrollTop() > 500) {
$('.header').addClass('solid');
} else {
$('.header').removeClass('solid');
}
});
});
var didScroll;
var lastScrollTop = 0;
var delta = 5;
var navbarHeight = 505;
$(window).scroll(function(event){
didScroll = true;
});
setInterval(function() {
if (didScroll) {
hasScrolled();
didScroll = false;
}
}, 350);
function hasScrolled() {
var st = $(this).scrollTop();
if(Math.abs(lastScrollTop - st) <= delta)
return;
if (st > lastScrollTop){
// Scroll Down
if (st > navbarHeight) {
$('header').addClass('no-bar').removeClass('solid');
}
} else {
// Scroll Up
if(st + $(window).height() < $(document).height()) {
$('header').removeClass('no-bar');
}
}
lastScrollTop = st;
}
/************************HEADER*********************************/
body {
height:500%;
padding-bottom: 500%;
background: green;
}
.header {
box-sizing: border-box;
width: 100vw
padding-top: 6%;
padding-bottom: 6%;
position: fixed;
top: 0%;
left: 0%;
padding-right: 100vw;
transition: top 0.2s ease-in-out;
z-index: 324;
border-bottom: 0%;
background-color: transparent;
transition: background-color 1s ease 0s;
}
.solid {
background-color: black;
transition: background-color 1s ease 0s;
box-shadow: 0 0 4px grey;
}
.no-bar {
opacity: 0;
}
.logo {
color: yellow;
position: inline-block;
position: absolute;
top: 38%;
margin-top: 0%;
padding: 0;
left: 37%;
}
.nav-fade {
opacity: 0;
transition: 0.5s;
}
.section-1 {
position: relative;
top:80%;
padding-top: 6%;
padding-bottom: 50%;
height: 200%;
width: 100%;
background: green;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="STACK-HEADER.CSS">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
<header class="header">
<div class="logo">
<h1>HEADER</h1>
</div>
</header>
<section class="section-1">
</section>
<section class="section-1">
</section>
<script type="text/javascript" src="STACK-HEADER.JS"></script>
</body>
</html>

Animating back and forth based on scroll position

I have created a small demo of two boxes animating in and out based on scroll position. But this isn't exactly what I want to achieve. What I want is for the boxes to animate based on scroll position not just transition in and out when a certain point is reached.
For example the scrolling should control the animation so if you scroll down the boxes will animate in, if you scroll up they will animate out. If you stop scrolling mid animation the animation will stop. If you reverse the scroll position the animation will reverse. So the animation only happens as you scroll.
I hope that is clear enough for you to understand. I will try provide a link to what I am trying to achieve. But for now here's my demo just using a transition to animate the boxes.
jQuery(document).ready(function($){
var scroll_pos = $(window).scrollTop();
var box = $('#container').offset().top - 200;
$(window).on('scroll', function(){
scroll_pos = $(window).scrollTop();
$('p').html(scroll_pos);
if(scroll_pos >= box){
$('#left').addClass('animate');
$('#right').addClass('animate');
}else{
$('#left').removeClass('animate');
$('#right').removeClass('animate');
}
});
});
#container{
width: 600px;
height: 300px;
margin: 1000px auto;
overflow: hidden;
font-size: 0;
}
#left{
width: 55%;
height: 300px;
background-color: blue;
display: inline-block;
transform: translateX(-100%);
transition: all 0.5s;
}
#right{
width: 45%;
height: 300px;
background-color: yellow;
display: inline-block;
transform: translateX(100%);
transition: all 0.5s;
}
#left.animate{
transform: translateX(0%);
}
#right.animate{
transform: translateX(0%);
}
p{
position: fixed;
top: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p></p>
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
Here's an example of what I want to achieve. As you can see the scroll controls the animation of the fidget spinner https://ampbyexample.com/visual_effects/basics_of_scrollbound_effects/
Based on this answer you could do someting like:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// Now our stuff:
var $container = $("#container");
var $left = $("#left");
var $right = $("#right");
$container.inViewport(function( px ) {
var v = 1 - px / $container.height(); // Value from 1.0 to 0.0 and v.versa
$("p").text(v);
$left.css({transform: `translateX(${ -v * 100 }%)`});
$right.css({transform: `translateX(${ v * 100 }%)`});
});
body {
height: 500vh;
}
#container {
position: relative;
margin: 0 auto;
top: 200vh;
overflow: hidden;
width: 60vw;
height: 60vh;
}
#left,
#right {
width: 50%;
height: 100%;
float: left;
}
#left {
background-color: blue;
transform: translateX(-100%);
}
#right {
background-color: yellow;
transform: translateX(100%);
}
p {position: fixed; top:0; left: 0;}
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
<p></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

multiple transition runs instantly even though transition-duration is given

the first transition runs instantly and the second one runs perfect. I been trying to run it at the same time with the transition-duration. Some help would be highly appreciated. Thanks :)
<script type="text/javascript">
function Scroll(){
var top = document.getElementById('header');
var ypos = window.pageYOffset;
document.getElementById('color-change-on-scroll').innerHTML=ypos;
if(ypos > 2350) {
var elem = document.getElementById('homer_pic');
elem.style.transition="top 1.0s linear 0s"; // runs instantly
elem.style.top="0px";
elem.style.transition="opacity 1.0s linear 0s"; // runs perfect
elem.style.opacity=1;
document.getElementById('color-change-on-scroll').innerHTML=ypos+" yposhigher then 2350";
}
}
window.addEventListener("scroll",Scroll);
</script>
#homer_pic{
position: relative;
float: left;
height: auto;
width: 33.333333%;
background-color: #f2f2f2;
text-align: center;
padding-top: 120px;
padding-bottom: 150px;
opacity: 0;
top:100px;
}
Each element can only have one CSS transition property.
elem.style.transition="top 1.0s linear 0s"; // runs instantly
elem.style.top="0px";
elem.style.transition="opacity 1.0s linear 0s"; // runs perfect
elem.style.opacity=1;
The second transition definition overrides the first one. That's why it seems to run instantly. To transition multiple properties on the same element you'd have to do it like this:
elem.style.transition = "top 1.0s linear 0s, opacity 1.0s linear 0s";
elem.style.top = "0px";
elem.style.opacity = 1;
function Scroll() {
var top = document.getElementById('header');
var ypos = window.pageYOffset;
document.getElementById('color-change-on-scroll').innerHTML = ypos;
if (ypos > 50) {
var elem = document.getElementById('homer_pic');
elem.style.transition = "top 1.0s linear 0s, opacity 1.0s linear 0s";
elem.style.top = "0px";
elem.style.opacity = 1;
document.getElementById('color-change-on-scroll').innerHTML = ypos + " yposhigher then 50";
} else {}
}
window.addEventListener("scroll", Scroll);
body {
height: 400px;
}
#homer_pic {
position: relative;
float: left;
height: auto;
width: 33.333333%;
background-color: black;
text-align: center;
padding-top: 120px;
padding-bottom: 150px;
opacity: 0.5;
top: 100px;
}
<div id="homer_pic">
Pic
</div>
<div style="position: fixed" id="color-change-on-scroll">
0
</div>

Categories

Resources