How to get smooth transitions in pure JavaScript and CSS? - javascript

I have div elements with a black background-color that get and loose the class animated that has an css definition for an animated colored background. The animation is working smooth. But the change from the black to the animated state and back are not. I tried some transition rules but I can not figure out how to get a smooth change.
Here is my minimal example:
let randomNumber;
let boxes = document.querySelectorAll(".dark");
let randomNumbers = [];
let milliseconds = 2000;
setInterval(function() {
randomNumber = Math.floor(Math.random() * boxes.length);
randomNumbers.push(randomNumber);
boxes[randomNumber].className = boxes[randomNumber].className.replace(/(?:^|\s)dark(?!\S)/g, " animated");
setTimeout(function() {
boxes[randomNumbers[0]].className = boxes[randomNumbers[0]].className.replace(/(?:^|\s)animated(?!\S)/g, " dark");
randomNumbers.shift();
}, boxes.length * milliseconds);
}, milliseconds);
#keyframes animated_background_color {
0% {
background-color: #e66000;
}
25% {
background-color: #ff9500;
}
50% {
background-color: #ffcb00;
}
75% {
background-color: #ff9500;
}
100% {
background-color: #e66000;
}
}
.box {
height: 20px;
margin-bottom: 4px;
width: 20px;
}
.dark {
background-color: black;
}
.animated {
animation-name: animated_background_color;
animation-duration: 3s;
animation-timing-function: linear;
animation-iteration-count: infinite;
background-color: #e66000;
}
<!DOCTYPE html>
<html>
<head>
<title>Animation</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>
<body>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
</body>
</html>

Your starting and ending colors are not black, that's one reason why you see a shift. replace your 0% and 100% values by background-color: black;.
Once this problem is fixed, you will have a problem with your milliseconds variable because it's not a divider of your animation time (here 5*2000ms, which means the .animated class remove the class at 10s when your animation cycle is 3s)
Bonus: I have no idea why I cleaned and modified your code but I did it. (I'm tired and it was ugly)
const DARK_SELECTOR = ".dark";
const DARK_CLASS = "dark";
const ANIMATED_CLASS = "animated";
const ANIMATION_CYCLE_TIME = 2000;
const TOTAL_ANIMATION_TIME = 3 * ANIMATION_CYCLE_TIME;
const TIME_BETWEEN_ANIMATIONS = 1.5 * ANIMATION_CYCLE_TIME;
function animateRandomBox(animationTime) {
const darkBoxes = document.querySelectorAll(DARK_SELECTOR);
const numberOfDarkBoxes = darkBoxes.length;
if (numberOfDarkBoxes === 0) {
return;
}
const randomBoxNumber = Math.floor(Math.random() * numberOfDarkBoxes);
const randomBoxClass = darkBoxes[randomBoxNumber].classList;
randomBoxClass.remove('dark');
randomBoxClass.add('animated');
setTimeout(() => {
randomBoxClass.add('dark');
randomBoxClass.remove('animated');
}, animationTime);
}
setInterval(() => animateRandomBox(TOTAL_ANIMATION_TIME), TIME_BETWEEN_ANIMATIONS);
#keyframes animated_background_color {
0% {
background-color: #000;
}
25% {
background-color: #ff9500;
}
50% {
background-color: #ffcb00;
}
75% {
background-color: #ff9500;
}
100% {
background-color: #000;
}
}
body {
display: grid;
grid-auto-rows: min-content;
row-gap: 0.25rem;
}
.box {
height: 1rem;
width: 1rem;
border-radius: 0.5rem;
}
.dark {
background-color: black;
}
.animated {
animation-name: animated_background_color;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
<!DOCTYPE html>
<html>
<head>
<title>Animation</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>
<body>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
</body>
</html>

According to the comment of devdgehog, I decided to add more keyframes. Now I switch from the dark state to the animated state and back again with the first and last keyframe setting the dark background and the other keyframes switching from orange to bright orange to yellow to bright orange to orange three times in a row.
const DARK_SELECTOR = ".dark";
const DARK_CLASS = "dark";
const ANIMATED_CLASS = "animated";
const ANIMATION_CYCLE_TIME = 6000;
function animateRandomBox(animationTime) {
const darkBoxes = document.querySelectorAll(DARK_SELECTOR);
const numberOfDarkBoxes = darkBoxes.length;
if (numberOfDarkBoxes === 0) {
return;
}
const randomBoxNumber = Math.floor(Math.random() * numberOfDarkBoxes);
const randomBoxClass = darkBoxes[randomBoxNumber].classList;
randomBoxClass.remove('dark');
randomBoxClass.add('animated');
setTimeout(() => {
randomBoxClass.add('dark');
randomBoxClass.remove('animated');
}, animationTime);
}
setInterval(() => animateRandomBox(ANIMATION_CYCLE_TIME), ANIMATION_CYCLE_TIME);
#keyframes animated_background_color {
0% {
background-color: #000;
}
12% {
background-color: #ff9500;
}
25% {
background-color: #ffcb00;
}
37% {
background-color: #ff9500;
}
50% {
background-color: #ffcb00;
}
62% {
background-color: #ff9500;
}
75% {
background-color: #ffcb00;
}
87% {
background-color: #ff9500;
}
100% {
background-color: #000;
}
}
body {
display: grid;
grid-auto-rows: min-content;
row-gap: 0.25rem;
}
.box {
height: 1rem;
width: 1rem;
border-radius: 0.5rem;
}
.dark {
background-color: black;
}
.animated {
animation-name: animated_background_color;
animation-duration: 6s;
animation-timing-function: linear;
}
<!DOCTYPE html>
<html>
<head>
<title>Animation</title>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
</head>
<body>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
<div class="box dark"></div>
</body>
</html>

