This is an intro to a website I'm currently making. Everything is working as intended, except that when I click the proceed button, it kind of jitters down some pixels before disappearing. I tried a lot of stuff and couldn't figure out why. I'm kinda new to this stuff.
const button = document.querySelector(".btn")
const prompts = document.querySelectorAll(".prompt")
button.addEventListener("click", function() {
setTimeout(() => {
button.classList.add("btnfadeout");
}, 1200);
setTimeout(() => {
prompts.forEach(prompt => {
prompt.classList.add("fadeout");
})
}, 800)
})
@font-face {
font-family: 'InconsolataEB';
src: url(Inconsolata/static/Inconsolata-ExtraBold.ttf);
}
body {
background-color: #030603;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
color: #42d999;
font-family: 'InconsolataEB';
overflow: hidden;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
opacity: 0;
animation: fadeIn 1s ease-out forwards;
}
#typewriter1 {
display: inline-block;
transform: translateY(-10rem);
}
#typewriter2 {
display: inline-block;
transform: translateY(-10rem);
}
#prompt1 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 2s steps(20);
animation-delay: 1s;
animation-fill-mode: forwards;
}
#prompt2 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 2.5s steps(17);
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
.btn {
margin-top: 1.5rem;
padding: 2.8rem;
border: 2px solid #b6eed7;
background-color: transparent;
color: #42d999;
text-shadow: 0 0 8px #59e9ad;
font-family: 'InconsolataEB';
font-size: 3rem;
cursor: pointer;
opacity: 0;
transform: translateY(-2rem);
animation: buttonFadeIn 1s ease-out forwards 8s;
transition: 325ms;
}
.btn:hover {
color: #5eecb1;
text-shadow: 0 0 5px #6af3ba,
0 0 45px #6af3ba
}
.btn:active {
transition: 20ms;
color: #5eec88;
text-shadow: 0 0 5px #6af388,
0 0 45px #6af388;
border: 2px solid #b6eeb7;
}
.btnfadeout {
animation: fadeOut 1.5s forwards;
}
.fadeout {
animation: fadeOut 1.5s forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes buttonFadeOut {
0% {
opacity: 1;
transform: translateY(-4rem);
}
100% {
opacity: 0;
transform: translateY(-4rem);
}
}
@keyframes buttonFadeIn {
to {
opacity: 1;
transform: translateY(-4rem);
}
}
@keyframes typing {
from {
width: 0;
opacity: 1;
}
to {
width: 100%;
opacity: 1;
}
}
<div class="container">
<div id="typewriter1" class="prompt">
<p id="prompt1">An interface awaits.</p>
</div>
<div id="typewriter2" class="prompt">
<p id="prompt2">Will you proceed?</p>
</div>
<button class="btn">[ PROCEED ]</button>
</div>
This is an intro to a website I'm currently making. Everything is working as intended, except that when I click the proceed button, it kind of jitters down some pixels before disappearing. I tried a lot of stuff and couldn't figure out why. I'm kinda new to this stuff.
const button = document.querySelector(".btn")
const prompts = document.querySelectorAll(".prompt")
button.addEventListener("click", function() {
setTimeout(() => {
button.classList.add("btnfadeout");
}, 1200);
setTimeout(() => {
prompts.forEach(prompt => {
prompt.classList.add("fadeout");
})
}, 800)
})
@font-face {
font-family: 'InconsolataEB';
src: url(Inconsolata/static/Inconsolata-ExtraBold.ttf);
}
body {
background-color: #030603;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
color: #42d999;
font-family: 'InconsolataEB';
overflow: hidden;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
opacity: 0;
animation: fadeIn 1s ease-out forwards;
}
#typewriter1 {
display: inline-block;
transform: translateY(-10rem);
}
#typewriter2 {
display: inline-block;
transform: translateY(-10rem);
}
#prompt1 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 2s steps(20);
animation-delay: 1s;
animation-fill-mode: forwards;
}
#prompt2 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 2.5s steps(17);
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
.btn {
margin-top: 1.5rem;
padding: 2.8rem;
border: 2px solid #b6eed7;
background-color: transparent;
color: #42d999;
text-shadow: 0 0 8px #59e9ad;
font-family: 'InconsolataEB';
font-size: 3rem;
cursor: pointer;
opacity: 0;
transform: translateY(-2rem);
animation: buttonFadeIn 1s ease-out forwards 8s;
transition: 325ms;
}
.btn:hover {
color: #5eecb1;
text-shadow: 0 0 5px #6af3ba,
0 0 45px #6af3ba
}
.btn:active {
transition: 20ms;
color: #5eec88;
text-shadow: 0 0 5px #6af388,
0 0 45px #6af388;
border: 2px solid #b6eeb7;
}
.btnfadeout {
animation: fadeOut 1.5s forwards;
}
.fadeout {
animation: fadeOut 1.5s forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes buttonFadeOut {
0% {
opacity: 1;
transform: translateY(-4rem);
}
100% {
opacity: 0;
transform: translateY(-4rem);
}
}
@keyframes buttonFadeIn {
to {
opacity: 1;
transform: translateY(-4rem);
}
}
@keyframes typing {
from {
width: 0;
opacity: 1;
}
to {
width: 100%;
opacity: 1;
}
}
<div class="container">
<div id="typewriter1" class="prompt">
<p id="prompt1">An interface awaits.</p>
</div>
<div id="typewriter2" class="prompt">
<p id="prompt2">Will you proceed?</p>
</div>
<button class="btn">[ PROCEED ]</button>
</div>
I've tried modifying the animation, keeping the transform consistent across fade-ins and fade-outs of the button, and I think the problem comes from the animation-fill-mode property, but the button always teleports down, instead of just staying put.
Share Improve this question edited Feb 16 at 10:46 Quentin 944k132 gold badges1.3k silver badges1.4k bronze badges asked Feb 16 at 10:24 davemakescontentdavemakescontent 32 bronze badges New contributor davemakescontent is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.2 Answers
Reset to default 0The movement down is because of buttonFadeIn
adding transform: translateY(-4rem);
. Now you just have to include it in your new animation, so that there is no real delta created in between the translateY
added by the 2 classes/animations.
I see that you have already added it in buttonFadeOut
. Just use it btnFadeOut
:
.btnfadeout {
animation: buttonFadeOut 1.5s forwards;
}
const button = document.querySelector(".btn")
const prompts = document.querySelectorAll(".prompt")
button.addEventListener("click", function() {
setTimeout(() => {
button.classList.add("btnfadeout");
}, 1200);
setTimeout(() => {
prompts.forEach(prompt => {
prompt.classList.add("fadeout");
})
}, 800)
})
@font-face {
font-family: 'InconsolataEB';
src: url(Inconsolata/static/Inconsolata-ExtraBold.ttf);
}
body {
background-color: #030603;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
color: #42d999;
font-family: 'InconsolataEB';
overflow: hidden;
}
.container {
display: flex;
flex-direction: column;
align-items: center;
opacity: 0;
animation: fadeIn 1s ease-out forwards;
}
#typewriter1 {
display: inline-block;
transform: translateY(-10rem);
}
#typewriter2 {
display: inline-block;
transform: translateY(-10rem);
}
#prompt1 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 0.2s steps(20);
animation-delay: 1s;
animation-fill-mode: forwards;
}
#prompt2 {
font-size: 2rem;
text-align: center;
font-family: 'InconsolataEB';
text-shadow: 0 0 2px #59e9ad;
width: 100%;
margin: 1rem 0;
white-space: nowrap;
overflow: hidden;
opacity: 0;
animation: typing 0.5s steps(17);
animation-delay: 4.5s;
animation-fill-mode: forwards;
}
.btn {
margin-top: 1.5rem;
padding: 2.8rem;
border: 2px solid #b6eed7;
background-color: transparent;
color: #42d999;
text-shadow: 0 0 8px #59e9ad;
font-family: 'InconsolataEB';
font-size: 3rem;
cursor: pointer;
opacity: 0;
transform: translateY(-2rem);
animation: buttonFadeIn 1s ease-out forwards 8s;
transition: 325ms;
}
.btn:hover {
color: #5eecb1;
text-shadow: 0 0 5px #6af3ba,
0 0 45px #6af3ba
}
.btn:active {
transition: 20ms;
color: #5eec88;
text-shadow: 0 0 5px #6af388,
0 0 45px #6af388;
border: 2px solid #b6eeb7;
}
.btnfadeout {
animation: buttonFadeOut 1.5s forwards;
}
.fadeout {
animation: fadeOut 1.5s forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
@keyframes fadeOut {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes buttonFadeOut {
0% {
opacity: 1;
transform: translateY(-4rem);
}
100% {
opacity: 0;
transform: translateY(-4rem);
}
}
@keyframes buttonFadeIn {
to {
opacity: 1;
transform: translateY(-4rem);
}
}
@keyframes typing {
from {
width: 0;
opacity: 1;
}
to {
width: 100%;
opacity: 1;
}
}
<div class="container">
<div id="typewriter1" class="prompt">
<p id="prompt1">An interface awaits.</p>
</div>
<div id="typewriter2" class="prompt">
<p id="prompt2">Will you proceed?</p>
</div>
<button class="btn">[ PROCEED ]</button>
</div>
The problem
Your btnfadeout
animation is applying a fadeOut
animation, but it doesn’t include any transform
properties, while your buttonFadeIn
animation initially moves the button up (transform: translateY(-4rem)
). Because of this, when you remove the button, it jumps back to its original position (or a default one) before fading out.
How to fix this
Modify your .btnfadeout
class to explicitly include a transform
that matches the final state of buttonFadeIn
. This ensures the button doesn’t jump before disappearing.
Replace:
.btnfadeout {
animation: fadeOut 1.5s forwards;
}
With:
.btnfadeout {
animation: buttonFadeOut 1.5s forwards;
}