Fix jumping in CSS text replacement animation - javascript

I have a textbox that I would like to do a fancy text slide in/out effect on whenever I change the text in it. I am able to switch the text and trigger the animation and it even works multiple times, but there is a weird jumping into place/resizing of the container div that happens during the animation. I have tried animating the margins of the text elements along with the rest of the animation but that doesn't work. I can't have the div resize because it is contained in a flexbox with an image right below it that I don't want to be pushed out of the way. What can I do to fix this and make the animation smoother?
function textboxWriteAnimated(str) {
const newText = document.createElement('p');
const currentText = document.getElementById("centerText");
const textContainer = document.getElementById("centerTextContainer");
newText.className = "fadingin";
newText.innerHTML = str;
newText.id = "centerText";
currentText.classList.add(["fadingout"]);
textContainer.appendChild(newText);
setTimeout(() => {
textContainer.removeChild(currentText);
document.getElementById("centerText").classList.remove(["fadingin"]);
}, 500)
}
setTimeout(() => {
textboxWriteAnimated("Does it work?");
setTimeout(() => {
textboxWriteAnimated(":(");
}, 1500)
}, 1000)
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#vert-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
#centerTextContainer {
font-size: 16px;
text-align: center;
line-height: 5px;
margin: 10px;
max-height: 37px;
min-height: 37px;
}
#img-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 50vw;
}
#links-container img {
margin: 5px;
}
#keyframes fade-out {
from {
bottom: 0px;
opacity: 100%;
font-size: 16px;
}
to {
bottom: 25px;
opacity: 0%;
font-size: 4px;
}
}
#keyframes fade-in {
from {
top: 25px;
opacity: 0%;
font-size: 4px;
}
to {
top: 0px;
opacity: 100%;
font-size: 16px;
}
}
.fadingout {
animation-name: fade-out;
animation-duration: 500ms;
animation-fill-mode: forwards;
}
.fadingin {
animation-name: fade-in;
animation-duration: 500ms;
}
<div id="vert-container">
<div id="centerTextContainer">
<p id="centerText">Testing...</p>
</div>
<div id="img-container">
<img src="https://img.shields.io/badge/Test-Image-black.svg">
</div>
</div>

Try like this:
function textboxWriteAnimated(str) {
const newText = document.createElement('p');
const currentText = document.getElementById("centerText");
const textContainer = document.getElementById("centerTextContainer");
newText.className = "fadingin";
newText.innerHTML = str;
newText.id = "centerText";
currentText.classList.add(["fadingout"]);
textContainer.appendChild(newText);
setTimeout(() => {
textContainer.removeChild(currentText);
document.getElementById("centerText").classList.remove(["fadingin"]);
}, 500)
}
setTimeout(() => {
textboxWriteAnimated("Does it work?");
setTimeout(() => {
textboxWriteAnimated(":)");
}, 1500)
}, 1000)
body, html {
margin: 0;
padding: 0;
overflow: hidden;
}
#vert-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
}
#centerTextContainer {
font-size: 16px;
text-align: center;
line-height: 5px;
margin: 10px;
max-height: 37px;
min-height: 37px;
position: relative;
display:block;
width:100%;
}
#centerTextContainer > p {
position:absolute;
display:block;
width:100%;
left:0;
right:0;
}
#img-container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
width: 50vw;
}
#links-container img {
margin: 5px;
}
#keyframes fade-out {
from {
bottom: 0px;
opacity: 100%;
font-size: 16px;
}
to {
bottom: 25px;
opacity: 0%;
font-size: 4px;
}
}
#keyframes fade-in {
from {
top: 25px;
opacity: 0%;
font-size: 4px;
}
to {
top: 0px;
opacity: 100%;
font-size: 16px;
}
}
.fadingout {
animation-name: fade-out;
animation-duration: 500ms;
animation-fill-mode: forwards;
}
.fadingin {
animation-name: fade-in;
animation-duration: 500ms;
}
<div id="vert-container">
<div id="centerTextContainer">
<p id="centerText">Testing...</p>
</div>
<div id="img-container">
<img src="https://img.shields.io/badge/Test-Image-black.svg">
</div>
</div>
The p elements in the animation need absolute positioning so that the top and bottom transitions will work as expected.