Related

How can I make successive movements with the same div?

hello I have the following problem, I want to make a series of random movements with the divs and using translate I managed to do only one because when I want to move that element again it returns to its initial position, my question is how can I maintain the position to be able to continue moving it and exchanging positions with other divs?
CSS:
body{
padding: 5rem ;
}
.elem{
width: 100px;
height: 100px;
}
#elem-1{
background-color: aqua;
}
#elem-2{
background-color: red;
}
#elem-3{
background-color: green;
}
#elem-4{
background-color: blue;
}
#elem-5{
background-color: violet;
}
#elem-6{
background-color: yellowgreen;
}
#elem-7{
background-color: gray;
}
#elem-0{
background-color: fuchsia;
}
.contenedor{
width: 400px;
height: 200px;
/* display: grid;
grid-template-columns: repeat(4,1fr); */
display: flex;
align-items: center;
justify-content: center;
flex-direction: row;
flex-wrap: wrap;
}
.move-right{
animation-duration: 4s;
animation-name: moving-x-right;
animation-fill-mode: forwards;
}
.move-left{
animation-duration: 4s;
animation-name: moving-x-left;
animation-fill-mode: forwards;
}
.move-down{
animation-duration: 2s;
animation-name: moving-y-down;
animation-fill-mode: forwards;
}
.move-up{
animation-duration: 2s;
animation-name: moving-y-up;
animation-fill-mode: forwards;
}
#keyframes moving-x-right {
from {
}
to {
transform: translateX(100px);
}
}
#keyframes moving-x-left {
from {
}
to {
transform: translateX(-100px);
}
}
#keyframes moving-y-up {
from {
}
to {
transform: translateY(-100px);
}
}
#keyframes moving-y-down {
from {
}
to {
transform: translateY(100px);
}
}
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div class="contenedor">
<div class="elem" id="elem-0">1</div>
<div class="elem" id="elem-1">2</div>
<div class="elem" id="elem-2">3</div>
<div class="elem" id="elem-3">4</div>
<div class="elem" id="elem-4">5</div>
<div class="elem" id="elem-5">6</div>
<div class="elem" id="elem-6">7</div>
<div class="elem" id="elem-7">8</div>
</div>
<script src="/scripts.js"></script>
</body>
</html>
and JS:
window.onload = moveGridElement
function moveGridElement() {
const elem1 = document.querySelector("#elem-0")
const elem2 = document.querySelector("#elem-1")
const elem3 = document.querySelector("#elem-2")
const elem4 = document.querySelector("#elem-3")
const elem5 = document.querySelector("#elem-4")
const elem6 = document.querySelector("#elem-5")
const elem7 = document.querySelector("#elem-6")
const elem8 = document.querySelector("#elem-7")
elem1.classList.add("move-right")
elem2.classList.add("move-left")
setTimeout(() => {
elem4.classList.add("move-down")
elem8.classList.add("move-up")
}, 1000);
setTimeout(() => {
elem1.classList.add("move-down")
elem6.classList.add("move-up")
}, 3000);
I need that when a div changes places it maintains that position to continue making movements and changing positions with other divs with HTML, CSS and JS only

how can I show or hide buttons slowly with a size animation?

I would like to add an animation to the buttons below.
When displaying the buttons:
the buttons should slowly increase in size until they are fully displayed.
When hiding:
they should slowly get smaller until they are out from the page.
How do i get this this with css?
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.btn {
transition: 1s;
/* Continue coding here */
}
</style>
</head>
<body>
<div class="container">
<button class="btn" id="q1" onclick="show()">B1</button>
<button class="btn" id="q2" hidden>B2</button>
<button class="btn" id="q3" hidden>B2</button>
</div>
</body>
</html>
<script>
function show() {
document.getElementById("q1").remove();
document.getElementById("q2").removeAttribute("hidden");
document.getElementById("q3").removeAttribute("hidden");
}
</script>
In order to animate the size, you need to set the beginning and end sizes. I would recommend using a class .hidden instead of the hidden attribute. The class will have a zero size, while the base class .btn has the styles for a non-hidden button. Then you just need to remove the class to trigger the transition.
function show() {
document.getElementById("q1").remove();
document.getElementById("q2").classList.remove("hidden");
document.getElementById("q3").classList.remove("hidden");
}
.btn {
transition: all 1s;
width: 4em;
height: 2.5em;
padding: 0.5em;
/* to hide the text when hidden */
overflow: hidden;
}
.btn.hidden {
width: 0;
height: 0;
padding: 0;
}
<div class="container">
<button class="btn" id="q1" onclick="show()">B1</button>
<button class="btn hidden" id="q2">B2</button>
<button class="btn hidden" id="q3">B3</button>
</div>
Use a keyframe animation that is set in a function that is added or removed when the button is clicked.
example: https://jsfiddle.net/93ah2ej5/1/
(clicking one of the B2 buttons hides them and shows the B1 button)
q1 = document.getElementById("q1")
q2 = document.getElementById("q2")
q3 = document.getElementById("q3")
function show() {
q1.classList.add('hide');
setTimeout(function() {
document.getElementById("q1").hidden = true;
document.getElementById("q2").removeAttribute("hidden");
document.getElementById("q3").removeAttribute("hidden");
q2.classList.remove('hide')
q3.classList.remove('hide')
q2.classList.add('show')
q3.classList.add('show')
}, 3000)
}
function hide() {
q2.classList.add('hide')
q3.classList.add('hide')
setTimeout(function() {
q2.hidden = 'true'
q3.hidden = 'true'
q1.hidden = false
q1.classList.add('show')
q1.classList.remove('hide')
}, 3000)
}
#keyframes show {
0% {
opacity: 0;
width: 10px;
height: 10px
}
100% {
opacity: 1;
width: 32px;
height: 21.5px;
}
}
.show {
animation-name: show;
animation-duration: 3s;
}
#keyframes hide {
0% {
opacity: 1;
width: 32px;
height: 21.5px;
}
100% {
opacity: 0;
width: 10px;
height: 10px
}
}
.hide {
animation-name: hide;
animation-duration: 3s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="container">
<button class="btn" id="q1" onclick="show()">B1</button>
<button class="btn" id="q2" hidden onclick='hide()'>B2</button>
<button class="btn" id="q3" hidden onclick='hide()'>B2</button>
</div>
</body>
</html>
Here is a way.
const button = document.querySelector(`.button`);
const showHide = document.querySelector(`.show-hide-button`);
let isHidden = true;
showHide.addEventListener(`click`, () =>{
if(isHidden === true)
{
setTimeout(()=>{
button.style.width = `50px`;
}, 100);
setTimeout(()=>{
button.style.display = `none`;
}, 1000);
}
else
{
setTimeout(()=>{
button.style.display = `block`;
}, 100);
setTimeout(()=>{
button.style.width = `150px`;
}, 150);
}
isHidden = !isHidden;
});
.button{
margin-top: 10px;
width: 150px;
display: block;
transition: 1s;
};
<div>
<button class="show-hide-button">ShowHide</button>
<button class="button">Button</button>
</div>
i would like to thank #tices , his/her answer has helped me a lot. but when i add design to "btn", the code doesn't work correctly. because the width and height are hard coded.
so how do i get the button to slowly increase or decrease without hard coding the width and height? I am looking forward to an answer.
q1 = document.getElementById("q1")
q2 = document.getElementById("q2")
q3 = document.getElementById("q3")
function show() {
q1.classList.add('hide');
setTimeout(function() {
document.getElementById("q1").hidden = true;
document.getElementById("q2").removeAttribute("hidden");
document.getElementById("q3").removeAttribute("hidden");
q2.classList.remove('hide')
q3.classList.remove('hide')
q2.classList.add('show')
q3.classList.add('show')
}, 3000)
}
function hide() {
q2.classList.add('hide')
q3.classList.add('hide')
setTimeout(function() {
q2.hidden = 'true'
q3.hidden = 'true'
q1.hidden = false
q1.classList.add('show')
q1.classList.remove('hide')
}, 3000)
}
.btn {
border-style: solid;
border-width: 1px;
background-color: inherit;
padding: 10px 18px;
font-size: 1.125rem;
font-weight: 700;
cursor: pointer;
margin-top: 0;
margin-bottom: 0;
}
#keyframes show {
0% {
opacity: 0;
width: 10px;
height: 10px
}
100% {
opacity: 1;
width: 32px;
height: 21.5px;
}
}
.show {
animation-name: show;
animation-duration: 3s;
}
#keyframes hide {
0% {
opacity: 1;
width: 32px;
height: 21.5px;
}
100% {
opacity: 0;
width: 10px;
height: 10px
}
}
.hide {
animation-name: hide;
animation-duration: 3s;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="container">
<button class="btn" id="q1" onclick="show()">B1</button>
<button class="btn" id="q2" hidden onclick='hide()'>B2</button>
<button class="btn" id="q3" hidden onclick='hide()'>B2</button>
</div>
</body>
</html>

Why is the variable not working properly on the CSS?

I created --item-width as a var variable in JavaScript. I thought it would work properly on the CSS, but it's not working properly. What should I do? I'm still a beginner, so I think I did something wrong. Help me.
I am writing again because I was banished from writing. I look forward to your kind cooperation.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>marquee_text</title>
<link href="CSS/style.css" type="text/css" rel="stylesheet">
<script src="js/script.js" defer></script>
</head>
<body>
<div id="wrap">
<div class="marquee-text">
<div class="marquee-text__wrapper" data-controller="marquee">
<div class="marquee-text__item">
<strong>Marquee Text</strong>
<svg class="marquee-text__separator" height="19" width="19" viewBox="0 0 100 95.11">
<polygon points="50 0 65.45 31.31 100 36.33 75 60.7 80.9 95.11 50 78.86 19.1 95.11 25 60.7 0 36.33 34.55 31.31 50 0"/>
</svg>
<span>Marquee Text</span>
</div>
</div>
</div>
</div>
</body>
</html>
#charset "UTF-8";
:root {
--item-width: 0;
}
.marquee-text {
position: relative;
width: 100%;
display: flex;
align-items: center;
overflow: hidden;
white-space: nowrap;
height: 50px;
background-color: #222;
font-size: 17px;
color: #fff;
}
.marquee-text__wrapper {
display: flex;
align-items: center;
height: 100%;
}
.marquee-text__item {
padding: 0 10px;
}
.marquee-text__separator {
position: relative;
top: -1px;
margin: 0 10px;
font-size: 1.3em;
vertical-align: middle;
fill: currentColor;
}
.marquee-text a:hover {
opacity: 0;
}
#keyframes marquee-text-ani {
0% {
transform: translate3d(0, 0, 0);
}
100% {
/* This code is not working. */
transform: translate3d(-(var(--item-width))'px', 0, 0);
}
}
setTimeout(()=>{
this.move()
}, 200)
function move() {
const $marqueeTop = document.querySelector(".marquee-text__wrapper");
const $marqueeTopItem = document.querySelector(".marquee-text__wrapper>div");
const $root = document.querySelector(":root");
const itemWidth= $marqueeTopItem.clientWidth;
for (i = 0; i < 10; i++) {
let marqueeTopItem = $marqueeTopItem.cloneNode(!0);
$marqueeTop.appendChild(marqueeTopItem);
}
// This variable is not working in CSS.
$root.style.setProperty(`--item-width`, itemWidth);
$marqueeTop.style.animation = `marquee-text-ani 4s linear 1s forwards infinite`;
}
I changed the code like Terry gave me the comment, and it works well. Thank you.
transform: translate3d(calc((-1px) * var(--item-width)), 0, 0);

