I am trying to make a slider, but i have run in to a problem: slideWidth variable (which is the width of the slide) is always the same, so when it gets to the second slide it doesn't want to go further, similar with the previous slide it slides to the empty space because of the fixed variable value. + It doesn't want to animate.
How to fix this?
Please check out the 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 = swWidth;
slider.style.width = sliderWidth + "px";
for (var i = 0; i < slide.length; i++) {
slide.item(i).style.width = " " + swWidth + "px";
}
function moveRight() {
slider.style.transform = "translateX(" + (-slideWidth) + "px)";
}
function moveLeft() {
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: translate 350ms cubic-bezier(.08, .13, 0, .81);
-o-transition: translate 350ms cubic-bezier(.08, .13, 0, .81);
transition: translate 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>
P.S. If you know the solution please write it in JavaScript not JQuery
Your problem is that you missed to calculate the translateX position of your slideWrapper : (the slideWidth var )
to fix it you have to check and assign a new calculated value instead of setting it always to the slider width .
Note that I've added calculation in both moveRight() and moveLeft()
See below working snippet : (using only js)
// 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>
Related
I'm doing an js assignment and the goals as mentioned in the fiddle below is to drag the main div, show when the div is centered and to translate it to it starting position.
goals:
After releasing ".draggable" it should animate back to its original position.
Currently I'm stuck with translating the div and understanding why the flow only works once then gets "frozen" and doesn't remove listeners.
I would love some clarifications on how should I approach the translate portion and can replicate this behavior as long as the client runs.
<html>
<head>
<style>
html,
body {
height: 100%;
margin: 0;
}
.draggable {
position: absolute;
left: 0;
top: 0;
z-index: 1;
width: 150px;
height: 150px;
cursor: grab;
}
.draggable-inner {
width: 100%;
height: 50%;
}
.draggable-inner.top {
background: #1ADECB;
}
.draggable-inner.bottom {
background: #1A8FDE;
}
.draggable.animate {
transition: 500ms transform ease;
}
.markers {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 0;
}
.marker {
background: yellow;
opacity: 0.2;
transition: 500ms opacity ease;
position: absolute;
}
.marker.visible {
background: #1ADE91;
opacity: 1;
}
.center-x-marker {
width: 10px;
height: 100%;
}
.center-y-marker {
width: 100%;
height: 10px;
}
</style>
</head>
<body>
<div class="draggable">
<div class="draggable-inner top"></div>
<div class="draggable-inner bottom"></div>
</div>
<div class="markers">
<div class="marker center-x-marker"></div>
<div class="marker center-y-marker"></div>
</div>
<script>
let isDragging = false;
const deltaToCenter = {
x: 0,
y: 0
};
const dragPosition = {
x: 0,
y: 0
};
const screenCenterPosition = {
x: 0,
y: 0
};
const draggable = document.querySelector('.draggable');
const markerX = document.querySelector('.center-x-marker');
const markerY = document.querySelector('.center-y-marker');
let {
width,
height
} = draggable.getBoundingClientRect();
const draggableCenter = {
x: width / 2,
y: height / 2
};
draggable.addEventListener('mousedown', initDrag);
function onTransitionEnd() {
draggable.classList.remove('animate');
hideMarkers();
}
function hideMarkers() {
markerX.classList.remove('visible');
markerY.classList.remove('visible');
}
function handleDrag(event) {
isDragging = true;
let pX = event.pageX;
let pY = event.pageY;
draggable.style.left = pX + "px";
draggable.style.top = pY + "px";
let dragObj = draggable.getBoundingClientRect();
if (dragObj.top === 145 && dragObj.bottom === 295){
markerX.classList.add('visible');
markerY.classList.add('visible');
}
}
function stopDrag() {
isDragging = false;
var bodyRect = document.body.getBoundingClientRect(),
elemRect = draggable.getBoundingClientRect();
draggable.classList.add('animate');
document.removeEventListener('mousemove', handleDrag);
draggable.addEventListener('webkitTransitionEnd', onTransitionEnd);
draggable.addEventListener('transitionend', onTransitionEnd);
draggable.style.transform = (`translate(0px, 0px)`);
}
function initDrag(event) {
isDragging = true;
dragPosition.x = event.pageX;
dragPosition.y = event.pageY;
screenCenterPosition.x = parseInt(document.body.offsetWidth / 2);
screenCenterPosition.y = parseInt(document.body.offsetHeight / 2);
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', handleDrag);
}
</script>
</body>
</html>
You main problem is that you are trying to reset the top left with transform.
// use left and top:
draggable.style.left = pX + "px";
draggable.style.top = pY + "px";
// reset:
draggable.style.left = 0 + "px";
draggable.style.top= 0 + "px";
// or use transform:
draggable.style.transform = "translate("+pX+"px, "+pY+"px)";
// reset:
draggable.style.transform = "translate(0px, 0px)";
Also I moved your event listeners out of your functions since you don't really need to remove them.
let isDragging = false;
const deltaToCenter = {
x: 0,
y: 0
};
const dragPosition = {
x: 0,
y: 0
};
const screenCenterPosition = {
x: 0,
y: 0
};
const draggable = document.querySelector('.draggable');
const markerX = document.querySelector('.center-x-marker');
const markerY = document.querySelector('.center-y-marker');
let {
width,
height
} = draggable.getBoundingClientRect();
const draggableCenter = {
x: width / 2,
y: height / 2
};
draggable.addEventListener('mousedown', initDrag);
document.addEventListener('mousemove', handleDrag);
document.addEventListener('mouseup', stopDrag);
draggable.addEventListener('transitionend', onTransitionEnd);
function initDrag(event) {
isDragging = true;
dragPosition.x = event.pageX;
dragPosition.y = event.pageY;
screenCenterPosition.x = parseInt(document.body.offsetWidth / 2);
screenCenterPosition.y = parseInt(document.body.offsetHeight / 2);
}
function handleDrag(event) {
if (isDragging) {
let pX = event.pageX;
let pY = event.pageY;
draggable.style.transform = 'translate('+pX+'px, '+pY+'px)';
let dragObj = draggable.getBoundingClientRect();
if (dragObj.top === 145 && dragObj.bottom === 295) {
markerX.classList.add('visible');
markerY.classList.add('visible');
}
}
}
function stopDrag() {
isDragging = false;
draggable.classList.add('animate');
draggable.style.transform = 'translate(0px, 0px)';
}
function onTransitionEnd() {
draggable.classList.remove('animate');
hideMarkers();
}
function hideMarkers() {
markerX.classList.remove('visible');
markerY.classList.remove('visible');
}
draggable.addEventListener('mousedown', initDrag);
draggable.addEventListener('transitionend', onTransitionEnd);
document.addEventListener('mouseup', stopDrag);
document.addEventListener('mousemove', handleDrag);
html,
body {
height: 100%;
margin: 0;
overflow: hidden;
}
.draggable {
position: absolute;
left: 0;
top: 0;
z-index: 1;
width: 150px;
height: 150px;
cursor: grab;
}
.draggable-inner {
width: 100%;
height: 50%;
}
.draggable-inner.top {
background: #1ADECB;
}
.draggable-inner.bottom {
background: #1A8FDE;
}
.draggable.animate {
transition: 500ms transform ease;
}
.markers {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 0;
}
.marker {
background: yellow;
opacity: 0.2;
transition: 500ms opacity ease;
position: absolute;
}
.marker.visible {
background: #1ADE91;
opacity: 1;
}
.center-x-marker {
width: 10px;
height: 100%;
}
.center-y-marker {
width: 100%;
height: 10px;
}
<div class="draggable">
<div class="draggable-inner top"></div>
<div class="draggable-inner bottom"></div>
</div>
<div class="markers">
<div class="marker center-x-marker"></div>
<div class="marker center-y-marker"></div>
</div>
var ele = document.getElementById("filler");
var deg = 0;
var myInterval = setInterval(function() {
deg = deg + 10;
if (deg > 360) {
clearInterval(myInterval);
}
ele.style.transform = `rotate(${deg}deg)`;
}, 500);
.filler-wrapper {
height: 100px;
width: 100px;
position: relative;
border-radius: 50%;
overflow: hidden;
background: linear-gradient(to left, red 50%, green 50%);
}
.filler {
border-radius: 0 100% 100% 0 / 50%;
display: block;
height: 100%;
margin-left: 50%;
transform-origin: left;
background: green;
transform: rotate(0deg)
}
<div class="filler-wrapper">
<div id="filler" class="filler"></div>
</div>
I have created this radial progress but this works for only 180. How can I make it to rotate 360 deg.
Here is an idea based on this previous answer where you can do this with only background:
var ele = document.getElementById("box");
var deg = -90;
var s = 1;
var myInterval = setInterval(function() {
if(deg >= 90 && s) {
ele.style.setProperty("--s", --s);
deg = -90;
}
deg = deg + 10;
ele.style.setProperty("--v", deg+'deg');
if(deg >= 90 && !s) {
clearInterval(myInterval);
}
}, 500);
#box {
width:100px;
height:100px;
border-radius:50%;
background:
linear-gradient(var(--v), green 50%,transparent 0) center/calc(var(--s)*100%),
linear-gradient(var(--v), red 50%, transparent 0) center/calc(100% - var(--s)*100%),
linear-gradient(to right, green 50%,red 0);
}
<div id="box" style="--v:-90eg;--s:1"></div>
<!-- first cycle : from -90deg to 90deg with s=1 -->
<!-- second cycle : from -90deg to 90deg with s=0 -->
Shortly this will be something trivial with conic-gradient():
var ele = document.getElementById("box");
var deg = 0;
var myInterval = setInterval(function() {
deg = deg + 10;
ele.style.setProperty("--v", deg+'deg');
if(deg >= 360 ) {
clearInterval(myInterval);
}
}, 500);
#box {
width:100px;
height:100px;
border-radius:50%;
background:
conic-gradient(red var(--v,0deg),green var(--v,0deg),green 360deg);
}
<div id="box" ></div>
The above should work only on Chrome
For JS
isCompleted = false;
progressCount = 10;
function updateProgress() {
progressCount = progressCount + 10;
const _count = progressCount * 1.8;
console.log(_count)
if (_count > 180) {
isCompleted = true;
}
if (this.isCompleted) {
return;
}
_rotateSpinner(_count);
}
var elCircleFullFill = document.getElementById("circleFullFill");
var elCircleHalfFill = document.getElementById("circleHalfFill");
var elCircleMaskFull = document.getElementById("circleMaskFull");
var elCircleFillFix = document.getElementById("circleFillFix");
function _rotateSpinner(__progressCount) {
const fillRotation = __progressCount;
const fixRotation = __progressCount * 2;
elCircleFullFill.style = `transform:rotate(${fillRotation}deg)`;
elCircleHalfFill.style = `transform:rotate(${fillRotation}deg)`;
elCircleMaskFull.style = `transform:rotate(${fillRotation}deg)`;
elCircleFillFix.style = `transform:rotate(${fixRotation}deg)`;
}
SCSS
.progress-radial {
width: 50px;
height: 50px;
background-color: #fff;
border-radius: 50%;
.circle {
.circle-mask,
.circle-fill {
width: 50px;
height: 50px;
position: absolute;
border-radius: 50%;
transition: -webkit-transform 1s;
transition: -ms-transform 1s;
transition: transform 1s;
-webkit-backface-visibility: hidden;
}
.circle-mask {
clip: rect(0px, 50px, 50px, 50px/2);
.circle-fill {
clip: rect(0px, 50px/2, 50px, 0px);
background-color: #0096FF;
}
}
}
}
HTML
<div class="progress-radial">
<div class="circle">
<div class="circle-mask" id="circleMaskFull">
<div class="circle-fill" id="circleFullFill"></div>
</div>
<div class="circle-mask">
<div class="circle-fill" id="circleHalfFill"></div>
<div class="circle-fill" id="circleFillFix"></div>
</div>
</div>
</div>
<button onclick="updateProgress()">Update Spinner</button>
I am using Skrollr librabry. In the start it works fine,but as I'm scrolling down,I am experiencing flickering and images do not load. The content of my website are just images. Works fine on firefox, but not on Chrome. Could you please help me. I am using approximately 190 images. Is that an issue?
I am using async calls to fetch the data,and every image is being loaded before the skrollr is rendered.
Here's my working example : https://jsfiddle.net/if_true/v1mLhutc/7/
html
<body>
<div id="fakeloader"></div>
<div style="transform: translate3d(0,0,0);"></div>
<div class="DESKScreen">
<div id="info" hidden="hidden">0</div>
<section id="slide">
<div class="bcg"></div>
</section>
</div>
</body>
CSS
*,:before,:after {
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box;
-webkit-backface-visibility:hidden;
backface-visibility: hidden;
}
#info{
position: fixed;
top: 20px;
left: 20px;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
padding: 20px;
z-index: 9999;
}
body {
margin: 0;
width: 100%;
height: 100%;
}
html{
width: 100%;
height: 100%;
}
section {
width: 100%;
max-width: 100%;
height: 100%;
position: fixed;
left: 0;
right: 0;
margin: auto;
}
#slide .bcg {
height: 100%;
width: 100%;
background-size: 100%;
background-position: center top;
background-attachment: fixed;
position: absolute;
transform:translateZ(0)
}
.img{
background-size: cover;
background-repeat: no-repeat;
background-position: center;
display: table;
margin: auto;
max-height: 100vh !important;
height: 100% !important;
}
.item {
width: 100%;
position: absolute;
opacity: 1;
}
`Js`
$(document).ready(function() {
DivImage("sup");
var s = skrollr.init({
render: function(data) {
console.log(data.curTop);
}
});
//Check the screen size.
(function() {
if (screen.width < 768) {
$("#fullpage").fullpage({
//scrollingSpeed: 0,
});
$(".DESKScreen").css("display", "none");
} else if (screen.width > 768) {
$(".MObileScreen").css("display", "none");
}
})();
//Fakeloader for the loadtime
function loader() {
$("#fakeloader").fakeLoader({
timeToHide: 4000,
bgColor: "#e74c3c",
spinner: "spinner2"
});
}
loader();
});
function DivImage(name) {
//console.log(name);
//a counter to set for div id
let counter = 0;
//create the urls based on a nr
var Images = makeUrls();
//first create the div and pass the counter to it
CreateDiv(Images);
}
function makeUrls() {
let base = "images/";
let rest = ".jpg";
let result = [];
for (let i = 0; i < 191; i++) {
let baseNr = 1 + i;
if (baseNr === 2000) {
console.log("base");
} else {
result.push(base + baseNr + rest);
}
}
return result;
}
function CreateDiv(images) {
// debugger;
var from = 0,
to = 0;
let result = [];
for (let i of images) {
var newDiv = $('<div class="img-div"></div>');
newDiv.css({
backgroundImage: `url(${i})`
});
newDiv.attr("data--" + from + "-top", "opacity: 0;");
from += 125;
newDiv.attr("data--" + from + "-top", "opacity: 0;");
from += 125;
newDiv.attr("data--" + from + "-top", "opacity: 1;");
newDiv.attr("data-anchor-target", "#slide");
newDiv.attr("data-skrollr-decks-speed", "300");
$("#slide").append($(newDiv));
}
}
I try to build a Slideshow in JS + CSS and it works pretty well except one visual glitch. The Transition to the last slides seems somehow broken.
But I couldn't figure out what the problem is. If I comment out the "offset" transition on the last slide, the error doesn't occure.
This is the codeine I am talking about: https://codepen.io/marianbreitmeyer/pen/paeYgZ
The Block of code I mentioned is this one:
const showNext = function() {
clicked = true;
for (i = 0; i <= slides.length-1; i++) {
if( parseInt(slides[i].style.zIndex) === slides.length) {
console.log(slides[i].innerHTML);
triggerAnimation(slides[i], 'offcanvas');
} else if (parseInt(slides[i].style.zIndex) === slides.length-1) {
//the line below triggers the problem
triggerAnimation(slides[i], 'offset');
}
}
};
Maybe someone with more experience could help me :)
Your code might be more simple:
const btn = document.getElementsByClassName('arrow')[0];
const slides = document.getElementsByClassName('slide');
slides[slides.length - 1].classList.add('offset', 'next');
btn.addEventListener("click", function(e) {
var o, n;
for (var i = 0; i < slides.length; i++) {
if (slides[i].classList.contains('offset')) {
slides[i].classList.remove('offset', 'next')
slides[i].classList.add('offcanvas');
o = (slides[i - 1] || slides[slides.length - 1]);
n = (slides[i - 2] || slides[slides.length + i - 2]);
}
if (slides[i].offsetLeft < -slides[i].offsetWidth) {
slides[i].classList.remove('offcanvas', 'next');
}
}
o.classList.add('offset');
n.classList.add('next');
}, false);
.container {
width: 100%;
height: 100vh;
background: brown;
position: relative;
}
body {
text-align: center;
font-size: 2rem;
}
.slide {
position: absolute;
top: 0;
left: 90%;
width: 100%;
height: 100%;
}
.slide:nth-child(1) {
background: pink;
}
.slide:nth-child(2) {
background: blue;
}
.slide:nth-child(3) {
background: green;
}
.slide:nth-child(4) {
background: grey;
}
.slide:nth-child(5) {
background: yellow;
}
.slide.next {z-index:1}
.slide.offset {
left: -10%;
z-index: 2;
transition: left .65s ease-in-out;
}
.slide.offcanvas {
left: -110%;
z-index: 2;
transition: left .65s ease-in-out;
}
.arrow {
position: absolute;
right: 5%;
top: 25px;
z-index: 9;
height: 50px;
width: 50px;
cursor: pointer;
}
.arrow:hover path {
transform: translate(16px, 0px);
}
path {
position: absolute;
top: 0;
left: 0;
transition: all .2s ease-in-out;
}
<div class="container">
<div class="slide">1 = pink</div>
<div class="slide">2 = blue</div>
<div class="slide">3 = green</div>
<div class="slide">4 = grey</div>
<div class="slide">5 = yellow</div>
<svg xmlns="http://www.w3.org/2000/svg" class="arrow"><path d="M19.443 5.17L30.138 15.5H-.095v1h30.233L19.443 26.829l.696.719L32.095 16 20.139 4.451z"/></svg>
</div>
How can one make a smooth smoke trail effect with Javascript, out of the code I attached? The trail should follow an object, but have the position the object had a moment ago. The code I attached does have some sort of trail effect, but it is not smooth. Can give the trail a position using something like this: position:trail = position:object, 5 ms ago?
var left = parseInt(document.getElementById("thingy").style.left);
setInterval(fly, 10);
function fly() {
if (left > 300) {
left = 300;
};
left++;
document.getElementById("thingy").style.left = left + "px";
}
setInterval(trail, 100);
function trail() {
document.getElementById("trail").style.left = left + "px";
}
<div id="thingy" style="position:absolute; top:100px; left: 0px; width: 100px; height: 100px; background-color:#000000;"></div>
<div id="trail" style="position:absolute; top:125px; left: 0px; width: 50px; height: 50px; background-color:#CCCCCC; z-index: -10;"></div>
If it is possible I would like to stay out of jQuery.
This solution clones the element each time it moves.
CSS3 transitions are used on the cloned nodes' background to simulate a smoke trail.
The code ensures there are never more than 100 cloned nodes.
var thingy= document.getElementById('thingy'),
left = thingy.offsetLeft,
shadows= [],
delta= 4;
setInterval(fly, 10);
function fly() {
var shadow= thingy.cloneNode();
shadow.classList.add('shadow');
shadow.style.backgroundColor= 'silver';
document.body.appendChild(shadow);
setTimeout(function() {
shadow.style.backgroundColor= 'white';
},100);
shadows.push(shadow);
if(shadows.length>100) {
shadows[0].parentNode.removeChild(shadows[0]);
shadows.shift();
}
if(left+delta > document.body.offsetWidth-thingy.offsetWidth || left < 0) {
delta= -delta;
}
left+= delta;
thingy.style.left = left + 'px';
}
body {
margin: 0;
padding: 0;
}
#thingy {
position: absolute;
top: 100px;
left: 0px;
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
}
.shadow {
transition: all 1s;
z-index: -1;
}
<div id="thingy"></div>
Update
For a "smokier" effect, you can use random values for the cloned nodes' width, height, transition, etc., like I've done in this Snippet:
var thingy= document.getElementById('thingy'),
tleft = thingy.offsetLeft,
ttop = thingy.offsetTop,
smokes= [],
deltaX= deltaY= 2;
setInterval(fly, 10);
function fly() {
if(Math.random()>0.5) {
var smoke= thingy.cloneNode();
smoke.classList.add('smoke');
smoke.style.background= 'gray';
smoke.style.opacity= 0.2;
smoke.style.transition= Math.random()+'s';
smoke.style.width= Math.random()*thingy.offsetWidth+'px';
smoke.style.height= Math.random()*thingy.offsetHeight+'px';
smoke.style.marginTop= smoke.offsetHeight+'px';
smoke.style.borderRadius= (Math.random()*25+25)+'%';
document.body.appendChild(smoke);
setTimeout(function() {
smoke.style.opacity= 0;
},100);
smokes.push(smoke);
if(smokes.length>20) {
smokes[0].parentNode.removeChild(smokes[0]);
smokes.shift();
}
}
if(tleft+deltaX > document.body.offsetWidth-thingy.offsetWidth || tleft < 0) {
deltaX= -deltaX;
}
if(ttop +deltaY > document.body.offsetHeight-thingy.offsetHeight || ttop < 0) {
deltaY= -deltaY;
}
tleft+= deltaX;
ttop += deltaY;
thingy.style.left = tleft + 'px';
thingy.style.top = ttop + 'px';
}
body {
margin: 0;
padding: 0;
background: black;
height: 100vh;
}
#thingy {
position: absolute;
top: 100px;
left: 0px;
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
}
.smoke {
z-index: -1;
}
<div id="thingy"></div>