Related

How to create a square box in which the border of the box will be filled by color depending on the value given on the box?

Just like the above image or an idea or reference to achieve this design, I appreciate the help or suggestion given by community thank you
I have got reference of progress bar which is circular but not able find an approach to solve it.
const boxes = document.querySelectorAll(".box");
const colors = ['red', 'blue', 'green', 'yellow', 'orange', 'violet']
boxes.forEach((box) => {
const insideContent = box.innerText;
box.style.border = `6px solid ${colors[insideContent]}`
})
#app {
display: flex;
}
.box {
width: 50px;
height: 50px;
margin: 10px;
background-color: cyan;
display: flex;
justify-content: center;
align-items: center;
}
<div id="app">
<div class="box">1</div>
<div class="box">2</div>
<div class="box">3</div>
</div>
As per your question I think this is what you are trying to achieve.
First define a pseudo class root
:root {
--color-val: blue;
}
Note: In order to use the --color-val you need to write it as color: var(--color-var) in CSS
Second use JavaScript to update the variable --color-val
let colors =
var root = document.querySelector(':root');
const delay = ms => new Promise(res => setTimeout(res, ms));
const colorChange = async () => {
await delay(1000);
color = colors[Math.floor(Math.random() * colors.length)]
console.log(color)
root.style.setProperty('--color-val', color);
};
colorChange()
Note:
Add the color list you want to select from or go to CodePen for a list of 1000+ hex codes.
Promise are used for asynchronous function and can be skipped by using setTimeOut for a delayed loop or if used with another eventlistener.
I apologize if I misunderstood the question. Wrote in a hurry and without beautyful visualisation, if you disassemble the principle, you can customize it.
h1 {
display: block;
margin:0 auto;
text-align: center;
padding-top:20%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
z-index: 110;
margin:0;
margin: -10px;
}
.top {
display:block;
background-color: green;
height: 24px;
width: 150px; /* gorizontal top */
animation: top 1s linear;
animation-fill-mode: forwards;
}
#keyframes top {
0% {
width: 0px;
}
100% {
width: 150px;
}
}
.right {
background-color: green;
height: 0%;/* right */
width: 32px;
animation: right 1s linear;
animation-fill-mode: forwards;
animation-delay: 1s;
z-index: 10;
}
#keyframes right {
0% {
height: 0%;
}
100% {
height: 100%;
}
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.bottom {
position: absolute;
top: 123px;
left: 150px;
background-color: green;
width: 0px;
height: 27px;
z-index: 10;
animation: bottom 1s linear;
animation-fill-mode: forwards;
animation-delay: 2s;
/* animation-direction: reverse; */
}
#keyframes bottom {
0% {
transform: translate(0,0);
}
100% {
transform: translate(-250px,0);
-webkit-transform: translate(-250px,0); /** Safari & Chrome **/
-o-transform: translate(-250px,0); /** Opera **/
-moz-transform: translate(-250px,0); /** Firefox **/
width: 250px;
}
}
.left {
position: absolute;
top: 122px;
background-color: green;
width: 25px;
height: 0px;
animation: left 1s linear;
animation-fill-mode: forwards;
animation-delay: 3s;
}
#keyframes left {
0% {
transform: translate(0,0);
}
100% {
transform: translate(0,-250px);
-webkit-transform: translate(0,-250px); /** Safari & Chrome **/
-o-transform: translate(0,-250px); /** Opera **/
-moz-transform: translate(0,-250px); /** Firefox **/
height: 277px;
}
}
<div class='head'>
<div class='container'>
<div class='top'></div>
<div class='box'>
<h1 id='timer'>
1
</h1>
</div>
<div class='right'></div>
<div class='bottom'></div>
<div class='left'></div>
</div>
</div>
<script type="text/javascript">
init()
function init()
{
sec = 0;
setInterval(tick, 1000);
}
function tick()
{ if (sec<3) { sec++
document.getElementById("timer").
childNodes[0].nodeValue = sec;
} else {
clearInterval(0);
}
}
</script>
Also, instead of the SetInterval script, you can take values from your block width and height styles and output a mathematical calculation in h1 instead of a stopwatch.
upd: After your comment, I decided to do what I wrote about above. You can play with values and math, I add a snippet of another solution that changes the progress bar from the entered values within the entered range. (of course, it would be easier on react than on pure js)
function grade () {
let grade = +document.getElementById("grade").value;
let range = +document.getElementById("range").value;
document.getElementById("timer").innerHTML = `${grade}/${range}`;
progress(grade,range)
}
function progress (value, grade) {
document.getElementById('1').style.backgroundColor = `white`
document.getElementById("left").className = "noactive";
document.getElementById('top').style.width = `0%`
document.getElementById('right').style.height = `0%`
document.getElementById('bottom').style.width = `0%`
let GradeValuSide = grade/4;
if (value <= GradeValuSide) {
document.getElementById('top').style.width =
`${value/GradeValuSide*100}%`
} else if (value > GradeValuSide && value <= (GradeValuSide*2)) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height =
`${(value-GradeValuSide)/GradeValuSide*100}%`
} else if (value >= grade/2 && value < (grade/4)*3) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width =
`${((((value-(GradeValuSide*2)) / GradeValuSide) *100) / 100) *27}%`
} else if (value >= grade-(grade/4) /* && value < value + 1 */) {
document.getElementById('top').style.width = `100%`
document.getElementById('right').style.height = `100%`
document.getElementById('bottom').style.width = `100%`
document.getElementById('1').style.backgroundColor = `green`
document.getElementById("left").className = "left";
document.getElementById('left').style.height =
`${(40 - (40 * ((((value-(GradeValuSide*3)) * 100) / GradeValuSide)/ 100)))}%`
}
}
h1 {
font-size:20px;
position: absolute;
left: 40px;
display: block;
margin: 0 auto;
align-items: center;
padding-top:10%;
}
.container {
display:flex;
width: 150px;
height: 150px;
border: 1px solid black;
margin:0;
margin: -10px;
}
div.top {
display:block;
background-color: green;
height: 24px;
width: 0%; /* gorizontal top */
z-index:999;
}
div.right {
position:relative;
background-color: green;
height: 0%;/* right */
width: 32px;
z-index: 9999;
}
.box {
position: fixed;
top: 32.5px;
left: 32.5px;
background-color:white;
width: 100px;
height: 100px;
border: 1px solid black;
margin: auto;
z-index: 120;
margin: -10px -10px;
}
.wrap{
position: relative;
}
div.bottom {
position: absolute;
top: 123px;
background-color: green;
width: 0%; /* 27 = 100% */
height: 27px;
float: right;
right: 78vw;
z-index: 100;
}
div.left {
position: absolute;
background-color: white;
width: 23px;
height: 40%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
div.noactive {
position: absolute;
background-color: white;
width: 23px;
height: 0%;
top: 23px;
bottom: 10px;
left: 0;
float: top;
}
.items {
margin-top: 50px;
text-align: center;
}
.grade,
.value {
height: 15px;
width: 50px;
align-items: center;
}
<div class='head'>
<div id='1' class='container'>
<div id='top' class='top'></div>
<div class='box'>
<h1 id='timer'>1</h1>
<div class='items'>
value<input id='grade' class='grade' type=number oninput="grade()"/>
range<input id='range' class='value' type=number oninput="grade()"/>
</div>
</div>
<div id='right' class='right'></div>
<div id='bottom' class='bottom'></div>
<div id='left' class='noactive'></div>
</div>
</div>
<script src='app.js'></script>

How do I make the menu go to the side and show text to the right of it?

Kinda like this:
Design picture
I've gotten the code for the menu in the right format.
I've tried to get the code to make an animation to the right. Although, it doesn't work the way I want it to.
Here's the code I have written thus far:
HTML:
> <link rel="stylesheet" href="index.css"> <link rel="stylesheet"
> href="jason.js"> <div id="menu">
> <div id="menu-items">
> About
> Team
> Contact us
>
> </div>
> <div id="menu-background-pattern"></div>
> <div id="menu-background-image"></div> </div>
CSS:
body {
background-color: rgb(20, 20, 20);
margin: 0px; }
/* Menu items */
#menu {
height: 100vh;
display: flex;
align-items: center; }
.menu-item {
color: white;
font-size: clamp(3rem, 8vw, 8rem);
font-family: "Ibarra Real Nova", serif;
display: block;
text-decoration: none;
padding: clamp(0.25rem, 0.5vw, 1rem) 0rem;
transition: opacicity 400ms ease; }
#menu-items {
margin-left: clamp(4rem, 20vw, 48rem);
position: relative;
z-index: 2; }
#menu-items:hover > .menu-item {
opacity: 0.3; }
#menu-items:hover > .menu-item:hover {
opacity: 1; }
/* Background pattern */
#menu-items:hover ~ #menu-background-pattern {
background-size: 11vmin 11vmin;
opacity: 0.5; }
#menu[data-active-index="0"] > #menu-background-pattern {
background-position: 0% -25%; }
#menu[data-active-index="1"] > #menu-background-pattern {
background-position: 0% -50%; }
#menu[data-active-index="2"] > #menu-background-pattern {
background-position: 0% -75%; }
#menu[data-active-index="3"] > #menu-background-pattern {
background-position: 0% -100%; }
#menu[data-active-index="0"] > #menu-background-image {
background-position: 0% 45%; }
#menu[data-active-index="1"] > #menu-background-image {
background-position: 0% 50%; }
#menu[data-active-index="2"] > #menu-background-image {
background-position: 0% 55%; }
#menu[data-active-index="3"] > #menu-background-image {
background-position: 0% 60%; }
#menu-background-image {
height: 100%;
width: 100%;
background-image: url('logo.png');
position: absolute;
left: 0px;
top: 0px;
z-index: 0;
background-position: center 40%;
background-size: 110vmax;
opacity: 0.15;
transition: opacity 800ms ease,
background-size 800ms ease,
background-position 800ms ease; }
#menu-items:hover ~ #menu-background-image {
background-size: 100vmax;
opacity: 0.10; }
JS:
const menu = document.getElementById("menu")
Array.from(document.getElementsByClassName("menu-item"))
.forEach((items, index) => {
items.onmouseover = () => {
menu.dataset.activeIndex = index;
}
});
I've been unable to get the menu to slide to the side. And make room for the text to the right without it ruining the zooming in animation and background animation.
The idea is for it to keep being zoomed out the same way whilst showing the text.
Here is the solution how to create a drawer with a multi page system using vanilla HTML, CSS & JavaScript
1. First create a HTML file named index.html
<!DOCTYPE html>
<html>
<head>
<link href="main.css" rel="stylesheet">
</head>
<body>
<section id="root" class="page">
<input type="button" value="Menu" onclick="onMenu()">
</section>
<section id="about" class="page">
<h1>About</h1>
<input type="button" value="Menu" onclick="onMenu()">
</section>
<section id="team" class="page">
<h1>Team</h1>
<input type="button" value="Menu" onclick="onMenu()">
</section>
<section id="contact" class="page">
<h1>Contact us</h1>
<input type="button" value="Menu" onclick="onMenu()">
</section>
<div id="menu">
<div id="close">
<input type="button" value="×" id="close-btn">
</div>
Home
About
Team
Contact us
</div>
<script src="app.js" type="text/javascript"></script>
</body>
</html>
2. Second create a CSS file named main.css
body {
margin: 0 auto;
padding: 0;
}
#root {
z-index: 1;
}
.page {
display: grid;
justify-items: center;
align-content: center;
width: 100vw;
height: 100vh;
background-color: #FFFFFF;
position: absolute;
overflow-x: hidden;
overflow-y: scroll;
}
section:target {
opacity: 1;
z-index: 1;
}
#menu {
display: none;
justify-items: center;
align-content: flex-start;
box-sizing: border-box;
position: fixed;
top: 0;
left: 0;
z-index: 1;
width: 75vw;
height: 100vh;
background-color: #333333AA;
}
.menu-btn {
margin: 1em 0 1em 0;
text-decoration: none;
color: #FFFFFF;
}
#close {
display: flex;
justify-content: center;
align-items: center;
width: inherit;
height: 10vh;
}
#close::before {
content: "";
width: 70vw;
}
#close-btn {
border: 0;
width: 25vw;
height: 10vh;
font-size: 64px;
color: #FFF;
background-color: transparent;
}
#keyframes slideRight {
from {
width: 0;
opacity: 0;
}
to {
width: 70vw;
opacity: 1;
}
}
#keyframes slideLeft {
from {
width: 70vw;
opacity: 1;
}
to {
width: 0;
opacity: 0;
}
}
3. Finally create sa JS file named app.js
let menu = document.querySelector("#menu");
let close_btn = document.querySelector("#close-btn");
let onMenu = () => {
menu.style.display = "grid";
menu.style.animationName = "slideRight";
menu.style.animationDuration = "0.5s";
};
close_btn.addEventListener("click", () => {
menu.style.animationName = "slideLeft";
menu.style.animationDuration = "0.5s";
setTimeout(() => {
menu.style.display = "none";
}, 400);
});