I want to pause/play CSS animation using one button with Javascript. The sun and sky colors should be controlled with the button

HTML CODE:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset = "utf-8">
<title>Keyframe Animations</title>
<link rel="stylesheet" href="SunLabcss.css" type="text/css"/>
<script src="scriptSun.js"></script>
</head>
<body>
<button id = "sunButton" onclick="sunPausePlayToggle()">PLAY/PAUSE</button
sunPausePlayToggle() is a function in JS which will control the animation .
<div id = "sunSky"
this is a div which i am using as a background sky
<div id = "sun"></div
the upper div is a sun which rise from right and dawn in the left
</div>
</body>
</html>
CSS code:
I am using keyframe animations to animate the sun and sky.
#keyframes risesky {
0% {
top: 100%;
left : 100%;
background-color: red;
}
50% {
left:50%;
top: 10%;
background-color: yellow;
}
100% {
background-color: orangered;
top: 100%;
left: 0%;
}
}
#keyframes sky {
0% , 100% {
background-color: #1c1341;
}
10% {
background-color: darkorange;
}
50% {
background-color: skyblue;
}
80% {
background-color: crimson;
}
}
#sunButton{
animation-play-state: running;
}
#sun {
position: relative;
border-radius: 50%;
width: 80px;
height: 80px;
animation: risesky 11s infinite;
}
#sunSky {
height: 500px;
overflow: hidden;
animation: sky 11s infinite both;
}
Javascript code:
here is the problem I am getting, I can only pause the animation in JS ,but can't play.
function sunPausePlayToggle(){
document.getElementById("sunSky").style.animationPlayState = "paused";
document.getElementById("sun").style.animationPlayState = "running";
}
Turn #sunButton = animation-play-state: "paused"; in css
And this is the js
function sunPausePlayToggle(){
let sunsky = document.getElementById("sunSky")
let sun = document.getElementById("sun")
const sky_sty = sunsky.style.animationPlayState === 'running';
const sun_sty = sun.style.animationPlayState === 'running';
sunsky.style.animationPlayState = sky_sty ? 'paused' : 'running';
sun.style.animationPlayState = sun_sty ? 'paused' : 'running';
}

