I am trying to make a touchscreen auto image slider for a landing page and it's somewhat working as it should. However, the image slider sometimes shows white space after a certain amount of scrolls.
Here's the code:
const slides = document.getElementById("slides");
const allSlides = document.querySelectorAll(".slide");
const slidesLength = allSlides.length;
const slideWidth = allSlides[0].offsetWidth;
let index = 0;
let posX1;
let posX2;
let initialPosition;
let finalPosition;
var myTimer;
let canISlide = true;
const prev = document.getElementById("prev");
const next = document.getElementById("next");
const firstSlide = allSlides[0];
const lastSlide = allSlides[allSlides.length - 1];
const cloneFirstSlide = firstSlide.cloneNode(true);
const cloneLastSlide = lastSlide.cloneNode(true);
slides.appendChild(cloneFirstSlide);
slides.insertBefore(cloneLastSlide, firstSlide);
next.addEventListener("click", () => switchSlide("next"));
prev.addEventListener("click", () => switchSlide("prev"));
slides.addEventListener("transitionend", checkIndex);
slides.addEventListener("mouseown", dragStart);
slides.addEventListener("touchstart", dragStart);
slides.addEventListener("touchmove", dragMove);
slides.addEventListener("touchend", dragEnd);
function dragStart(e) {
e.preventDefault();
initialPosition = slides.offsetLeft;
if (e.type == "touchstart") {
posX1 = e.touches[0].clientX;
} else {
posX1 = e.clientX;
document.onmouseup = dragEnd;
document.onmousemove = dragMove;
}
}
function dragMove(e) {
if (e.type == "touchmove") {
posX2 = posX1 - e.touches[0].clientX;
posX1 = e.touches[0].clientX;
} else {
posX2 = posX1 - e.clientX;
posX1 = e.clientX;
}
slides.style.left = `${slides.offsetLeft - posX2}px`;
}
function dragEnd() {
/*
three possibilities:
1. next slide
2. prev slide
3. stay still
*/
finalPosition = slides.offsetLeft;
if (finalPosition - initialPosition < -496) {
switchSlide("next", "dragging");
} else if (finalPosition - initialPosition > 496) {
switchSlide("prev", "dragging");
} else {
slides.style.left = `${initialPosition}px`;
}
document.onmouseup = null;
document.onmousemove = null;
}
function switchSlide(arg, arg2) {
slides.classList.add("transition");
if (canISlide) {
if (!arg2) {
initialPosition = slides.offsetLeft;
}
if (arg == "next") {
slides.style.left = `${initialPosition - slideWidth}px`;
index++;
} else {
slides.style.left = `${initialPosition + slideWidth}px`;
index--;
}
}
canISlide = false;
}
function checkIndex() {
slides.classList.remove("transition");
if (index == -1) {
slides.style.left = `-${slidesLength * slideWidth}px`;
index = slidesLength - 1;
}
if (index == slidesLength) {
slides.style.left = `-${1 * slideWidth}px`;
index = 0;
}
canISlide = true;
}
* {
box-sizing: border-box;
}
.container body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
max-height: 100vh;
}
img {
width: 100%;
height: 100%;
}
.slider {
overflow: hidden;
position: relative;
width: 1080px;
height: 500px;
margin: auto;
}
.slides {
width: 10000px;
display: flex;
position: absolute;
top: 0;
left: -1080px;
cursor: pointer;
}
.slides.transition {
transition: all 0.3s ease-in-out;
}
.slide {
width: 1080px;
height: 500px;
animation: slide 16s infinite;
}
.prev,
.next {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: #f3f3f3;
font-size: 4rem;
}
.next {
right: 2rem;
}
.prev {
left: 2rem;
}
.next:hover, .prev:hover {
transition: 0.2s ease-in-out;
}
.active {
background-color: #ffffff;
-webkit-transition: all 0.4s ease-in-out;
-moz-transition: all 0.4s ease-in-out;
-ms-transition: all 0.4s ease-in-out;
-o-transition: all 0.4s ease-in-out;
transition: all 0.4s ease-in-out;
}
#keyframes slide{
0%{
transform: translateX(0);
}
25%{
transform: translateX(0);
}
30%{
transform: translateX(-100%);
}
50%{
transform: translateX(-100%);
}
55%{
transform: translateX(-200%);
}
75%{
transform: translateX(-200%);
}
80%{
transform: translateX(-300%);
}
100%{
transform: translateX(-300%);
}
}
<div class="container">
<div class="slider">
<div class="slides" id="slides">
<span class="slide">
<a href="#">
<img loading="lazy" src="img.png" alt="" width="100%"></a>
</span>
<span class="slide">
<a href="#">
<img loading="lazy" src="img2.png"></a>
</span>
<span class="slide">
<a href="#">
<img loading="lazy" src="img3-png" width="100%"></a>
</span>
</div>
<a href="#" id="prev" class="prev">❮
<i class="fas fa-caret-left"></i>
</a>
<a href="#" id="next" class="next">❯
<i class="fas fa-caret-right"></i>
</a>
</div>
Of course, I can also just leave out the automatic scrolling, but that isn't quite the goal. The goal is to have the image slider move automatically with a touch function, while working smoothly.
Thank you!
Related
This code I am trying to get working has the play buttons at the bottom inside their own container.
How the code works is, click on a button, and then a video should appear on the screen.
To test jsitor code, press run, not update.
https://jsitor.com/MIYiywN4HC / https://jsfiddle.net/kxhyLdr8/
<div class="playButtonContainer">
<button class="playa cover" type="button"></button>
<button class="playb cover" type="button"></button>
<button class="playc cover" type="button"></button>
<button class="playd cover" type="button"></button>
<button class="playe cover" type="button"></button>
<button class="playf cover" type="button"></button>
<button class="playg cover" type="button"></button>
<button class="playh cover" type="button"></button>
<button class="playi cover" type="button"></button>
</div>
What is weird about the above code is that after clicking on the buttons, no errors are appearing, when there should be.
By errors I mean, in the console log, I was referring to, usually errors will appear in there if something is broken. I am stuck trying to figure out how to get the broken code working.
For comparison, here is a demo code of it working with the play buttons not inside their own container.
The only difference between the demo code and the code I am working on is that in the code I am working on, the play buttons are inside their own container.
To test jsitor code, press run, not update.
https://jsitor.com/qTWoiuHp7z / https://jsfiddle.net/24xf0avp/
The only difference between the working and non working example is just the extra layer of HTML.
Nothing was touched in any other part of the code.
Would anyone be able to check and see if their able that code to work, the code with the play buttons in their own container?
No one has been able to figure out how that would be done, getting the play buttons to work inside their own container.
I was told by my instructor, the code needs to work with the play buttons inside their own container, separate from the HTML.
I have no idea how that would be done, and because there are no errors appearing in the code, that further confuses me.
I was told this:
The problem here is inside the body of the function showCover, which
adds the class active and calls the function show (which removes the
class hide) to and from the parent of the button , instead of the
.container element where it should be.
Could it be that you just need to extend your JS code so that it
reaches the inner html node?
on the button click event it probably captures the parent element
instead of the target element?
Binding of the click of the play button
So you should either wrap them together, put the play button in the
outer, and then go to the closest('.outer') then
querySelector('.video') or whatever you want to do. Or put an
attribute on the .playa button (eg data-player-id="play1") that you
can use to directly find from the click and then use this to call the
.container.play1 element
Here I created a very simple demo with one button.
<div class="playButtonContainer">
<button class="playa cover" type="button"></button>
</div>
Here is the working demo code with only 1 button.
https://jsitor.com/Qer_1Oi9Jv / https://jsfiddle.net/1bmrwuzn/
Here is the broken code with only 1 button.
https://jsitor.com/D38vgjs3g / https://jsfiddle.net/gt57k29h/
What is meant by broken is, is that it is not working or functioning the same way as the demo code I provided.
Smaller, reproducible example code:
const manageCover = (function makeManageCover() {
const config = {};
const body = document.body;
let currentPlayButton = {};
function show(el) {
el.classList.remove("hide");
}
function hide(el) {
el.classList.add("hide");
}
function hideAll(elements) {
elements.forEach(hide);
}
function resetBackground(backgroundSelector) {
const allBackgrounds = document.querySelectorAll(backgroundSelector);
function hideBackground(background) {
background.classList.add("bg1");
}
allBackgrounds.forEach(hideBackground);
}
function resetButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function hideButton(button) {
button.classList.add("isOpen");
}
allButtons.forEach(hideButton);
}
function resetPage() {
resetBackground("body");
resetButtons(".outer");
}
function markAsPlayed(played) {
played.classList.add("played");
}
function showCover(playButton) {
hideAll(config.containers);
resetPage();
markAsPlayed(playButton);
const cover = playButton.parentElement;
cover.classList.add("active");
show(cover);
}
function animationEndHandler(evt) {
const animationName = evt.animationName;
if (animationName === "initial-fade") {
body.classList.remove("initial-fade");
showCover(currentPlayButton);
}
}
function coverClickHandler(evt) {
currentPlayButton = evt.currentTarget;
body.classList.add("initial-fade");
}
function addClickToButtons(playButtons) {
playButtons.forEach(function playButtonHandler(playButton) {
playButton.addEventListener("click", coverClickHandler);
});
}
function addCoverHandler(coverSelector, handler) {
const cover = document.querySelector(coverSelector);
cover.addEventListener("click", handler);
}
function init(selectors) {
config.containers = document.querySelectorAll(selectors.container);
const playButtons = document.querySelectorAll(selectors.playButton);
addClickToButtons(playButtons);
body.addEventListener("animationend", animationEndHandler);
}
return {
addCoverHandler,
init
};
}());
const manageUI = (function makeManageUI() {
const body = document.body;
const players = [];
function findPlayers() {
const allCovers = document.querySelectorAll(".cover");
const allWrappers = document.querySelectorAll(".wrap");
allCovers.forEach(function addToPlayers(cover, index) {
players.push({
"cover": cover,
"wrapper": allWrappers[index]
});
});
}
// inline arrow function, direct return
function getWrapper(cover) {
const index = players.findIndex(
(player) => player.cover === cover
);
return players[index].wrapper;
}
function resetBackground(backgroundSelector) {
const allBackgrounds = document.querySelectorAll(backgroundSelector);
function showBackground(background) {
background.classList.remove("bg1");
}
allBackgrounds.forEach(showBackground);
}
function resetCurtains(curtainSelector) {
const allCurtains = document.querySelectorAll(curtainSelector);
function showCurtain(curtain) {
curtain.classList.remove("active");
}
allCurtains.forEach(showCurtain);
}
function showAllButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function showButton(button) {
button.classList.remove("hide");
}
allButtons.forEach(showButton);
}
function resetButtons(buttonSelector) {
const allButtons = document.querySelectorAll(buttonSelector);
function showButton(button) {
button.classList.remove("isOpen");
}
allButtons.forEach(showButton);
}
function animationEndHandler(evt) {
const animationName = evt.animationName;
console.log(animationName);
if (animationName === "fadingOut") {
fadeReset();
}
}
function fadeReset() {
body.classList.remove("fadingOut");
resetBackground("body");
resetCurtains(".with-curtain");
showAllButtons(".hide");
resetButtons(".outer");
}
function resetPage() {
body.classList.add("fadingOut");
}
function exitClickHandler() {
resetPage();
}
function addClickToExit(exitButtons) {
exitButtons.forEach(function addExitButtonHandler(exitButtons) {
exitButtons.addEventListener("click", exitClickHandler);
});
}
function addExitHandlers(callback) {
const resetVideo = document.querySelectorAll(".exit");
resetVideo.forEach(function resetVideoHandler(video) {
video.addEventListener("click", callback);
});
}
function init() {
findPlayers();
const exitButtons = document.querySelectorAll(".exit");
addClickToExit(exitButtons);
body.addEventListener("animationend", animationEndHandler);
}
return {
addExitHandlers,
getWrapper,
init
};
}());
const videoPlayer = (function makeVideoPlayer() {
const tag = document.createElement("script");
tag.src = "https://www.youtube.com/player_api";
const firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onPlayerReady(event) {
const player = event.target;
player.setVolume(100);
}
function onPlayerStateChange(event) {
const player = event.target;
return player;
}
function addPlayer(video, playerOptions) {
playerOptions.videoId = playerOptions.videoId || video.dataset.id;
playerOptions.events = playerOptions.events || {};
playerOptions.events.onReady = onPlayerReady;
playerOptions.events.onStateChange = onPlayerStateChange;
const player = new YT.Player(video, playerOptions);
return player;
}
return {
addPlayer
};
}());
const managePlayer = (function makeManagePlayer() {
const playerVars = {
autoplay: 0,
controls: 1,
disablekb: 1,
enablejsapi: 1,
fs: 0,
iv_load_policy: 3
};
const defaults = {
height: 360,
host: "https://www.youtube-nocookie.com",
playerVars,
width: 640
};
function show(el) {
el.classList.remove("hide");
}
function combinePlayerOptions(opts1 = {}, opts2 = {}) {
const combined = Object.assign({}, opts1, opts2);
Object.keys(opts1).forEach(function checkObjects(prop) {
if (typeof opts1[prop] === "object") {
combined[prop] = Object.assign({}, opts1[prop], opts2[prop]);
}
});
return combined;
}
function createPlayer(videoWrapper, playerOptions = {}) {
const video = videoWrapper.querySelector(".video");
const options = combinePlayerOptions(defaults, playerOptions);
return videoPlayer.addPlayer(video, options);
}
function playerAdder(wrapper, playerOptions) {
return function addPlayerCallback() {
initPlayer(wrapper, playerOptions);
};
}
function removePlayer(wrapper) {
wrapper.player.destroy();
delete wrapper.player;
console.log("removePlayer");
}
function removePlayerHandler(evt) {
const el = evt.target;
const container = el.closest(".container");
const wrapper = container.querySelector(".wrap");
if (wrapper.player) {
return removePlayer(wrapper);
}
}
function initPlayer(wrapper, playerOptions) {
show(wrapper);
const player = createPlayer(wrapper, playerOptions);
wrapper.player = player;
}
return {
adder: playerAdder,
removePlayerHandler
};
}());
const players = (function coverUIPlayerFacade() {
function addPlayer(coverSelector, playerOptions) {
const cover = document.querySelector(coverSelector);
const wrapper = manageUI.getWrapper(cover);
const callback = managePlayer.adder(wrapper, playerOptions);
manageCover.addCoverHandler(coverSelector, callback);
}
function init() {
manageCover.init({
container: ".container",
playButton: ".cover"
});
manageUI.init({});
manageUI.addExitHandlers(managePlayer.removePlayerHandler);
}
return {
add: addPlayer,
init
};
}());
players.init();
function onYouTubeIframeAPIReady() {
players.add(".playa", {});
}
html,
body {
height: 100%;
margin: 0;
padding: 0;
}
body {
background: #353198;
}
.initial-fade {
animation: initial-fade 500ms ease forwards;
}
#keyframes initial-fade {
to {
opacity: 0;
}
}
.initial-fade,
.fadingOut {
cursor: default;
}
.initial-fade .cover,
.initial-fade .cover * {
pointer-events: none !important;
}
.container {
display: flex;
justify-content: center;
position: relative;
/*z-index: 2;*/
}
.container.active {
flex: 1 0 0;
}
/*body.*/
.bg1 {
animation: fadeInBody 5s ease 0s forwards;
animation-delay: 0s;
opacity: 0;
}
#keyframes fadeInBody {
100% {
opacity: 1;
}
}
/*body.*/
.bg1 .with-curtain:before {
content: "";
position: fixed;
/*z-index: 1;*/
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: 165px 165px;
background-image:
}
.playButtonContainer {
display: flex;
flex-wrap: wrap;
min-height: 100%;
margin: auto;
justify-content: center;
align-content: center;
width: 290px;
gap: 10px;
animation: fadeInButtons 3s ease 0s forwards;
}
#keyframes fadeInButtons {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.outer.isOpen {
width: auto;
}
.fadingOut .isOpen {
animation: fadingOut 1s;
animation-delay: 11.3s;
}
#keyframes fadingOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.inner-container {
display: none;
}
/* when container is active hide the cssPlay and show the inner container*/
.container.active .cover {
display: none;
}
.container.active .inner-container {
display: flex;
}
.container.active .inner-container.curtain {
display: block;
}
.cover {
-webkit-appearance: none;
appearance: none;
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 90px;
height: 90px;
border-radius: 50%;
cursor: pointer;
border: 9px solid blue;
background: transparent;
filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
}
.cover::before {
content: "";
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 27px solid blue;
transform: translateX(4px);
}
.cover:hover {
box-shadow: 0 0 0 5px rgba(43, 179, 20, 0.5);
}
.cover:focus {
outline: 0;
box-shadow: 0 0 0 5px rgba(0, 255, 255, 0.5);
}
.played {
border-color: green;
}
.played::before {
border-left-color: green;
}
.curtain {
flex: 1 0 0;
margin: auto;
max-width: 642px;
/*box-shadow: inset 0 -2px 0px 0px #0a0a0a;*/
border: 20px solid black;
border-radius: 3.2px;
border-color: #000 #101010 #000 #101010;
position: relative;
}
.curtain::before {
content: '';
position: absolute;
top: -2px;
left: -2px;
right: -2px;
bottom: -2px;
background: radial-gradient(circle, transparent 0% 35%, #0a0a0a 35%);
}
.ratio-keeper {
position: relative;
height: 0;
padding-top: 56.25%;
margin: auto;
overflow: hidden;
border: 1px solid #333;
}
.video-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
iframe {
user-select: none;
}
.panel-left,
.panel-right {
position: absolute;
height: 100%;
width: calc(50% + 1px);
/* rounding error fix */
top: 0%;
transition: all ease 10s;
/*background-image: url("https://picsum.photos/600");
background-size: cover;
background-repeat: no-repeat;
background-position: center;*/
overflow: hidden;
}
.panel-left {
left: 0;
/*background-color: rgb(91, 96, 106);*/
}
.panel-right {
right: 0;
/*background-color: rgb(229, 211, 211);*/
}
.panel-left::before,
.panel-right::before {
content: "";
position: absolute;
height: 100%;
width: 200%;
top: 0;
left: 0;
background-size: auto;
background-repeat: no-repeat;
background-position: 0 0;
}
.panel-right::before {
left: -100%;
}
.container.active .curtain .panel-left {
animation: curtain1-open 8s forwards 520ms;
}
#keyframes curtain1-open {
to {
transform: translateX(calc(-100% - 1px));
}
}
.container.active .curtain .panel-right {
animation: curtain2-open 8s forwards 520ms;
}
#keyframes curtain2-open {
to {
transform: translateX(calc(100% + 1px));
}
}
.fadingOut .container.active .curtain .panel-left {
animation: curtain1-close 8s ease forwards;
transform: translateX(calc(-100% - 1px));
animation-delay: 3.3s;
}
#keyframes curtain1-close {
to {
transform: translateX(0);
}
}
.fadingOut .container.active .curtain .panel-right {
animation: curtain2-close 8s ease forwards;
transform: translateX(calc(100% + 1px));
animation-delay: 3.3s;
}
#keyframes curtain2-close {
to {
transform: translateX(0);
}
}
.exit {
position: absolute;
top: auto;
bottom: -47px;
margin: auto;
right: 0;
left: 0;
width: 47px;
height: 47px;
cursor: pointer;
background: black;
border-radius: 50%;
border: 5px solid red;
animation: fadeInExit 1s forwards;
opacity: 0;
pointer-events: none;
}
.exit::before,
.exit::after {
content: "";
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
width: 100%;
height: 5px;
background: red;
transform: rotate(45deg);
transition: all 1s ease;
}
.exit::after {
transform: rotate(-45deg);
}
#keyframes fadeInExit {
99% {
pointer-events: none;
}
100% {
pointer-events: initial;
opacity: 1;
}
}
.exit:hover::before,
.exit:hover::after,
.fadingOut .exit::before,
.fadingOut .exit::after {
background: green;
}
.fadingOut .exit {
animation: fadeOutExit 8s forwards;
pointer-events: none;
opacity: 1;
}
#keyframes fadeOutExit {
to {
opacity: 0;
}
}
.hide {
display: none;
}
<div class="outer">
<div class="container play1 with-curtain">
<div class="inner-container curtain curtain1">
<div class="ratio-keeper">
<div class="wrap">
<div class="video video-frame" data-id="CHahce95B1g"></div>
</div>
<div class="sliding-panels">
<div class="panel-left"></div>
<div class="panel-right"></div>
</div>
</div>
<button class="exit" type="button" title="Exit" aria-label="Close"></button>
</div>
</div>
</div>
<div class="playButtonContainer">
<button class="playa cover" type="button" aria-label="Open"></button>
</div>
I have the below code to begin an animation for an acronym that makes the code transform to a vertical form. I'd like to have it where it will type the rest of the acronym out next to the letters on the button click. However doing so adds far to much space between all the type I want them to basically line up how they do before the button is pressed you can see what it currently does here:
var a = 0;
var b = 0;
var c = 0;
var d = 0;
var e = 0;
var f = 0;
var balance = 'alance';
var execution = 'xecution';
var teamwork = 'eamwork';
var training = 'raining';
var experience = 'xperience';
var results = 'esults';
var speed = 50;
function typeWriter() {
while (a < balance.length) {
document.getElementById("balance").innerHTML += balance.charAt(a);
a++;
setTimeout(typeWriter, speed);
}
while (b < execution.length) {
document.getElementById("execution").innerHTML += execution.charAt(b);
b++;
setTimeout(typeWriter, speed);
}
while (c < teamwork.length) {
document.getElementById("teamwork").innerHTML += teamwork.charAt(c);
c++;
setTimeout(typeWriter, speed);
}
while (d < training.length) {
document.getElementById("training").innerHTML += training.charAt(d);
d++;
setTimeout(typeWriter, speed);
}
while (e < experience.length) {
document.getElementById("experience").innerHTML += experience.charAt(e);
e++;
setTimeout(typeWriter, speed);
}
while (f < results.length) {
document.getElementById("results").innerHTML += results.charAt(f);
f++;
setTimeout(typeWriter, speed);
}
}
function scroller() {
var move = document.querySelectorAll(".move");
var fade = document.querySelectorAll(".fade");
for (var i = 0; i < move.length; i++) {
var windowHeight = window.innerHeight;
var elementTop = move[i].getBoundingClientRect().top;
var elementVisible = 0;
if (elementTop < windowHeight - elementVisible) {
move[i].classList.add("active");
} else {
move[i].classList.remove("active");
}
}
for (var i = 0; i < fade.length; i++) {
var windowHeight = window.innerHeight;
var elementTop = fade[i].getBoundingClientRect().top;
var elementVisible = 0;
if (elementTop < windowHeight - elementVisible) {
fade[i].classList.add("active");
} else {
fade[i].classList.remove("active");
}
}
}
window.addEventListener("scroll", scroller);
.move {
font-size: 105px;
position: relative;
}
.move.active {
font-size: 105px;
position: relative;
animation: mover 5s ease 0s normal forwards;
}
.fade {
font-size: 105px;
position: relative;
}
.fade.active {
font-size: 105px;
position: relative;
animation: fader 2s ease 0s normal forwards;
}
.move.active span {
margin: 0px;
position: relative;
display: inline-block;
animation: rotate 5s ease 0s normal forwards;
}
#keyframes mover {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
transform: scale(1) translate(-20%, 300px) skew(0deg) rotate(90deg);
}
}
#keyframes rotate {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
transform: scale(1) translate(0px, 0px) skew(0deg) rotate(-90deg);
}
}
#keyframes fader {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
opacity: 0;
}
}
#keyframes typing {
0% {
width: 0%
}
100% {
width: 100%
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<CENTER>
<h2 class="fade">IT'S </h2>
<h2 class="move">
<span id="balance">B</span>
<span id="execution">E</span>
<span id="teamwork">T</span>
<span id="training">T</span>
<span id="experience">E</span>
<span id="results">R</span>
</h2>
<h2 class="fade">TOGETHER </h2>
</CENTER>
<button onclick="typeWriter()">Click me</button>
https://noahark.w3spaces.com/saved-from-Tryit-2022-04-29.html
Any and all help will be extremely appreciated.
In your particular example, the spacing is coming from the lengths of the words. When I undo the rotation caused by the animation, we can see this:
So, if you force the length of the word to be one character (regardless of how many characters are actually there), then you no longer have the spacing problem caused by the words' length.
.move span {
display: inline-block;
width: 1.5ch;
}
Although forcing the span's width works, it can feel a little naughty. We're now relying on nice overflow behaviour, and hopefully we don't need the true width of the element for anything else.
I found that I didn't have to force width if we start at the end rather than the beginning. By default (no transform applied), it is already arranged as a column of words exactly like what you want at the end of the animation.
Then, you apply the 90 degree rotation to get the horizontal "BETTER" text. The animation undoes the rotation, meaning you always get what you expect at the end.
const betterAcronym = document.querySelector('#better-acronym')
const revealButton = document.querySelector('#reveal-button')
const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms))
const typeElement = async (element) => {
const word = element.dataset['word']
const start = element.textContent.length
for (let c = start; c < word.length; ++c) {
element.textContent += word[c]
await wait(100)
}
}
revealButton.addEventListener('click', async () => {
betterAcronym.classList.add('revealed')
await wait(2750) // length of the animation plus some
Array.from(betterAcronym.children).forEach(typeElement)
})
.acronym {
font-size: 1.25rem;
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
transform: rotate(-90deg);
transform-origin: 0.5em 0.5em;
transition: transform 2.5s ease-in-out;
}
.acronym > li {
display: inline-block;
transform: rotate(90deg);
transform-origin: 0.5em 0.5em;
transition: transform 2.5s ease-in-out;
}
.acronym.revealed {
transform: rotate(0deg);
}
.acronym.revealed > li {
transform: rotate(0deg);
}
body {
overflow: hidden;
}
button {
font-size: 1.25rem;
}
<ol id="better-acronym" class="acronym">
<li data-word="balance">B</li>
<li data-word="execution">E</li>
<li data-word="teamwork">T</li>
<li data-word="training">T</li>
<li data-word="experience">E</li>
<li data-word="results">R</li>
</ol>
<button id="reveal-button">Reveal</button>
You just have to provide width: 73px to .move.active span. And after the animation ends adjust the parent height.
In the demo look for code comments. I've also fixed the typing effect code. View in full page mode.
const move = document.querySelector(".move");
const fade = document.querySelectorAll(".fade");
const words = ['balance', 'execution', 'teamwork', 'training', 'experience', 'results'];
let col = 1;
let row = 0;
const speed = 100;
function typeWriter() {
const e = document.getElementById(words[row]);
e.textContent += words[row][col];
col++;
if(col >= words[row].length){
col = 1;
row++;
}
if(row < words.length)
setTimeout(typeWriter, speed);
else
typeWriter = () => console.log('can not rerun the animation');
}
function scroller() {
var windowHeight = window.innerHeight;
var elementTop = move.getBoundingClientRect().top;
var elementVisible = 0;
if (elementTop < windowHeight - elementVisible) {
move.classList.add("active");
} else {
move.classList.remove("active");
}
for (var i = 0; i < fade.length; i++) {
var windowHeight = window.innerHeight;
var elementTop = fade[i].getBoundingClientRect().top;
var elementVisible = 0;
if (elementTop < windowHeight - elementVisible) {
fade[i].classList.add("active");
} else {
fade[i].classList.remove("active");
}
}
}
// adjust parent height after the animation ends
// change the calculation as per your requirements
move.onanimationend = (event)=>{
if(move === event.target) {
move.parentElement.style.height = move.parentElement.offsetHeight - move.offsetHeight + move.offsetWidth + - move.nextElementSibling.scrollHeight + 'px';
}
};
window.addEventListener("scroll", scroller);
center{ border: 1px dashed gray;}
.move {
font-size: 105px;
position: relative;
}
.move.active {
font-size: 105px;
position: relative;
animation: mover 5s ease 0s normal forwards;
/* we need exact width to adjust the parent's height */
width: fit-content;
}
.fade {
font-size: 105px;
position: relative;
}
.fade.active {
font-size: 105px;
position: relative;
animation: fader 2s ease 0s normal forwards;
}
.move.active span {
margin: 0px;
position: relative;
display: inline-block;
animation: rotate 5s ease 0s normal forwards;
/* specify width equal to one character in the font */
width: 73px;
}
#keyframes mover {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
transform: scale(1) translate(-20%, 300px) skew(0deg) rotate(90deg);
}
}
#keyframes rotate {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
transform: scale(1) translate(0px, 0px) skew(0deg) rotate(-90deg);
}
}
#keyframes fader {
0.0% {
transform: scale(1) translate(-0px, 0) skew(0deg);
}
100% {
opacity: 0;
}
}
#keyframes typing {
0% {
width: 0%
}
100% {
width: 100%
}
}
button {
position: fixed;
top: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<CENTER>
<h2 class="fade">IT'S </h2>
<h2 class="move">
<span id="balance">B</span>
<span id="execution">E</span>
<span id="teamwork">T</span>
<span id="training">T</span>
<span id="experience">E</span>
<span id="results">R</span>
</h2>
<h2 class="fade">TOGETHER </h2>
</CENTER>
<button onclick="typeWriter()">Click me</button>
Adjust the calculations as per your requirements.
I modified a code to upload an image with specific size and I'm here right now:
imageUploadPrepare();
function imageUploadPrepare() {
var $profileImgDiv = document.getElementById("profile-img-div"),
$profileImg = document.getElementById("profile-img"),
$changePhoto = document.getElementById("change-photo"),
$xPosition = document.getElementById("x-position"),
$yPosition = document.getElementById("y-position"),
$saveImg = document.getElementById("save-img"),
$loader = document.getElementById("loader"),
$cancelImg = document.getElementById("cancel-img"),
$profileImgInput = document
.getElementById("profile-img-input"),
$profileImgConfirm = document
.getElementById("profile-img-confirm"),
$error = document.getElementById("error");
var currentProfileImg = "",
profileImgDivW = getSizes($profileImgDiv).elW,
NewImgNatWidth = 0,
NewImgNatHeight = 0,
NewImgNatRatio = 0,
NewImgWidth = 0,
NewImgHeight = 0,
NewImgRatio = 0,
xCut = 0,
yCut = 0;
makeSquared($profileImgDiv);
$changePhoto.addEventListener("change", function() {
currentProfileImg = $profileImg.src;
showPreview(this, $profileImg);
$loader.style.width = "100%";
$profileImgInput.style.display = "none";
$profileImgConfirm.style.display = "flex";
$error.style.display = "none";
});
$xPosition.addEventListener("input", function() {
$profileImg.style.left = -this.value + "px";
xCut = this.value;
yCut = 0;
});
$yPosition.addEventListener("input", function() {
$profileImg.style.top = -this.value + "px";
yCut = this.value;
xCut = 0;
});
$saveImg.addEventListener("click", function() {
cropImg($profileImg);
resetAll(true);
});
$cancelImg.addEventListener("click", function() {
resetAll(false);
});
window.addEventListener("resize", function() {
makeSquared($profileImgDiv);
profileImgDivW = getSizes($profileImgDiv).elW;
});
function makeSquared(el) {
var elW = el.clientWidth;
el.style.height = (elW * 0.82) + "px";
}
function showPreview(input, el) {
var reader = new FileReader();
reader.readAsDataURL(input.files[0]);
if (input.files && input.files[0]) {
reader.onload = function(e) {
setTimeout(function() {
el.src = e.target.result;
}, 300);
var poll = setInterval(function() {
if (el.naturalWidth && el.src != currentProfileImg) {
clearInterval(poll);
setNewImgSizes(el);
setTimeout(function() {
$loader.style.width = "0%";
$profileImg.style.opacity = "1";
}, 250);
}
}, 100);
};
} else {
return;
}
}
function setNewImgSizes(el) {
if (getNatSizes(el).elR > 1) {
el.style.width = "auto";
el.style.height = "100%";
newImgWidth = getSizes(el).elW;
$xPosition.style.display = "block";
$yPosition.style.display = "none";
$xPosition.max = newImgWidth - profileImgDivW;
} else if (getNatSizes(el).elR < 1) {
el.style.width = "100%";
el.style.height = "auto";
newImgHeight = getSizes(el).elH;
$xPosition.style.display = "none";
$yPosition.style.display = "block";
$yPosition.max = newImgHeight - profileImgDivW;
} else if (getNatSizes(el).elR == 1) {
el.style.width = "100%";
el.style.height = "auto";
$xPosition.style.display = "none";
$yPosition.style.display = "none";
}
}
function getNatSizes(el) {
var elW = el.naturalWidth,
elH = el.naturalHeight,
elR = elW / elH;
return {
elW: elW,
elH: elH,
elR: elR
};
}
function getSizes(el) {
var elW = el.clientWidth,
elH = el.clientHeight,
elR = elW / elH;
return {
elW: elW,
elH: elH,
elR: elR
};
}
function cropImg(el) {
var natClientImgRatio = getNatSizes(el).elW / getSizes(el).elW;
(myCanvas = document.getElementById("croppedPhoto")),
(ctx = myCanvas.getContext("2d"));
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, 400, 487);
ctx.drawImage(
el,
xCut * natClientImgRatio,
yCut * natClientImgRatio,
profileImgDivW * natClientImgRatio,
profileImgDivW * natClientImgRatio,
0,
0,
400,
487
);
var newProfileImgUrl = myCanvas.toDataURL("image/jpeg");
$profileImg.src = newProfileImgUrl;
uploadImage(newProfileImgUrl);
function uploadImage(image) {
const dashboardProfileImage = document.getElementById('profile-img');
dashboardProfileImage.src = image;
downloadImage(image);
dashboardProfileImage.download = "output.png";
async function downloadImage(imageSrc) {
const image = await fetch(imageSrc)
const imageBlog = await image.blob()
const imageURL = URL.createObjectURL(imageBlog)
const link = document.createElement('a')
link.href = imageURL
link.download = 'image file name here'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
}
}
}
function resetAll(confirm) {
if (!confirm) {
$profileImg.src = currentProfileImg;
}
$changePhoto.value = "";
$profileImgInput.style.display = "block";
$profileImgConfirm.style.display = "none";
$profileImg.style.left = "0";
$profileImg.style.top = "0";
$profileImg.style.width = "100%";
$profileImg.style.height = "100%";
$xPosition.style.display = "none";
$yPosition.style.display = "none";
$xPosition.value = "0";
$yPosition.value = "0";
xCut = "0";
yCut = "0";
}
function checkMinSizes(el) {
if (getNatSizes(el).elW > 400 && getNatSizes(el).elH > 400) {
return true;
} else {
return false;
}
}
}
/*Profile image*/
.profile-photo-div{
position: relative;
margin: 0 auto 40px auto;
width: 320px;
height: auto;
overflow: hidden;
border-radius: 10px;
-webkit-transition: ease .3s;
-o-transition: ease .3s;
transition: ease .3s;
}
.profile-photo-div .profile-img-div{
display: block;
position: relative;
overflow: hidden;
}
.profile-photo-div #loader{
position: absolute;
top:0;
left: 0;
width: 0%;
height: 100%;
background-color: #00cccf;
z-index:10;
-webkit-transition: .3s;
-o-transition: .3s;
transition: .3s;
}
.profile-photo-div #profile-img{
position: absolute;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.profile-photo-div #change-photo{
display: none;
}
.profile-photo-div .profile-buttons-div{
position: relative;
display: block;
}
.profile-photo-div .button{
position: relative;
display: block;
font-family: helvetica, sans-serif;
font-size: 15px;
padding:15px;
text-align: center;
color: white;
background-color: #8f7cff;
cursor: pointer;
-webkit-transition: .5s;
-o-transition: .5s;
transition: .5s;
overflow: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.profile-photo-div .button:hover{
letter-spacing: 1px;
}
.profile-photo-div .button:after{
content: '';
position: absolute;
top: 50%;
left: 50%;
-webkit-transform: translate(-50%,-50%);
-ms-transform: translate(-50%,-50%);
transform: translate(-50%,-50%);
width: 10px;
height: 10px;
background-color: rgba(255,255,255,0.4);
border-radius: 50%;
opacity: 0;
-webkit-transition: .9s;
-o-transition: .9s;
transition: .9s;
}
.profile-photo-div .button:hover:after{
-webkit-transform: scale(50);
-ms-transform: scale(50);
transform: scale(50);
opacity: 1;
}
.profile-photo-div .button.half{
width: 50%;
}
.profile-photo-div .green{
background-color: #15ae6b;
}
.profile-photo-div .red{
background-color: #ae0000;
}
.profile-photo-div #x-position{
position: absolute;
bottom: 5px;
left: 50%;
-webkit-transform: translateX(-50%);
-ms-transform: translateX(-50%);
transform: translateX(-50%);
display: none;
}
.profile-photo-div #y-position{
position: absolute;
right: -50px;
top: 50%;
-webkit-transform: translateY(-50%) rotate(90deg);
-ms-transform: translateY(-50%) rotate(90deg);
transform: translateY(-50%) rotate(90deg);
display: none;
}
.profile-photo-div canvas{
position: absolute;
top: -2000px;
left: -2000px;
z-index: -1;
}
.profile-photo-div .profile-img-confirm{
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
width: 100%;
}
.profile-photo-div .error{
font-family: Helvetica, sans-serif;
font-size: 13px;
color: red;
text-align:center;
display: none;
}
/*end of profile image*/
<div class="profile-photo-div" id="profile-photo-div">
<div class="profile-img-div" id="profile-img-div" style="height: 150px;">
<div id="loader"></div>
<img id="profile-img" src="/dashboard/img/default-user.png">
<input id="x-position" type="range" name="x-position" value="0" min="0">
<input id="y-position" type="range" name="y-position" value="0" min="0">
</div>
<div class="profile-buttons-div">
<div class="profile-img-input" id="profile-img-input">
<label class="button" id="change-photo-label" for="change-photo">UPLOAD PHOTO</label>
<input id="change-photo" name="change-photo" type="file" style="display: none;" accept="image/*">
</div>
<div class="profile-img-confirm" id="profile-img-confirm" style="display: none;">
<div class="button half green" id="save-img">
<i class="fa fa-check" aria-hidden="true"></i>
</div>
<div class="button half red" id="cancel-img">
<i class="fa fa-remove" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="error" id="error">حداقل سایز مجاز 400×400</div>
<canvas id="croppedPhoto" width="400" height="400"></canvas>
</div>
The issue is so far the image is always cropped with fixed dimensions of 400 * 400 pixels !!
But I want to crop them at 454.138px * 306px and no matter how I modify the numbers I always get that 400* 400 fix size?!
How can fix this?
NOTE: Since Stack overflow snippet code is completely useless in order to test the code please use this Codepen:
https://codepen.io/pixy-dixy/pen/RwZGKBQ
I built a carousel for some images. I need my 'next' and 'previous' buttons to use the CSS animation that I assigned them in my javascript function for their event listeners.The animation will only play for one click, and when the buttons are clicked again to navigate the carousel the animation doesn't play. I need the buttons to grow and shrink for every click.
Here's the CSS:
.carousel-actions {
position: absolute;
display: flex;
justify-content: space-between;
width: 105%;
top: 30%;
}
.carousel-actions button {
padding: 30px 50px;
background-color: rgba(255, 255, 255, 0.329);
font-weight: 900;
cursor: pointer;
border-radius: 100px;
border: 0;
font-size: 60px;
color: black;
outline: none;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
Here's the HTML:
<div class="carousel-actions">
<button id="prev" aria-label="Previous Slide"><</button>
<button id="next" aria-label="Next Slide">></button>
</div>
Here's the JS:
const slides = document.querySelectorAll(".carousel-item");
const totalSlides = slides.length;
let slidePosition = 0;
console.log(totalSlides);
const next = document.getElementById("next");
const prev = document.getElementById("prev");
function hideAllSlides() {
for (const slide of slides) {
slide.classList.remove("carousel-item-visible") &&
slide.classList.add("carousel-item-hidden");
}
}
function nextSlide() {
hideAllSlides();
if (slidePosition === totalSlides - 1) {
slidePosition = 0;
} else {
slidePosition++;
}
slides[slidePosition].classList.add("carousel-item-visible");
next.style.animation = "grow 1s";
}
function prevSlide() {
hideAllSlides();
if (slidePosition === 0) {
slidePosition = totalSlides - 1;
} else {
slidePosition--;
}
slides[slidePosition].classList.add("carousel-item-visible");
prev.style.animation = "grow 1s";
}
next.addEventListener("click", nextSlide);
prev.addEventListener("click", prevSlide);
The problem is seen because once the system has played the animation it thinks 'well, I've played it'. Setting it to the same again does not make it play again.
To get round this you can unset the animation when it has finished.
In your code add an event listener for the animationend event.
Here's a simplified example:
const div = document.querySelector('div');
div.addEventListener('click', function() { div.style.animationName='grow';});
div.addEventListener('animationend', function() { div.style.animationName='';});
div {
width: 100px;
height: 100px;
background-color: blue;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
<div></div>
I'm working on a slideshow and it works, except for the animations. The animation for sliding out works fine but the animation for sliding in from the left does not. The left margin gets set to 0% but there is no animation, even though it is set to -100% at first.
Javascript:
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
]
function slideShow(startAt){
var holder = document.getElementById("currentImage");
var img = document.createElement("img");
img.src = images[startAt];
holder.appendChild(img);
nextPicture(startAt, img);
}
function nextPicture(current, currentElement){
var holder = document.getElementById("currentImage");
setTimeout(function(){
currentElement.className = "translateLeft";
current += 1;
var img = document.createElement("img");
img.src = images[current];
img.style.marginLeft = "-100%";
holder.appendChild(img);
img.className = "translateIn";
if (current == 5){
current = -1;
nextPicture(current, img);
} else {
nextPicture(current, img);
}
}, 5000)
}
slideShow(0);
CSS:
.translateLeft {
transition: 3s;
margin-left: 100% !important;
}
.translateIn {
transition: 3s;
margin-left: 0% !important;
}
Here is a solution for you.
https://jsfiddle.net/smaefwrp/2/
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
html,
body,
img {
position: absolute;
top:0;
left: 0;
margin: 0;
padding: 0;
height: 100%;
overflow-x: hidden;
}
#currentImage {
height: 100%;
width: 1920px;
}
.translateOrigin {
transition: none;
transform: translate3d(-100%, 0, 0) !important;
}
.translateLeft {
transition: transform 3s;
transform: translate3d(100%, 0, 0) !important;
}
.translateIn {
transition: transform 3s;
transform: translate3d(0, 0, 0) !important;
}
</style>
</head>
<body>
<div id="currentImage">
</div>
<div id="buttons">
</div>
<script type="text/javascript">
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
];
var imageEle = [];
var currImage = 0;
var holder = document.getElementById("currentImage");
function imagesPreload() {
for (var i = 0; i < images.length; i++) {
var img = new Image();
img.src = images[i];
img.className = "translateOrigin";
holder.appendChild(img);
imageEle.push(img);
}
}
imagesPreload();
document.onkeydown = function(event){
if(event.keyCode === 13) {
nextPicture();
}
};
function slideShow(startAt) {
var holder = document.getElementById("currentImage");
imageEle[currImage].className = "translateIn";
nextPicture();
}
function nextPicture() {
setTimeout(function () {
var img = imageEle[currImage];
img.addEventListener("transitionend", transitionEnd, false);
img.className = "translateLeft";
if (currImage == 5) {
currImage = 0;
} else {
currImage++;
}
imageEle[currImage].className = "translateIn";
/* Reset the image to original position */
function transitionEnd() {
img.className = "translateOrigin";
img.removeEventListener("transitionend", transitionEnd, false);
nextPicture();
}
}, 5000)
}
slideShow(currImage);
</script>
</body>
</html>
To create a nice slideshow I suggest to use css transform property rather than the margin. The idea is to create the placeholder element currentImage with relative position, and then create all images inside it with position set to absolute. Then by default all images are translated out of the placeholder element, and adding/removing classes show and hide you can place them inside the view and then outside of it, like this:
var images = [
'http://i.imgur.com/ByyUANz.png',
'http://i.imgur.com/S5FfOOB.png',
'http://i.imgur.com/EuefPdv.png',
'http://i.imgur.com/Ucvm4pJ.png',
'http://i.imgur.com/pK5WBHN.png',
'http://i.imgur.com/nuOLVpy.png'
];
// Get the holder
var holder = document.getElementById("currentImage");
// Create the images
images.forEach(function(url) {
var img = document.createElement("img");
img.src = url;
holder.appendChild(img);
});
// Image counter
var counter = 0;
// Slide show interval
var slideshow = setInterval(function() {
// When we reach the end of images we shut down the slide show
// or you can reset the counter to start over
if(counter === images.length) {
clearInterval(slideshow);
return;
}
// Get all images
var nodes = holder.getElementsByTagName("img");
// Hide previous image
if(nodes[counter - 1]) {
nodes[counter - 1].className = "hide";
}
// Show next image
nodes[counter].className = "show";
counter++;
}, 2500);
#currentImage {
background: gray;
width: 300px;
height: 300px;
margin: 0 auto;
position: relative;
overflow: hidden;
}
#currentImage img {
width: 100%;
position: absolute;
transform: translateX(-110%);
-webkit-transition: -webkit-transform 1.0s ease 0s;
-moz-transition: -moz-transform 1.0s ease 0s;
-o-transition: -o-transform 1.0s ease 0s;
transition: transform 1.0s ease 0s;
}
#currentImage img.show {
transform: translateX(0%);
}
#currentImage img.hide {
transform: translateX(110%);
}
<div id="currentImage">
</div>
You can try something like:
// HTML
<div id="currentImage">
<div class="window">
<div class="image-list">
<div>
<img src="http://i.imgur.com/ByyUANz.png" />
</div>
<div>
<img src="http://i.imgur.com/S5FfOOB.png" />
</div>
<div>
<img src="http://i.imgur.com/EuefPdv.png" />
</div>
<div>
<img src="http://i.imgur.com/Ucvm4pJ.png" />
</div>
<div>
<img src="http://i.imgur.com/pK5WBHN.png" />
</div>
<div>
<img src="http://i.imgur.com/nuOLVpy.png" />
</div>
</div>
</div>
</div>
And CSS
// CSS
img {
height: 50px;
width: 50px
}
.window {
position: absolute;
height: 50px;
width: 50px;
border: 2px solid red;
overflow: hidden
}
div {
display: inline-block
}
.image-list {
list-style-type: none;
display: inline-block;
padding-left: 0px;
margin: 0px;
width: 350px;
animation: slidingli 30s ;
}
#keyframes slidingli {
0% {
transform: translateX(0px)
}
16% {
transform: translateX(-50px)
}
32% {
transform: translateX(-100px)
}
48% {
transform: translateX(-150px)
}
64% {
transform: translateX(-200px)
}
80% {
transform: translateX(-250px)
}
100% {
transform: translateX(-300px)
}
}
Checkout this fiddle. Also there are many libraries out there which provide what need For example: http://fotorama.io/customize/autoplay/