How to use CSS animation to achieve dynamic switching effect?

I'm a front-end beginner and I want to make an effect now!
When you click the button on the red card, let the red move down and fade out, while the blue card slides down from above.
When you click the blue button again, it turns blue and moves down to fade out, and the red card slides down from above.
But I only make the red card move down, and it has no effect when I want to click the button of the blue card.
I'm sorry that my whole logic is stuck, I hope I can ask for your help here, thank you in advance.
The effect I want to do is similar to this URL below
enter link description here
I made a screenshot as an example
let btn = document.querySelector('.btn');
let btn2 = document.querySelector('.btn2');
btn.addEventListener('click', function() {
$('.card1').addClass('active');
})
btn2.addEventListener('click', function() {
$('.card2').addClass('active');
})
body {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.wrap {
position: relative;
}
.wrap .card1 {
width: 500px;
height: 300px;
background-color: red;
border-radius: 20px;
display: flex;
justify-content: center;
align-items: flex-end;
}
.wrap .card1 .btn {
width: 100px;
height: 50px;
border-radius: 50px;
margin-bottom: 10px;
}
.wrap .card2 {
position: absolute;
top: 0px;
width: 500px;
height: 300px;
background-color: blue;
border-radius: 20px;
z-index: -1;
display: flex;
justify-content: center;
align-items: flex-end;
}
.wrap .card2 .btn2 {
width: 100px;
height: 50px;
border-radius: 50px;
margin-bottom: 10px;
}
.active {
-webkit-animation-iteration-count: 1;
animation-iteration-count: 1;
-webkit-animation-name: moveup;
animation-name: moveup;
-webkit-animation-duration: 1s;
animation-duration: 1s;
-webkit-animation-fill-mode: forwards;
animation-fill-mode: forwards;
}
#-webkit-keyframes moveup {
from {
opacity: 1;
}
to {
transform: translatey(20px);
display: none;
opacity: 0;
}
}
#keyframes moveup {
from {
opacity: 1;
}
to {
transform: translatey(20px);
display: none;
opacity: 0;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrap">
<div class="card1">
<input type="button" value="save" class="btn">
</div>
<div class="card2">
<input type="button" value="recalculate" class="btn2">
</div>
</div>
I made this code for you, hope you find it helpful, if you have any doubt I will be glad to help you out.
function card2Show() {
var card2 = document.getElementById('card2');
var card1 = document.getElementById('card1');
//card1 down transition
card1.style.transform = "translateY(131px)"; //this move the card down
card1.style.filter = "opacity(0)"; //this changes the opacity of the card to desapeare it
//this timeout is set to give time to the first animation to finish
setTimeout(() => {
card1.style.display = "none";
//here is the card2 animation to apear
card2.style.transform = "translateY(-131px)";
card2.style.filter = "opacity(0)";
card2.style.display = "block";
setTimeout(() => {
card2.style.filter = "opacity(1)";
card2.style.transform = "translateY(0)";
}, 60)
}, 450)
}
function card1Show() {
var card2 = document.getElementById('card2');
var card1 = document.getElementById('card1');
//card1 down transition
card2.style.transform = "translateY(-131px)"; //this move the card down
card2.style.filter = "opacity(0)"; //this changes the opacity of the card to desapeare it
//this timeout is set to give time to the first animation to finish
setTimeout(() => {
card2.style.display = "none";
//here is the card2 animation to apear
card1.style.transform = "translateY(131px)";
card1.style.filter = "opacity(0)";
card1.style.display = "block";
setTimeout(() => {
card1.style.filter = "opacity(1)";
card1.style.transform = "translateY(0)";
}, 60)
}, 450)
}
.cardsContainer {
background-color: red;
max-height: 180px;
min-height: 180px;
overflow: hidden;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.card1 {
height: 100px;
transition: all .6s ease,filter .5s ease;
padding: 20px;
background-color:white;
}
.card2 {
display: none;
height: 100px;
padding: 20px;
background-color:white;
transition: all .6s ease;
}
<section>
<div class="col-12 cardsContainer">
<div class="col-8">
<div id="card1" class="card card1">
<div class="card-body">
<button onclick="card2Show()">Show card2</button>
</div>
</div>
<div id="card2" class="card card2">
<div class="card-body">
<button onclick="card1Show()">Show card1</button>
</div>
</div>
</div>
</div>
</section>

How do I do this to the progress bar?(html-css)

How do I do this to the progress bar like below:
.detail-load {
height: 42px;
border: 1px solid #A2B2C5;
padding: 1px;
border-radius: 10px;
}
.detail-load > .detail-loading {
background: #904BFF;
height: 100%;
border-radius: 10px;
}
.detail-load-text {
position: absolute;
right: 0;
left: 0;
top: 10px;
text-align: center;
color: #fff;
font-weight: 600;
font-size: 17px;
}
<div class="detail-pop-item">
<div class="detail-load">
<div class="detail-loading" style="width: 80%;"></div>
</div>
<div class="detail-load-text">80%</div>
</div>
The progress bar I want to make is like the image I shared above. Can anyone help?
You could use the clip-path property to achieve your desired result. I included some dummy javascript in the snippet to simulate loading.
You can set --loading-color-primary and --loading-color-secondary to any two colors you'd like.
const front = document.getElementById('progress-front');
const back = document.getElementById('progress-back');
let progress = 0;
setInterval(() => {
front.style.webkitClipPath = `inset(0 0 0 ${progress}%)`;
if(++progress >= 100) {
progress = 0;
}
front.innerHTML = back.innerHTML = progress + "%";
}, 50);
:root {
--loading-color-primary: purple;
--loading-color-secondary: white;
}
.progress {
position: relative;
display: flex;
font-size: 50px;
border: 2px solid var(--loading-color-primary);
overflow: hidden;
width: 100%;
}
.back {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
background: var(--loading-color-primary);
color: var(--loading-color-secondary);
}
.front {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
left: 0;
width: 100%;
right: 0;
top: 0;
bottom: 0;
background: var(--loading-color-secondary);
color: var(--loading-color-primary);
}
<div class="progress">
<div class="back" id="progress-back">0%</div>
<div class="front" id="progress-front">0%</div>
</div>
This is an example of what you want to accomplish:
https://codepen.io/robinrendle/pen/wKqmbW
<div class="wrapper">
<div class="bg">
<div class="el"></div>
</div>
</div>
$loadingTime: 10s;
$color: rgb(255,0,0);
body {
background-color: white;
}
#keyframes loading {
0% {
width: 0;
} 100% {
width: 100%;
}
}
#keyframes percentage {
#for $i from 1 through 100 {
$percentage: $i + "%";
#{$percentage} {
content: $percentage;
}
}
}
.bg {
background-color: $color;
animation: loading $loadingTime linear infinite;
}
.el{
color: $color;
width: 200px;
border: 1px solid $color;
&:after {
padding-left: 20px;
content: "0%";
display: block;
text-align: center;
font-size: 50px;
padding: 10px 20px;
color: rgb(0,255,255);
mix-blend-mode: difference;
animation: percentage $loadingTime linear infinite;
}
}
html {
height: 100%;
background-color: white;
font-family: 'PT Sans', sans-serif;
font-weight: bold;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
The key item here is the mix-blend-mode property which defines how an element's content should blend with its background.
You can learn more about it here and here.
I used a different approach, where you can set a CSS variable to control the length of the loading progress as well as displaying the value.
Because I used a pseudo-class to display the value, I needed to use a number hack, using counter-reset on the ::after pseudo-element.
As for having the dark text turn white, you can use mix-blend-mode: color-dodge. It's not perfect, as you can see, but perhaps good enough?
.detail-load {
height: 42px;
border: 1px solid #A2B2C5;
padding: 1px;
border-radius: 10px;
}
.detail-load > .detail-loading {
background: #904BFF;
height: 100%;
border-radius: 10px;
/* ADDED */
width: calc(var(--progress) * 1%);
position: relative;
}
.detail-load > .detail-loading::after {
font-weight: 600;
font-size: 17px;
/* ADDED */
counter-reset: number-hack var(--progress);
content: counter(number-hack)"%";
position: absolute;
right: 0px;
top: 50%;
transform: translate(50%, -50%);
color: #d2b6ff;
mix-blend-mode: color-dodge;
}
.detail-load > .detail-loading.grey-text::after {
color: #b5b5b5;
}
<div class="detail-pop-item">
<div class="detail-load">
<div class="detail-loading" style="--progress: 30"></div>
</div>
</div>
<div class="detail-pop-item">
<div class="detail-load">
<div class="grey-text detail-loading" style="--progress: 60"></div>
</div>
</div>
Following Veselin's answer, you just need to change the color attributes as follows:
$color: rgb(255,0,0); becomes $color: rgb(255,0,255);
and
.el{
...
&:after {
...
color: rgb(0,255,255);
}
}
becomes
.el{
...
&:after {
...
color: rgb(0,255,0);
}
}
The result is:
$loadingTime: 10s;
$color: rgb(255,0,255);
body {
background-color: white;
}
#keyframes loading {
0% {
width: 0;
} 100% {
width: 100%;
}
}
#keyframes percentage {
#for $i from 1 through 100 {
$percentage: $i + "%";
#{$percentage} {
content: $percentage;
}
}
}
.bg {
background-color: $color;
animation: loading $loadingTime linear infinite;
}
.el{
color: $color;
width: 200px;
border: 1px solid $color;
&:after {
padding-left: 20px;
content: "0%";
display: block;
text-align: center;
font-size: 50px;
padding: 10px 20px;
color: rgb(0,255,0);
mix-blend-mode: difference;
animation: percentage $loadingTime linear infinite;
}
}
html {
height: 100%;
background-color: white;
font-family: 'PT Sans', sans-serif;
font-weight: bold;
}
body {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}

