I want to make an animation on my product page. When user clicks "add to cart" the product image will be animated moving and shrinking to the cart icon in the nav bar.
Here is a sample html
$('div.test').on('animationend', (e) => {
$(e.target).remove();
})
//user click
$('div.test').addClass('animateTest');
.test {
position : fixed;
top : 200px;
left : 600px;
background : red;
width : 200px;
height : 300px;
}
#keyframes toCart {
25% {
top : 850px;
left : 550px;
width : 200px;
height : 300px;
}
100% {
top : 100px;
left : 1100px;
width : 0;
height : 0
}
}
.animateTest {
animation : toCart 2s;
/* animation-fill-mode: forwards; */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="test">
</div>
The hard part is, since users' viewports vary, I probably need to use javascript to get the cart icon's position(unless I can get it from CSS which I don't think is possible):
whereIsCart = $('#cartIcon').offset()
and I need to do something like
100% {
top : whereIsCart.top;
left : whereIsCart.left;
width : 0;
height : 0
}
But how can I do this?
Or, is there any better practice to achieve the same goal?
It may be easier to use css transitions instead of keyframe animations:
.test {
// ...
transition: transform 1s ease-in-out;
}
// on click
whereIsCart = $('#cartIcon').offset();
$('div.test').css('transform', 'translate(' + whereIsCart.left + 'px, ' + whereIsCart.top + 'px) scale(0)');
When working with CSS in JavaScript you may want to use the CSSOM API; more specifically, its factory functions for unit values, e.g. CSS.px(), CSS.percent().
Note that parts of the CSSOM API are still experimental, e.g. the factory functions. In production, you should make sure that the target browsers support the features you use.
Regardless of using CSS or JS for the animation itself: To get the element's current position in the viewport you can use Element.getBoundingClientRect(), or more generally Element.getClientRects() for all its relevant boxes.
CSS Custom Properties
You can use custom properties for the initial position. You can set them via JavaScript, and even provide a fallback value in CSS.
If you use them for the animating (not as animated) properties, it should just work:
const divTest = document.querySelector("div.test");
// Example for non-empty custom properties
divTest.style.setProperty("--top", CSS.px(20));
divTest.style.setProperty("--left", CSS.px(80));
// Should happen on click:
toCart(divTest);
function toCart(element) {
const rect = element.getBoundingClientRect();
element.style.setProperty("--top", CSS.px(rect.top));
element.style.setProperty("--left", CSS.px(rect.left));
element.classList.add("animateTest");
}
.test {
position: fixed;
top: var(--top, 10%);
left: var(--left, 10%);
width: 200px;
height: 300px;
background: red;
}
#keyframes toCart {
25% {
top: 80%;
left: 50%;
width: 200px;
height: 300px;
}
100% {
top: 10%;
left: 100%;
width: 0;
height: 0;
}
}
.animateTest {
animation: toCart 2s;
}
<div class="test"></div>
Sidenote: If you want to animate custom properties themselves, you have to define the in a #property rule. Otherwise CSS cannot animate it since its type may be anything (animating e.g. from a length to a color is impossible).
Web Animations API
In JavaScript, you can use the Web Animations API, which is essentially CSS animations but in JS.
You can define keyframes, duration, fill-mode and more. Since Animation.finished is a promise, you can simply react to the animation's end via await or Promise.then().
Example:
const divTest = document.querySelector("div.test");
// Should happen on click:
const animation = animateToCart(divTest);
animation.finished.then(() => console.log("Animation finished. This could start a new animation!"));
function animateToCart(element) {
const rect = element.getBoundingClientRect();
const keyframes = [
{
offset: .25,
top: CSS.percent(80),
left: CSS.percent(50),
width: CSS.px(rect.width),
height: CSS.px(rect.height)
}, {
top: CSS.percent(10),
left: CSS.percent(100),
width: 0,
height: 0
}
];
return element.animate(keyframes,
{
duration: 2000,
easing: "ease" // Is default in CSS, but not in Web Animations...
}
);
}
.test {
position: fixed;
top: 10%;
left: 10%;
width: 200px;
height: 300px;
background: red;
}
<div class="test"></div>
Multi-step animations are also easily done with Web Animations, since you can start another animation after the first animation's promise has resolved.
CSS variables sample code...
const
bluElm = document.querySelector('#blue_elm')
, btAnim = document.querySelector('#bt-anim')
, btMovE = document.querySelector('#bt-movE')
, elTest = document.querySelector('.test')
;
btMovE.onclick = () =>
{
bluElm.classList.toggle('move');
}
btAnim.onclick = () =>
{
let rect = bluElm.getBoundingClientRect();
/* change CSS variables values as style Property ------------- */
elTest.style.setProperty('--p_top', `${rect.bottom}px`);
elTest.style.setProperty('--p_left', `${rect.left}px`);
elTest.classList.add('animateTest');
}
elTest.onanimationend = () =>
{
elTest.classList.remove('animateTest');
}
#blue_elm {
position : fixed;
top : 20px;
left : 300px;
width : 20px;
height : 20px;
border-radius : 10px;
background : cornflowerblue;
}
#blue_elm.move {
top : 50px;
left : 150px;
}
.test {
position : fixed;
top : 200px;
left : 600px;
background : red;
width : 200px;
height : 300px;
--p_top : 0; /* CSS variables declaration */
--p_left : 0;
}
.animateTest {
animation : toCart 2s;
}
#keyframes toCart {
25% {
top : 850px;
left : 550px;
width : 200px;
height : 300px;
}
100% {
top : var(--p_top); /* CSS variables usage */
left : var(--p_left);
width : 0;
height : 0
}
}
<button id="bt-anim"> show animation</button>
<button id="bt-movE"> move element +- 150px</button>
<div id="blue_elm"></div>
<div class="test"></div>
Related
I have this piece of css but I want to change the width in the keyframe with a variable in javascript. How can I do that?
#keyframes test {
100% {
width: 100%;
}
}
Does it have to be a keyframe animation? Typically you would use the CSS transition property for this kind of animation powered by JavaScript, like this:
var width = 50;
document.getElementById('button').addEventListener('click', () => {
width += 50;
document.getElementById('box').style.width = `${width}px`;
});
#box {
background: red;
height: 50px;
width: 50px;
transition: width .5s;
margin-bottom: 1em;
}
<div id="box"></div>
<button id="button">Change Width</button>
If you have a more general animation (that can't be encompassed by just doing a transition) then you can use JS to set a CSS variable.
Taking the example in the question, replace the 100% with a variable:
#keyframes test {
100% {
width: var(--bg);
}
}
and the Javascript you'd have something like:
thediv.style.setProperty('--bg', '60px');
#JohnUleis already answeared correctly. I was too late. But I add just for fun a solution. Is named: How lfar is Rom? ;-)
Cheers
let root = document.documentElement;
const div = document.querySelector('div');
root.addEventListener("mousemove", e => {
div.style.setProperty('--width', e.clientX + "px");
div.innerHTML = e.clientX + ' km';
});
:root {
--width: 100%;
}
div {
background: hotpink;
width: var(--width);
text-align: center;
color: white;
}
<div>how far is rom?</div>
This question is about SVG.js
I use two move commands on animations of two SVG objects to swap their positions. I then use a callback from afterAll to move one of these objects further. I find that I need to specify my new position relative the the previous changes, i.e. from the position of the object right at the start. This is a headache, for keeping track of old coordinate changes (deltas).
So:
do I need to "commit" (or finish) my animation to change the object position permanently, before moving on? How?
am I accidentally re-using the FX object by calling animation() again on the same object at a different part in the code?
Thanks for any help...
If you just want to swap SVG images maybe you don't need a library (A and B options)
A) To do so you can rely on basic CSS transition.
div {
position: absolute;
width: 100px;
height: 100px;
}
#one {
background-color: #39464e;
left: 0;
}
#two {
background-color: #ff4f68;
right: 0;
}
body.swap #one {
left: calc(100% - 100px);
transition: 5s;
}
body.swap #two {
right: calc(100% - 100px);
transition: 5s;
}
Example: https://jsfiddle.net/gengns/et9dbpur/
You can use a svg tag instead of a div or set your SVG in a div background-image.
B) If you don't want to animate, just simple swap them you can do it in a declarative way with CSS Grid.
body {
display: grid;
grid-template-areas: 'one two';
}
body.swap {
grid-template-areas: 'two one';
}
div {
width: 100px;
height: 100px;
}
#one {
background-color: #39464e;
grid-area: one;
}
#two {
background-color: #ff4f68;
grid-area: two;
}
Example: https://jsfiddle.net/gengns/bsacypd8/
C) Using svg.js 2.7.1
SVG.on(document, 'DOMContentLoaded', function() {
const draw = SVG('drawing')
// Rectangles
const rect_one = draw.rect(100, 100).attr({fill: '#39464e'})
const rect_two = draw.rect(100, 100).attr({fill: '#ff4f68'}).move(500, 0)
// Swap
rect_one.animate().move(500, 0)
rect_two.animate().move(0, 0).after(() => {
// Swap again
rect_one.animate().move(0, 0)
rect_two.animate().move(500, 0)
})
})
Example: https://jsfiddle.net/gengns/497j1z0a/
Hope this help :)
The problem with my slider is that when it gets to the last slide and i click next it jumps over the two slides to get to the first one. Similarly when i am on the first slide and click previous, it jumps over slides to get to the last one. I would like to make it that when i get to the last slide and click NEXT the first slide would come from the right to left. (similar concept for the PREVIOUS button on first slide). I tried using insertBefore() and appendChild() for the slides but couldn't figure it out...
Here is my code:
// Slider
const slider_wrapp = document.querySelector('.tract-slider');
const slider = document.querySelector('.tract-slider-wrapp');
var slide = document.getElementsByClassName('tract-slide');
const leftBtn = document.querySelector('.slide-left');
const rightBtn = document.querySelector('.slide-right');
let swWidth = slider_wrapp.clientWidth;
let sliderWidth = swWidth * slide.length;
let slideWidth = 0;
slider.style.width = sliderWidth + "px";
for (var i = 0; i < slide.length; i++) {
slide.item(i).style.width = swWidth + "px";
}
function moveRight() {
slideWidth === sliderWidth - swWidth ? slideWidth = 0 : slideWidth += swWidth;
slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}
function moveLeft() {
slideWidth === 0 ? slideWidth = sliderWidth - swWidth : slideWidth -= swWidth;
slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}
rightBtn.addEventListener("click", function() {
moveRight();
});
leftBtn.addEventListener("click", function() {
moveLeft();
});
.tract-slider {
width: 100%;
height: 75vh;
position: relative;
overflow: hidden;
}
.tract-slider-wrapp {
height: 100%;
position: relative;
-webkit-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
-o-transition: all 350ms cubic-bezier(.08, .13, 0, .81);
transition: all 350ms cubic-bezier(.08, .13, 0, .81);
}
.tract-slide {
height: 100%;
float: left;
position: relative;
display: block;
background-position: center;
-webkit-background-size: cover;
background-size: cover;
}
.tract-slide:nth-child(1) {
background-image: url("https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg");
}
.tract-slide:nth-child(2) {
background-image: url("https://static.pexels.com/photos/29017/pexels-photo-29017.jpg");
}
.tract-slide:nth-child(3) {
background-image: url("https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg");
}
.tract-slider-control {
position: absolute;
left: 0;
bottom: 0;
background: #ffffff;
padding: 1em;
}
.tract-slider-btn {
display: inline-block;
cursor: pointer;
margin-left: 1em;
}
.tract-slider-btn:nth-child(1) {
margin-left: 0;
}
<div class="tract-slider">
<div class="tract-slider-wrapp">
<div class="tract-slide"></div>
<div class="tract-slide"></div>
<div class="tract-slide"></div>
</div>
<div class="tract-slider-control">
<div class="tract-slider-btn slide-left">Prev</div>
<div class="tract-slider-btn slide-right">Next</div>
</div>
</div>
PS. Please use JavaScript for solution
Creating an infinite slider means you need to move your slides around in DOM so they give the impression of a continuous track.
The first thing you need to change is having their backgrounds tied up to their position in DOM. If we want to slide back from first slide to the last one, we need to take the last slide, prepend it before the first one but, considering your current CSS, that will change the backgrounds of all slides, as they are currently bound to their position in DOM (...:nth-child {background-image:...}...).
The second thing that needs changing is positioning the slides into the slider track. If they're floated, whenever we change their order, all the rest of the slides will be affected. By positioning them with position:absolute each slide moves independently, without affecting the others, so it's easier to rearrange them while keeping control.
Long story short, I started from scratch and placed all methods inside a single object: theSlider.
The reset() function does the heavy lifting: it puts before class on first element, current on second and after on all the rest. So you have to put the "last" slide first, because the slider will start with it appended before the "current" one.
The sliding is done by applying go-left and go-right classes to the track. After the transition is done, I just move the first/last slide into the new position, depending on case, and run reset() again (which strips all classes and reapplies them based on new positions).
Animations are handled by CSS. All JavaScript does is apply/remove classes and move the slides in DOM.
var theSlider = {
track : document.querySelector('.tract-slider-wrapp'),
// has to match `transition-duration` in CSS:
duration : 600,
reset : function() {
var slides = document.querySelectorAll('.tract-slider-wrapp > div');
for (var i = 0; i < slides.length; i++) {
slides[i].className = '';
slides[i].classList.add(i > 1? 'after' : (i ? 'current':'before'))
}
},
init : function() {
theSlider.reset();
theSlider.track.classList.remove('not-loaded')
},
next : function() {
theSlider.track.classList.add('go-right');
setTimeout(function(){
var firstSlide = document.querySelector('.tract-slider-wrapp > div:first-child');
theSlider.track.appendChild(firstSlide);
theSlider.reset();
theSlider.track.classList.remove('go-right')
},theSlider.duration)
},
prev : function() {
theSlider.track.classList.add('go-left');
setTimeout(function() {
var lastSlide = document.querySelector('.tract-slider-wrapp > div:last-child');
theSlider.track.insertBefore(lastSlide, theSlider.track.firstChild);
theSlider.reset();
theSlider.track.classList.remove('go-left')
},theSlider.duration)
},
prevButton : document.querySelector('.slide-left'),
nextButton : document.querySelector('.slide-right')
};
window.addEventListener("load", theSlider.init);
theSlider.prevButton.addEventListener('click', theSlider.prev);
theSlider.nextButton.addEventListener('click', theSlider.next);
.tract-slider {
width: 100%;
height: 75vh;
position: relative;
overflow: hidden;
background-color: #f5f5f5;
}
.tract-slider-wrapp {
height: 100%;
transition: all 350ms cubic-bezier(.08, .13, 0, .81);
opacity: 1;
}
.tract-slider-wrapp.not-loaded {
opacity: 0;
}
.tract-slider-wrapp>div {
height: 100%;
position: absolute;
background: transparent no-repeat 50% 50% /cover;
width: 100%;
}
.tract-slider-wrapp > div.before {
margin-left: -100%;
}
.tract-slider-wrapp > div.current + div {
margin-left: 100%;
}
.tract-slider-wrapp > div.after ~ div {
opacity: 0;
}
.tract-slider-control {
position: absolute;
width: 100%;
z-index: 1;
top: 50%;
display: flex;
justify-content: space-between;
transform: translateY(-50%);
}
.tract-slider-control div {
background-color: rgba(0,0,0,.35);
padding: .5rem 1rem;
color: white;
cursor: pointer;
}
.tract-slider-control :first-child {
border-radius: 0 17px 17px 0;
}
.tract-slider-control :last-child {
border-radius: 17px 0 0 17px;
}
body {
margin: 0;
}
.go-right div {
transform: translateX(-100%);
}
.go-left div {
transform: translateX(100%);
}
.go-right div, .go-left div {
transition-property: transform;
transition-timing-function: cubic-bezier(.4,0,.2,1);
/* has to match `duration` in js: */
transition-duration: 600ms;
}
<div class="tract-slider">
<div class="tract-slider-wrapp not-loaded">
<div style="background-image:url('https://static.pexels.com/photos/126282/pexels-photo-126282.jpeg')"></div>
<div style="background-image:url('https://static.pexels.com/photos/29017/pexels-photo-29017.jpg')"></div>
<div style="background-image:url('https://static.pexels.com/photos/70760/dandelion-dandelion-seeds-taraxacum-fluffy-70760.jpeg')"></div>
</div>
<div class="tract-slider-control">
<div class="tract-slider-btn slide-left">Prev</div>
<div class="tract-slider-btn slide-right">Next</div>
</div>
</div>
If you want to change the animation duration you need to change it in both js and css.
The only current limitation is it needs at least 3 slides to work. I guess it could be adjusted to work with only two slides by: cloning the "inactive" slide into third position, removing the clone after transition and cloning the other one.
ToDo's:
prefix CSS so it works in more browsers
replace .classList.add('whatever') with .className += ' whatever' and
.classList.remove('whatever') with .className.replace('whatever', '') if you want to show IE some love.
I told the above just to tell you this: if you want to get going, don't reinvent the wheel.
It's great you use vanilla javascript. But sooner or later you'll end up writing your own wrappers for common things. Depending on how good you are/have become, you'll write your own, limited, custom version of jQuery. Allow me to put things into perspective: Google included a lite version of jQuery into AngularJS. It's that good.
You, as an single developer, do not stand a chance at writing a better, more streamlined and tested version of it. And besides, you don't have to. Use your skill and abilities to go forward, not sideways.
I am moving an <img> element (the octopus) from the large gray <div> above (#large) to the small orange <div> below (#small) using
$(document).on("click", "#large > img", function() {
$(this).appendTo("#small");
});
This works great but I want it to transition smoothly and to 'fly' over so it will slowly interpolate its coordinates and size.
I tried adding a CSS transition
img { transition: all 3s; }
to my <img>, but that won't work as the image is readded to the DOM and not moved.
How can such animation be established?
JS Fiddle
Using the jQuery .append method won't allow you to animate the element between the 2 states.
Here is an example with an animation using CSS transition and the scale() function. This example also uses the transform-origin property to change the position the of the image on the "big" state. Fiddle here.
$(document).on("click", "img", function() {
$(this).toggleClass("big");
});
div {
margin: 20px;
padding: 10px;
}
#large {
width: 600px;
height: 400px;
background-color: gray;
}
#small {
width: 120px;
height: 90px;
background-color: orange;
}
img {
width: 100%;
height: 100%;
transition: transform .3s ease-out;
transform-origin: 0 129px;
}
img.big {
transform: scaleX(5) scaleY(4.4);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="large">
</div>
<div id="small">
<img src="https://ak.picdn.net/assets/cms/5bb580387901a83212e3028ab5a2fa8fb1153d7b-img_offset_2x.jpg" />
</div>
Note that :
you will need to add vendor prefixes to the transition, transform and transform-origin properties depending on the browsers you need to support.
this technique relies on the fact you are using hard values (in pixels). It would be possible to make this responsive (using percent values for widths, margins and paddings) but it will need more calculations.
i made a responsive solution ( so i think ) using JQ . check it out below or in jsFiddle
first i cached all the necessary selectors for cleaner and concise code .
the -20 is because of the div { margin-top:20px}`
there i calculated the TOP offset of both divs in relation to the document, then got the width and height of the small div
in the click function first i got the image's top offset so i could compare that with the #small's offset .
so if the image's distance to top is smaller than the #small's distance to top, it means that the img is in the #large div and so i move it using transform:translate giving it an Y-axis value equal to the TOP offset of the #small Div, so the img offset.top ( iOffset ) will become equal to the #small offset.top ( sOffset )
also adding width and height of the #small div to the image
else ( if iOffset is = or bigger than sOffset ) then it means that the image is not in the large div, so i need to translate it back to the offset of the #large div and add width:100% and height:100%
hope i got it right and explained correctly.
let me know if it helps
var Large = $("#large"),
Small = $("#small"),
lOffset = $(Large).offset().top - 20 + 'px',
sOffset = $(Small).offset().top - 20 + 'px',
sWidth = $(Small).width(),
sHeight = $(Small).height()
$(document).on("click", "img", function() {
var iOffset = $(this).offset().top + 'px'
if (iOffset < sOffset) {
$(this).css('transform', 'translate(0,' + sOffset + ')')
.width(sWidth).height(sHeight)
} else {
$(this).css('transform', 'translate(0,' + lOffset + ')')
.width("100%").height("100%")
}
})
div {
margin: 20px;
padding: 10px;
}
#large {
width: 600px;
height: 400px;
background-color: gray;
}
#small {
width: 120px;
height: 90px;
background-color: orange;
}
img {
width: 100%;
height: 100%;
transition: 5s;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="large">
<img src="https://ak.picdn.net/assets/cms/5bb580387901a83212e3028ab5a2fa8fb1153d7b-img_offset_2x.jpg" />
</div>
<div id="small">
</div>
You need to compute the current dimensions of the image, the target dimensions, and calculate the needed transform.
To make it easier, I will calculate the transform needed to make the new element (the cloned one) look like it is still at the current position.
Later, a standard animation (that just resets scale and position) will do the trick.
I avoided using jQuery so the solution is easier to port
function func (target) {
var image = document.getElementById('image');
var current = image.parentNode;
var rectImage = current.getBoundingClientRect();
var rectTarget = target.getBoundingClientRect();
evalRect (rectImage);
evalRect (rectTarget);
var scaleX = rectImage.width / rectTarget.width;
var scaleY = rectImage.height / rectTarget.height;
var translateX = rectImage.centerX - rectTarget.centerX;
var translateY = rectImage.centerY - rectTarget.centerY;
var dup = image.cloneNode();
var scale = 'scale(' + scaleX + ', ' + scaleY + ') ';
var translate = 'translate(' + translateX + 'px, ' + translateY + 'px) ';
target.appendChild(dup);
dup.style.transform = translate + scale;
current.removeChild(image);
}
function evalRect (rect) {
rect.centerX = rect.left + rect.width * 0.5;
rect.centerY = rect.top + rect.height * 0.5;
}
.container {
border: solid 1px black;
position: relative;
display: inline-block;
}
#container1 {
width: 200px;
height: 100px;
}
#container2 {
width: 400px;
height: 200px;
}
#container3 {
width: 200px;
height: 200px;
}
#image {
background: linear-gradient(45deg, yellow, tomato);
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
animation: adjust 1s forwards;
}
#keyframes adjust {
to {transform: translate(0px, 0px);}
}
<div id="container1" class="container" onclick="func(this)">click me
<div id="image"></div>
</div>
<div id="container2" class="container" onclick="func(this)">click me</div>
<div id="container3" class="container" onclick="func(this)">click me</div>
appendto do not accept animations, but this question maybe helpful for you
appendTo() animation
Just add a transition and change the size and position to match the target. On the transitionend event, append the image to the target element.
// when transition completes
$('img').on('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend', function(){
// place in container
$('#target').append($('img'));
// set to corner of container
$('img').css({
top: '0',
left: '0'
});
});
// position in corner of target and make size the same
$('img').css({
position: 'absolute',
top: $('#target').offset().top + 'px',
left: $('#target').offset().left + 'px',
height: $('#target').css('height'),
width: $('#target').css('width')
});
#target {
height: 150px;
width: 150px;
border: 1px solid grey;
position: absolute;
top: 350px;
left: 5px;
z-index: 1;
}
img {
position: absolute;
top: 0;
left: 5px;
transition: all 1s;
height: 300px;
width: 300px;
z-index: 5;
}
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<img src="https://placeholdit.imgix.net/~text?txtsize=33&txt=300%C3%97300&w=300&h=300" />
<div id="target">
</div>
This should be simple but I guess no jQuery makes it a bit difficult.
I want to repeat a process where a div goes 100px to the right (with animation) and then 100px to the left (so i want a continuous movement).
There seems to be plenty of jQuery answers to this question yet no pure javascript solution. I'm probably missing something obvious here yet I can't find it.
Here is the code:
var left = 0;
var id = setInterval(function(){goRight()}, 10);
var ed = setInterval(function(){goLeft()}, 10);
function goRight(){
var redpixel = document.getElementById("redpixel");
left++;
redpixel.style.left = left + "px";
if (left>100) {
clearInterval(id)
goLeft();
}
}
function goLeft(){
var redpixel = document.getElementById("redpixel");
left-=1;
redpixel.style.left = left + "px";
if (left<100) {
clearInterval(ed);
goRight()
}
}
HTML:
<button onclick="goRight()">Go Right</button>
<div id="redpixel"></div>
CSS:
.container {
width: 480px;
height: 800px;
border: 1px solid black;
}
#redpixel {
position: absolute;
top: 200px;
left: 0;
background: red;
width: 25px;
height: 25px;
}
Last comments:
The animation starts without me calling any function (without using the button), how is that possible?
The animation works but stops when it hits the first 100px.
(Additional question) - if i put the var redpixel out of the function it doesn't work at all, why?
All help appreciated, thanks!
The problem with your code is that you set left and right animations at the same time, and the left one is cleared immediately because left<100. Fixed code:
var left = 0,
id = setInterval(goRight, 10);
ed;
function goRight() {
var redpixel = document.getElementById("redpixel");
left++;
redpixel.style.left = left + "px";
if (left > 100) {
clearInterval(id);
ed = setInterval(goLeft, 10);
}
}
function goLeft() {
var redpixel = document.getElementById("redpixel");
left -= 1;
redpixel.style.left = left + "px";
if (left < 1) {
clearInterval(ed);
id = setInterval(goRight, 10);
}
}
#redpixel {
position: absolute;
top: 50px;
left: 0;
background: red;
width: 25px;
height: 25px;
}
<div id="redpixel"></div>
One more point, is as demonstrated by Adjit it really makes sense to look at CSS approach as simpler and more effective.
You don't need any JavaScript at all actually, and it is quite simple to do with CSS3.
Just need to set up keyframes and animation like so: (obviously including the necessary browser compatibility)
#box {
height: 100px;
width: 100px;
background: red;
position: relative;
animation: waver 2s infinite;
-webkit-animation: waver 2s infinite;
}
#keyframes waver {
0% {left: 0px;}
50% {left: 100px;}
100% {left: 0px;}
}
#-webkit-keyframes waver {
0% {left: 0px;}
50% {left: 100px;}
100% {left: 0px;}
}
See this fiddle for an example: http://jsfiddle.net/bwsd3eoy/