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>
Related
I am working with JavaScript to move an HTML div across the page. Below is the movement that I want the element to follow:
It should be starting and following routes 1, 2, 3 and 4. It should only change the route once the element reaches the max width/height of the page. I am using the below code and I am stuck on how to continue further.
var box = document.getElementById("box");
var height = document.getElementById("container").offsetHeight;
var widht = document.getElementById("container").offsetWidth;
window.setInterval(() => {
let addPosition = (parseInt(box.style.top) + 10);
let subPosition = (parseInt(box.style.top) - 10);
if (addPosition > height)
box.style.top = subPosition + 'px';
else
box.style.top = addPosition + 'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 100%;
height: 100%;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>
No JS is needed to make this animation. You can use CSS-Animations for this.
For that, you use keyframes and change the position where the element should move to. You can define the speed with the animation-duration property and repeat it with animation-iteration-count
body {
margin: 0;
height: 100vh;
}
div {
height: 50px;
width: 50px;
background-color: red;
position: fixed;
animation-name: moveBox;
animation-duration: 5s;
animation-iteration-count: infinite;
}
#keyframes moveBox {
0% { top: 0; left: 0; }
20% { top: calc(100% - 50px); left: 0; }
50% { top: 0; left: calc(100% - 50px); }
70% { top: calc(100% - 50px); left: calc(100% - 50px); }
100% { top: 0; left: 0; }
}
<div></div>
As someone else mentioned, this is normally done with CSS animations, but if you have to use javascript you basically want a state system that keeps track of what your current target is.
Here's roughly how you could do it:
let box = document.getElementById("box");
let height = document.getElementById("container").offsetHeight;
let width = document.getElementById("container").offsetWidth;
let getAngle=function(x1,y1,x2,y2)
{
return Math.atan2(y2-y1,x2-x1);
}
let state=0;
let speed=10;//how many pixels to move per interval
let x=0,y=0;
let xTarget=0,yTarget=0;
window.setInterval(() => {
//we do not account for the box's size here, but if we needed to we could add or subtract it to the target as needed
switch(state) {
case 0:
xTarget=0;
yTarget=height;
break;
case 1:
xTarget=width;
yTarget=0;
break;
case 2:
xTarget=width;
yTarget=height;
break;
case 3:
xTarget=0;
yTarget=0;
break;
}
//do we still have more steps left? calculate the angle to the target, then step in that direction
if (state<4)
{
var angle=-getAngle(x,y,xTarget,yTarget)+Math.PI/2;
x+=Math.sin(angle)*speed;
y+=Math.cos(angle)*speed;
}
//are we close enough to the target? snap to the target, then switch to the next state
//note: you may want to calculate the actual distance here instead
if (Math.abs(xTarget-x)<speed && Math.abs(yTarget-y)<speed)
{
x=xTarget;
y=yTarget;
state++;
}
if (state>=4) state=0;//if you want the movement to loop
box.style.left=x+'px';
box.style.top=y+'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 300px;
height: 200px;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>
I have some code that displays 4 divs at a random hight at specified distances from the viewport sides, each div appears with a different delay speed and then moves around the page at random.
I want to add a delay to the movement of each div so they don't all start and stop moving at the same time but every time I add ad .delay() it breaks. Any help?
Thanks
HTML
<div class="content">
<div class="loopbox">
<div id="rand_pos" class="loop mobile box1">L</div>
<div id="rand_pos" class="loop mobile box2">O</div>
<div id="rand_pos" class="loop mobile box3">O</div>
<div id="rand_pos" class="loop mobile box4">P</div>
</div>
<div class="info">
<h1>COMING SOON</h1>
<p>info#loopstudio.uk</p>
</div>
</div>
*CSS
#import url('https://fonts.googleapis.com/css?family=Marcellus&display=swap');
*:focus {
outline: none;
}
html { overflow: hidden; }
body {
margin: 0;
background-color:#FFF9F3;
}
p,h1 {
font-family:sans-serif;
}
h1{
font-weight:100;
}
.loop {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
font-size:22vw;
font-family:'Marcellus', serif;
font-weight:100;
color: black;
position: absolute;
}
.loop:hover {
animation: shake 0.82s cubic-bezier(.5,.01,.01,.05) 1;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000px;
-webkit-animation-fill-mode:forwards;
-moz-animation-fill-mode:forwards;
animation-fill-mode:forwards;
}
.box1{
top:10vh;
left:8vw;
display:none;
}
.box2{
top:20vh;
left:30vw;
display:none;
}
.box3{
top:30vh;
right:35vw;
display:none;
}
.box4{
top:40vh;
right:10vw;
display:none;
}
.content {
position: relative;
height: 100vh;
width: 100vw;
margin: 0 auto;
resize: both;
}
.info {
width: 100%;
height:auto;
transform: translate(-50%, -50%);
position: fixed;
top: 50%;
left: 50%;
resize: both;
text-align:center;
z-index:-1000;
}
JS
$('document').ready(function(){
$('.box1').delay(500).fadeIn(850);
$('.box2').delay(1000).fadeIn(850);
$('.box3').delay(750).fadeIn(850);
$('.box4').delay(1250).fadeIn(850);
});
$('document').ready(function() {
var bodyHeight = document.body.clientHeight;
var randPosY = Math.floor((Math.random()*bodyHeight));
$('#rand_pos').css('top', randPosY);
});
$(document).ready(function(){
animateDiv('.box1');
animateDiv('.box2');
animateDiv('.box3');
animateDiv('.box4');
});
function makeNewPosition(){
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(myclass){
var newq = makeNewPosition();
$(myclass).animate({ top: newq[0], left: newq[1] }, 8000, function(){
animateDiv(myclass);
});
};
I would like to make a website with mouse parallax effect like in this page http://brightmedia.pl background mouse parallax is so smooth..
I have two questions:
When you mouseover on a container from, let's say, the top left corner, the image jumps. How can I make a smooth animation?
When you mouseout of a container, how can I make the image move a little bit and stop with a smooth animation?
What would code to solve these problems be?
Here is basic code:
$('.container').mousemove( function(e){
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({marginLeft: -xPos/20});
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body{
height: 1000px;
}
h1{
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="css.css">
</head>
<body>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
As I had solved the problem long time ago and I forgot about this post so I decided to update with the answer. Maybe it will be helpful for anyone else.
Problem solved by using GSAP. Below You can see the code that works exactly as I wanted
let wrap = document.getElementById('container');
let request = null;
let mouse = { x: 0, y: 0 };
let cx = window.innerWidth / 2;
let cy = window.innerHeight / 2;
document.querySelector('.container').addEventListener('mousemove', function(event) {
mouse.x = event.pageX;
mouse.y = event.pageY;
cancelAnimationFrame(request);
request = requestAnimationFrame(update);
});
function update() {
dx = mouse.x - cx;
dy = mouse.y - cy;
let tiltx = (dy / cy );
let tilty = - (dx / cx);
TweenMax.to("#container img", 1, {x:-tilty*20, y:-tiltx*20, rotation:0.01, ease:Power2.easeOut});
}
window.addEventListener('resize', function(event){
window.innerWidth / 2;
window.innerHeight / 2;
});
* {
margin:0;
padding:0;
box-sizing:border-box;
}
.container {
position: relative;
width: 100%;
height: 100vh;
overflow: hidden;
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.container img {
width: 110%;
height: 120vh;
position: absolute;
}
h1 {
z-index:100;
font-size: 6rem;
z-index: 10;
color:#333;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenMax.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>GSAP Mouse Parallax</h1>
</div>
You can rely one mouseenter / mouseleave to add animation:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css({
marginLeft: -xPos / 10
});
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').animate({
"marginLeft": -xPos / 10
}, "slow");
});
$('.container').mouseleave(function(e) {
$('#par1').animate({
"marginLeft": "0"
}, "slow");
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
As Temani said, playing with transition and eventually delay should do the job.
For 1st question: transition seems appropriate, associated with a mousein listener. Or even better, use the $(element).animate() function that allows to set the animation duration. That way, you don't set any value for transition duration.
For 2nd question: listener on mouseout > same process, but shorter animation (for the img shifting as well as the animation duration).
This should also give you some ideas:
https://codepen.io/Aldlevine/pen/Jowke
Based on Teemani below code example:
$('.container').mousemove(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseenter(function(e) {
var xPos = e.pageX;
var yPos = e.pageY;
$('#par1').css("margin-left", -xPos / 10);
});
$('.container').mouseleave(function(e) {
$('#par1').css({"transition": "margin-left 1s ease-in-out", "margin-left": "0"});
setTimeout( function() {
$('#par1').css("transition", "initial");
}, 500);
});
.container {
position: relative;
width: 100%;
height: 800px;
background: grey;
overflow: hidden;
margin: 0 auto;
}
.container img {
width: 110%;
height: 100vh;
position: absolute;
transition: margin-left 0.2s;
/* transition: margin-left 0.2s ease-in-out 0.2s;*/
}
body {
height: 1000px;
}
h1 {
font-size: 60px;
z-index: 10;
position: absolute;
left: 50%;
top: 30%;
transform: translate(-50%, -50%);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container" id="container">
<img id="par1" src="https://www.gettyimages.ca/gi-resources/images/Homepage/Hero/UK/CMS_Creative_164657191_Kingfisher.jpg" alt="">
<h1>TEXT</h1>
</div>
I'm trying to do an animation on page scroll where selected element will animate from left to right on scroll down and if back to top then animate the selected element from right to left (default position), here's what I tried
$(document).ready(function() {
$(window).scroll(function() {
var wS = $(this).scrollTop();
if (wS <= 10) {
$("#test-box").animate({
'left': 100
}, 500);
}
if (wS > 11) {
$("#test-box").animate({
'left': $('#main-container').width() - 100
}, 500);
}
});
});
#main-container {
width: 100%;
overflow: auto;
height: 500px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100;
top: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>
As you can see, on scroll down, the test box moves as I instruct but when scroll up, it does not go to the left as default, any ideas, help please?
You can add a global variable to control the animation. See the working snippet below please, where I've commented parts of the code that I added:
$(document).ready(function() {
var animated = false; //added variable to control the animation
$(window).scroll(function() {
var wS = $(this).scrollTop();
if (animated && wS <= 10) {
$("#test-box").animate({
'left': 100
}, 500);
animated = false; //animation ended
}
if (!animated && wS > 11) {
$("#test-box").animate({
'left': $('#main-container').width() - 100
}, 500);
animated = true; //it was animated
}
});
});
#main-container {
width: 100%;
overflow: auto;
height: 500px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100px;
top: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>
This should work, it also uses css for the animation.
$(document).ready(function() {
var box = document.querySelector('#test-box');
var stateClass = '-right';
window.addEventListener('scroll', function(event) {
box.classList.toggle(stateClass, document.body.scrollTop > 10);
});
});
#main-container {
width: 100%;
overflow: auto;
height: 2000px;
}
#test-box {
background: red;
color: #ffffff;
padding: 15px;
font-size: 18px;
position: fixed;
left: 100px;
top: 10;
transition: .5s linear;
}
#test-box.-right {
left: 100%;
transform: translateX(-100%) translateX(-100px)
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main-container">
<div id="test-box">test</div>
</div>
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I try to make this effect using css.
This is the effect:
I try to make div that:
div {
height: 300px;
width: 10px;
position: absolute;
border-radius: 0px 500px 500px 0;
-moz-border-radius: 0px 500px 500px 0;
-webkit-border-radius: 0px 500px 500px 0;
background-color: grey;
opacity:0.1;
}
and then by css change the width of this effect.But it look very ugly it more square then circle and also I the change in the width dont make it become like the effect. it looks like the shape become bigger in width but not become more circle...
How can I make this effect by css/js ? everything that I tried with the div look very bad.
Thanks.
The effect is a little tricky because of its shape. The key is that the circle that you are creating with the div has to be moved mostly off screen to get a curve that aligns more with the example you gave.
.container .effect{
position:absolute;
width:200px;
height:80%;
top:10%;
right:-140px;
background-color:#fff;
border-radius:100% 100% 100% 100%;
transition:width 500ms ease-in-out, right 500ms ease-in-out, opacity 500ms ease-in-out;
opacity:.7;
}
Here is a fiddle with more details. Try turning the overflow:hidden off on the .container element to see more details of whats going on. The JavaScript is just to show the effect happening.
**Side note: the background image is not my own and was used for education purposes. Credit belongs with the original owner.
Just give it a try (Don't forget to emulate touch events in chrome):
var _div = document.getElementById('wrapper');
var _elem = document.getElementById('div');
_div.addEventListener('touchmove', function () {
_elem.style.width = '60px';
});
_div.addEventListener('touchend', function () {
_elem.style.width = '0';
});
*, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
#div {
height: 95%;
width: 0;
top: 2.5%;
position: absolute;
border-radius: 0 500px 500px 0;
-moz-border-radius: 0 500px 500px 0;
-webkit-border-radius: 0 500px 500px 0;
background-color: gray;
opacity: 0.1;
-webkit-transition: width .2s; /* Safari */
transition: width .2s;
}
#wrapper {
width: 100%;
height: 100%;
background: darkgreen;
}
<div id="wrapper">
<div id='div'></div>
</div>
Here is another take using pseudo-elements and transforms. When scroll reaches end on both sides, the faux-rubber-banding effect will show up.
Works with mouse scroll to test on non-touch screen desktops. For Chrome, can emulate mouse events to test.
Demo Fiddle: http://jsfiddle.net/abhitalks/v4mLkttL/
Demo Snippet:
var $wrap = $('#wrap'), startX, isDrag = false;
$wrap.on('touchstart', function(e) {
startX = e.originalEvent.touches[0].clientX; isDrag = true;
});
$wrap.on('touchmove', function(e) {
var delta = e.originalEvent.changedTouches[0].clientX - startX,
pos = $(this).scrollLeft(), w = $(this).width(),
iw = $(this).innerWidth(), sh = this.scrollWidth
;
if (isDrag) {
if ((delta > 0) && (pos <= 0)) {
$wrap.addClass('rubberLeft');
isDrag = false; e.preventDefault();
}
if ((delta < 0) && (pos + iw >= sh)) {
$wrap.addClass('rubberRight');
isDrag = false; e.preventDefault();
}
}
});
$wrap.on('touchend', function(e) {
isDrag = false; clearRubber();
});
$wrap.on('mousewheel DOMMouseScroll', function(e) {
var start = e.originalEvent,
delta = start.wheelDelta || -start.detail,
pos = $(this).scrollLeft(), w = $(this).width(),
iw = $(this).innerWidth(), sh = this.scrollWidth
;
this.scrollLeft += delta * -1;
if (pos <= 0) { $wrap.addClass('rubberLeft'); setTimeout(clearRubber, 600); }
else if (pos + iw >= sh) { $wrap.addClass('rubberRight'); setTimeout(clearRubber, 600); }
else { clearRubber(); }
e.preventDefault();
});
function clearRubber() { $wrap.removeClass('rubberLeft').removeClass('rubberRight'); }
* { box-sizing: border-box; padding: 0; margin: 0; }
html, body { height: 100vh; width: 100vw; overflow: hidden; }
#wrap {
min-width: 100vw; height: 100vh;
overflow-y: hidden; overflow-x: scroll;
background-color: #000; white-space: nowrap;
-webkit-overflow-scrolling: touch;
}
#wrap img { display: inline-block; vertical-align: top; }
#wrap::before, #wrap::after {
content: ''; display: block;
position: absolute; top: 4%;
width: 100px; height: 90%;
background-color: rgba(255,255,255,0.6);
box-shadow: 0 0 10px 4px rgba(0,0,0,0.5);
border-radius: 50%; transform: translateX(0px);
transition: transform 0.5s;
}
#wrap::before { left: -105px; }
#wrap::after { right: -105px; }
#wrap.rubberLeft::before { transform: translateX(45px); }
#wrap.rubberRight::after { transform: translateX(-45px); }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="wrap">
<img class="page" src='//lorempixel.com/240/320' />
<img class="page" src='//lorempixel.com/241/320' />
<img class="page" src='//lorempixel.com/239/320' />
<img class="page" src='//lorempixel.com/240/320' />
<img class="page" src='//lorempixel.com/241/320' />
<img class="page" src='//lorempixel.com/239/320' />
</div>