How to make an animated messenger

I want to create a messenger component that, when the function is called, will create a message and, when pressed or by a timer, will at first make it transparent -> after that, smoothly decrease the height of the wrapper ->, and after the end of the transition, delete the object
How can can I do that
My code is not working correctly
<template>
<div class="message" id="wrapper"></div>
</template>
<style lang="scss">
$height-block: 9vmin;
.message {
position: absolute;
z-index: 10;
right: 1vmin;
bottom: 1vmin;
width: 25vmin;
height: 50vmin;
overflow: hidden;
display: flex;
flex-direction: column;
justify-content: flex-end;
.wrapper {
* {
box-sizing: border-box;
}
flex-shrink: 0;
width: 100%;
position: relative;
transition: height 0.5s linear;
transition: margin 0.5s linear;
height: $height-block;
padding: 0.5vmin 0;
&__block {
background: rgba(42, 29, 29, 0.8);
height: 100%;
width: 100%;
font-size: 2vmin;
padding: 1vmin;
color: white;
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.5s linear;
}
}
}
</style>
<script>
export default {
name: "Messenger",
};
//eslint-disable-next-line no-unused-vars
window.msg = function msg(msg) {
let wrapper = document.createElement("div");
wrapper.classList.add("wrapper");
document.getElementById("wrapper").appendChild(wrapper);
let wrapper__block = document.createElement("div");
wrapper__block.classList.add("wrapper__block");
wrapper.appendChild(wrapper__block);
wrapper__block.innerHTML = msg;
setTimeout(() => {
wrapper__block.style.opacity = "0";
}, 1000);
wrapper__block.addEventListener("mousedown", () => {
wrapper__block.style.opacity = "0";
});
wrapper__block.addEventListener("transitionend", () => {
wrapper.parentElement.style.height = "0";
wrapper.parentElement.style.margin = "0";
});
wrapper.addEventListener("transitionend", () => {
wrapper.remove(wrapper__block);
});
};
</script>

Categories