How to change div width when clicked?

I'm trying to make it so that when i click the div, it either expands the full viewport width or returns to its original width. But its not working. I tried box.style.width but no change so I googled and got getComputedStyle(). so i was abe to console log the width but then i used setProperty on the width and it still didnt work.
const box = document.querySelector(".box");
const bsl = window.getComputedStyle(box);
let i = 0;
window.onload = () => {
console.log(bsl.getPropertyValue("width"), i, 77);
}
box.onclick = () => {
if (i % 2 === 0) {
bsl.setProperty("width", "100vw");
} else {
bsl.setProperty("width", "100px");
}
i++;
console.log(box.clientWidth, i);
}
* {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
}
.box {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: rebeccapurple;
animation: exc 1s linear forwards paused;
}
#keyframes exc {
from {
width: 100px;
}
to {
width: 100vw;
border-radius: 0%;
}
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="boxid" class="box"></div>
</body>
apparently there was a problem with your animation especially "puased"
check this out
const box = document.querySelector(".box");
let isExpand = false;
box.onclick = () => {
if (isExpand) {
box.style.width = "100px"
box.style.borderRadius = "50%"
isExpand = false
} else {
box.style.width = "100vw"
box.style.borderRadius = "0%"
isExpand = true
}
}
* {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
}
.box {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: rebeccapurple;
transition: width 1s linear, border-radius 1s linear;
}
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="boxid" class="box"></div>
</body>

Categories

Resources