CSS #keyframe Animation Removing whole button instead of just border - javascript

I have a CSS keyframe animation that outlines the border of the button. However, when I try to reverse the animation on mouse off, it removes the inset box shadow instead of the gradient border.
As you can see below, I've tried to set the border and background again in mouseLeaveAnimationClass. That does not solve the problem either. Is there an elegant solution to this problem?
var els = document.querySelectorAll('.get-started');
for (var i = 0; i < els.length; i++) {
els[i].addEventListener('mouseleave', function(e) {
e.target.classList.add('mouseleaveAnimationClass');
});
els[i].addEventListener('mouseenter', function(e) {
e.target.classList.remove('mouseleaveAnimationClass');
});
}
body {
background-color: black;
}
#button {
display: flex;
font-size: 2.5rem;
color: white;
align-items: center;
justify-content: center;
width: 250px;
height: 75px;
position: relative;
top: -30%;
left: calc(50% - 125px);
}
.get-started {
--borderWidth: 5px;
position: relative;
border-radius: var(--borderWidth);
background-color: #8551FF;
box-shadow: inset 0 0 0 5px white;
z-index: 1;
}
.get-started:after {
content: '';
position: absolute;
}
.get-started:hover:after {
background: linear-gradient(60deg, #f79533, #f37055, #ef4e7b, #a166ab, #5073b8, #1098ad, #07b39b, #6fba82);
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 2px;
background-size: 300% 300%;
animation: frame-enter 1s forwards ease-in-out reverse, gradient-animation 4s ease-in-out infinite;
}
.get-started.mouseleaveAnimationClass {
background: linear-gradient(60deg, #f79533, #f37055, #ef4e7b, #a166ab, #5073b8, #1098ad, #07b39b, #6fba82);
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 2px;
background-size: 300% 300%;
animation: frame-enter 1s forwards ease-in-out;
}
/* motion */
#keyframes gradient-animation {
0% {
background-position: 15% 0%;
}
50% {
background-position: 85% 100%;
}
100% {
background-position: 15% 0%;
}
}
#keyframes frame-enter {
0% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), 5px calc(100% - 5px), 5px 100%, 100% 100%, 100% 0%, 0% 0%);
}
25% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) 100%, 100% 100%, 100% 0%, 0% 0%);
}
50% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, 100% 0%, 0% 0%);
}
75% {
-webkit-clip-path: polygon(0% 100%, 5px 100%, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 0%, 0% 0%);
}
100% {
-webkit-clip-path: polygon(0% 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 0% 100%);
}
}
<div class="get-started" id="button">Get Started</div>
Runnable Example

In your original problem, the .get-started.mouseleaveAnimationClass { rule is applied to the element itself, and not to the ::after pseudo-element, and that's why the element is clipped. However, this won't solve your main problem - the reverse animation.
I've updated your code with a solution that is not super DRY, and you can probably improve it.
On the 1st hover only, the .ready class is added to the button. This enables the frame-leave animation, without running it. Whenever you :hover the element the frame-enter animation is applied, and as soon as you leave the element, the frame-leave is called again.
Notes:
frame-enter and frame-leave are the same animation. Using a different name allows us to replace them.
When you enter and then leave in the middle of the animation it will jump from the enter to the leave animation.
var els = document.querySelectorAll('.get-started');
for (var i = 0; i < els.length; i++) {
els[i].addEventListener('mouseenter', function(e) {
e.target.classList.add('ready');
}, { once: true });
}
#button {
display: flex;
font-size: 2.5rem;
color: white;
align-items: center;
justify-content: center;
width: 250px;
height: 75px;
position: relative;
top: -30%;
left: calc(50% - 125px);
}
.get-started {
--borderWidth: 5px;
position: relative;
border-radius: var(--borderWidth);
background-color: #8551FF;
box-shadow: inset 0 0 0 5px white;
z-index: 1;
}
.get-started::after {
content: '';
position: absolute;
background: linear-gradient(60deg, #f79533, #f37055, #ef4e7b, #a166ab, #5073b8, #1098ad, #07b39b, #6fba82);
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 2px;
background-size: 300% 300%;
clip-path: polygon(0% 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 0% 100%);
}
.get-started.ready::after {
animation: frame-leave 1s forwards ease-in-out, gradient-animation 4s ease-in-out infinite;
}
.get-started.ready:hover::after {
animation: frame-enter 1s forwards ease-in-out reverse, gradient-animation 4s ease-in-out infinite;
}
/* motion */
#keyframes gradient-animation {
0% {
background-position: 15% 0%;
}
50% {
background-position: 85% 100%;
}
100% {
background-position: 15% 0%;
}
}
#keyframes frame-enter {
0% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), 5px calc(100% - 5px), 5px 100%, 100% 100%, 100% 0%, 0% 0%);
}
25% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) 100%, 100% 100%, 100% 0%, 0% 0%);
}
50% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, 100% 0%, 0% 0%);
}
75% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 0%, 0% 0%);
}
100% {
clip-path: polygon(0% 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 0% 100%);
}
}
#keyframes frame-leave {
0% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), 5px calc(100% - 5px), 5px 100%, 100% 100%, 100% 0%, 0% 0%);
}
25% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) calc(100% - 5px), calc(100% - 5px) 100%, 100% 100%, 100% 0%, 0% 0%);
}
50% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, calc(100% - 5px) 5px, 100% 0%, 0% 0%);
}
75% {
clip-path: polygon(0% 100%, 5px 100%, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 5px, 5px 0%, 0% 0%);
}
100% {
clip-path: polygon(0% 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 5px 100%, 0% 100%);
}
}
<div class="get-started" id="button">Get Started</div>

Related

How to dynamically change a CSS seconds value

var timerSeconds = 10; // This will be set from a DB value
function StartCountDownTimer() {
var timerStart = new Date();
var css_seconds = `${timerSeconds}s`;
css_root = document.querySelector(':root');
cssVarBefore = '--timer-seconds BEFORE being set by JS: ' + getComputedStyle(css_root).getPropertyValue('--timer-seconds');
css_root.style.setProperty('--timer-seconds', css_seconds);
cssVarAfter = '--timer-seconds AFTER being set by JS: ' + getComputedStyle(css_root).getPropertyValue('--timer-seconds');
document.querySelector('.progress-border').classList.add('progress-border-animation');
timerStart.setSeconds(timerStart.getSeconds() + timerSeconds);
timerStart = timerStart.getTime();
// Update the count down every 1 second
var x = setInterval(function() {
var now = new Date().getTime();
var distance = timerStart - now;
var seconds = Math.round(distance / 1000, 1000);
document.getElementById("seconds-remaining").innerHTML = seconds;
if (seconds < 1) {
clearInterval(x);
document.getElementById("seconds-remaining").innerHTML = "";
document.querySelector('.progress-border').classList.remove('progress-border-animation');
alert("This demonstrates that the CSS variable is actually being changed it just isn't affecting the animation duration\n\n" + cssVarBefore + '\n' + cssVarAfter);
}
}, 1000);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
/* this is the variable I'm trying to set from JavaScript */
--timer-seconds: 5s;
--box-size: 150px;
--border-width: 8px;
}
body {
margin: 3em;
}
container {
display: flex;
flex-direction: columns;
gap: 1em;
}
.secs {
color: #365a2a;
font-size: 72px;
font-weight: bold;
text-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);
}
.count-down-timer{
position: relative;
display: flex;
flex-wrap: wrap;
align-content: center;
justify-content: center;
width: var(--box-size);
height: var(--box-size);
border: var(--border-width) solid #c05b20;
border-radius: calc(var(--border-width)*2);
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.5);
background: linear-gradient(#599646, #bfe2c3);
cursor: pointer;
}
.progress-border {
position: absolute;
top: calc(var(--border-width)*-1);
left: calc(var(--border-width)*-1);
width: var(--box-size);
height: var(--box-size);
border-radius: calc(var(--border-width)*2);
}
.progress-border-animation {
border: var(--border-width) solid #365a2a;
animation: fill forwards linear;
animation-duration: var(--timer-seconds); /* this line doesn't work */
/* animation-duration: 10s; */ /* this line works */
}
#keyframes fill {
0% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0%);
}
12.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 100% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0%);
}
25% {
clip-path: polygon(50% -20.71%, 50% 50%, 120.71% 50%, 120.71% 50%, 120.71% 50%, 120.71% 50%, 100% 0%);
}
37.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 0%);
}
50% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% 120.71%, 50% 120.71%, 50% 120.71%, 100% 100%, 100% 0%);
}
62.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 0% 100%, 0% 100%, 0% 100%, 100% 100%, 100% 0%);
}
75% {
clip-path: polygon(50% -20.71%, 50% 50%, -20.71% 50%, -20.71% 50%, 0% 100%, 100% 100%, 100% 0%);
}
87.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 0% 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
}
100% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% -20.71%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
visibility: hidden;
}
}
<!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>Progress Bar</title>
</head>
<body>
<container>
<div>
<p><b>Click on the box to start the timer</b></p><br>
<div onclick="StartCountDownTimer()" class="count-down-timer">
<p class="secs" id="seconds-remaining"></p>
<div class="progress-border"></div>
</div>
</div>
<div>
<p><b>This is where I need help:</b></p>
<p>The CSS variable used for animation duration of the border is being set to 10 seconds to match the count down timer but the border is still using the original value of 5 seconds for its animation. <b>WHY?</b>
</p>
</div>
</container>
</body>
</html>
Trying to figure out how to dynamically change the seconds value for a CSS animation duration. I statically set the value in the class to 20s. From JavaScript I want to be able to change the 20s to some dynamic value, e.g. 60s. I'm using the value in JS to do other iterations so I need it to be an integer in JS. I think the issue I'm having is using different data types integer vs seconds but I'm not sure.
I've tried a few different approaches but none have worked:
changing CSS integer variable --sec: 20, from JS, then using calc(0s + var(--sec)) for the animation duration.
changing CSS seconds variable --sec: 20s, from JS by concatenating (60 + 's') and using var(--sec) for the animation duration.
modifying the document.getElementsByClassName('class')[0].style.animationDuration value from JS by concatenating (60 + 's')
Any suggestions would be much appreciated...
UPDATE regarding the latest posted code
It seems that the CSS variables are not defined in :root {}, instead are in * {}, therefore the setProperty() did not work.
If you move them to :root {} it should work properly:
:root {
--timer-seconds: 5s;
--box-size: 150px;
--border-width: 8px;
}
Update regarding custom duration input
You can also set ms as value of animation-duration in CSS.
More about animation-duration
Here is an over simplified example, it sets a value in ms to animation-duration by changing a variable --duration on the animated element.
There are many other ways, but this seems to be straight forward.
Hope this will help.
const figure = document.querySelector("figure");
const btns = document.querySelectorAll("button:not(#custom)");
const btnCustom = document.querySelector("button#custom");
const input = document.querySelector("input");
btnCustom.addEventListener("click",()=>{
const {value} = input
if (!value || isNaN(value) || value < 100 || value > 2000) {
input.value = ""
return}
const duration = `${Math.floor(value)}ms`
figure.style.setProperty("--duration", duration)
})
btns.forEach((btn) =>
btn.addEventListener("click", (e) =>
figure.style.setProperty("--duration", e.target.dataset.duration)
)
)
*,
*::after,
*::before {
margin: 0;
padding: 0;
box-sizing: border-box;
}
section {
display: flex;
flex-direction: column;
flex-wrap: wrap;
gap: 6px;
justify-content: center;
align-items: center;
width: 500px;
padding: 6px;
}
.control {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
gap: 3px;
}
button {
flex: 1;
padding: 3px;
}
input {
flex: 1;
padding: 3px;
}
.animation {
display: flex;
align-items: center;
width: 500px;
height: 150px;
background-color: #fdf5e6;
}
figure {
width: 100px;
height: 100px;
background-color: #1e90ff;
border-radius: 50%;
animation: move alternate infinite linear;
animation-duration: var(--duration, 1200ms);
}
#keyframes move {
from {
transform: translateX(0);
}
to {
transform: translateX(400px);
}
}
<section>
<div class="control">
<input
type="number"
min="100"
max="2000"
step="100"
placeholder="Enter num between 100 and 2000"
/>
<button id="custom">Set custom duration in ms</button>
</div>
<div class="control">
<button data-duration="1200ms">Defalut</button>
<button data-duration="700ms">Fast</button>
<button data-duration="300ms">Faster</button>
</div>
<div class="animation">
<figure></figure>
</div>
</section>

html/css circular progress bar with image inside

I want to create a circular progress bar around an image that should look like this :
I have tried making the circle fill but it just transforms into a spinner with the following code
.wrapper {
width: 152px;
height: 152px;
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #21ac62;
width: 120px;
height: 120px;
animation: fill ease-in-out 3s;
transform: rotate(360deg);
}
.wrapper {
background: url('https://i.ibb.co/5T3p5sY/icon-3151974-1280.png') center no-repeat;
background-size:50%;
}
#keyframes fill{
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="jQuery-plugin-progressbar.css">
</head>
<body>
<div class="wrapper">
<div class="loader"></div>
</div>
</body>
</html>
I achieved the goal without changing the HTML layout using clip-path animation.
https://developer.mozilla.org/en-US/docs/Web/CSS/clip-path
.wrapper {
width: 152px;
height: 152px;
background-image: url('https://i.ibb.co/5T3p5sY/icon-3151974-1280.png');
background-position: center;
background-repeat: no-repeat;
background-size: 50%;
}
.loader {
border: 16px solid #21ac62;
border-radius: 50%;
width: 120px;
height: 120px;
animation: fill linear 3s;
}
#keyframes fill {
0% {
clip-path: polygon(50% 0%, 50% 50%, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0%);
}
12.5% {
clip-path: polygon(50% 0%, 50% 50%, 100% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0%);
}
37.5% {
clip-path: polygon(50% 0%, 50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 0%);
}
62.5% {
clip-path: polygon(50% 0%, 50% 50%, 0% 100%, 0% 100%, 0% 100%, 100% 100%, 100% 0%);
}
87.5% {
clip-path: polygon(50% 0%, 50% 50%, 0% 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
}
100% {
clip-path: polygon(50% 0%, 50% 50%, 50% 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
}
}
<div class="wrapper">
<div class="loader"></div>
</div>
Edit: This should be smoother:
.wrapper {
width: 152px;
height: 152px;
background-image: url('https://i.ibb.co/5T3p5sY/icon-3151974-1280.png');
background-position: center;
background-repeat: no-repeat;
background-size: 50%;
}
.loader {
border: 16px solid #21ac62;
border-radius: 50%;
width: 120px;
height: 120px;
animation: fill linear 3s;
}
#keyframes fill {
0% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% 0%, 50% 0%, 50% 0%, 50% 0%, 50% 0%);
}
12.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 100% 0%, 100% 0%, 100% 0%, 100% 0%, 100% 0%);
}
25% {
clip-path: polygon(50% -20.71%, 50% 50%, 120.71% 50%, 120.71% 50%, 120.71% 50%, 120.71% 50%, 100% 0%);
}
37.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 0%);
}
50% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% 120.71%, 50% 120.71%, 50% 120.71%, 100% 100%, 100% 0%);
}
62.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 0% 100%, 0% 100%, 0% 100%, 100% 100%, 100% 0%);
}
75% {
clip-path: polygon(50% -20.71%, 50% 50%, -20.71% 50%, -20.71% 50%, 0% 100%, 100% 100%, 100% 0%);
}
87.5% {
clip-path: polygon(50% -20.71%, 50% 50%, 0% 0%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
}
100% {
clip-path: polygon(50% -20.71%, 50% 50%, 50% -20.71%, 0% 0%, 0% 100%, 100% 100%, 100% 0%);
}
}
<div class="wrapper">
<div class="loader"></div>
</div>
For more Information and Full Explaination, Reach to https://dev.to/shantanu_jana/circular-progress-bar-using-html-and-css-1oda
body {
background:#d2eaf1;
}
.circle-wrap {
margin: 150px auto;
width: 150px;
height: 150px;
background: #fefcff;
border-radius: 50%;
border: 1px solid #cdcbd0;
}
.circle-wrap .circle .mask,
.circle-wrap .circle .fill {
width: 150px;
height: 150px;
position: absolute;
border-radius: 50%;
}
.circle-wrap .circle .mask {
clip: rect(0px, 150px, 150px, 75px);
}
.circle-wrap .inside-circle {
width: 122px;
height: 122px;
border-radius: 50%;
background: #d2eaf1;
line-height: 120px;
text-align: center;
margin-top: 14px;
margin-left: 14px;
color: #1e51dc;
position: absolute;
z-index: 100;
font-weight: 700;
font-size: 2em;
display:flex;
align-items:center;
justify-content:center;
}
/* color animation */
/* 3rd progress bar */
.mask .fill {
clip: rect(0px, 75px, 150px, 0px);
background-color: #227ded;
}
.mask.full,
.circle .fill {
animation: fill ease-in-out 3s;
transform: rotate(135deg);
}
#keyframes fill{
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(135deg);
}
}
<body>
<div class="circle-wrap">
<div class="circle">
<div class="mask full">
<div class="fill"></div>
</div>
<div class="mask half">
<div class="fill"></div>
</div>
<div class="inside-circle">
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" fill="currentColor" class="bi bi-apple" viewBox="0 0 16 16">
<path d="M11.182.008C11.148-.03 9.923.023 8.857 1.18c-1.066 1.156-.902 2.482-.878 2.516.024.034 1.52.087 2.475-1.258.955-1.345.762-2.391.728-2.43zm3.314 11.733c-.048-.096-2.325-1.234-2.113-3.422.212-2.189 1.675-2.789 1.698-2.854.023-.065-.597-.79-1.254-1.157a3.692 3.692 0 0 0-1.563-.434c-.108-.003-.483-.095-1.254.116-.508.139-1.653.589-1.968.607-.316.018-1.256-.522-2.267-.665-.647-.125-1.333.131-1.824.328-.49.196-1.422.754-2.074 2.237-.652 1.482-.311 3.83-.067 4.56.244.729.625 1.924 1.273 2.796.576.984 1.34 1.667 1.659 1.899.319.232 1.219.386 1.843.067.502-.308 1.408-.485 1.766-.472.357.013 1.061.154 1.782.539.571.197 1.111.115 1.652-.105.541-.221 1.324-1.059 2.238-2.758.347-.79.505-1.217.473-1.282z"/>
<path d="M11.182.008C11.148-.03 9.923.023 8.857 1.18c-1.066 1.156-.902 2.482-.878 2.516.024.034 1.52.087 2.475-1.258.955-1.345.762-2.391.728-2.43zm3.314 11.733c-.048-.096-2.325-1.234-2.113-3.422.212-2.189 1.675-2.789 1.698-2.854.023-.065-.597-.79-1.254-1.157a3.692 3.692 0 0 0-1.563-.434c-.108-.003-.483-.095-1.254.116-.508.139-1.653.589-1.968.607-.316.018-1.256-.522-2.267-.665-.647-.125-1.333.131-1.824.328-.49.196-1.422.754-2.074 2.237-.652 1.482-.311 3.83-.067 4.56.244.729.625 1.924 1.273 2.796.576.984 1.34 1.667 1.659 1.899.319.232 1.219.386 1.843.067.502-.308 1.408-.485 1.766-.472.357.013 1.061.154 1.782.539.571.197 1.111.115 1.652-.105.541-.221 1.324-1.059 2.238-2.758.347-.79.505-1.217.473-1.282z"/>
</svg> </div>
</div>
</div>
</body>

How to make earth progress pie [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I would want to add to my website a progress bar with this design:
The progress pie
How do I make a progress pie with an image inside it, and when it moves it display the image inside it with colors?
This is non-trivial but could be achieved by using two images, clip-path and a script, a greyscale image and a coloured image.
Position the greyscale image under the coloured one.
Use clip-path to only show a portion of the coloured image.
Adjust the clip-path values using a JavaScript loop OR using a css key-frames animation
Here's a simplified keyframes example:
.greyscale {
filter: grayscale(1);
}
.color {
overflow: hidden;
animation: clippy 2s infinite;
}
#keyframes clippy {
0% { clip-path: polygon(50% 50%, 50% 0, 50% 0, 50% 0, 50% 0, 50% 0, 50% 0); }
12.5% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 0, 100% 0, 100% 0, 100% 0); }
25% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 100% 50%, 100% 50%, 100% 50%); }
37.5% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 100% 100%, 100% 100%, 100% 100%); }
50% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 50% 100%, 50% 100%, 50% 100%); }
62.5% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 0 100%, 0 100%, 0 100%); }
75% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 0 100%, 0 50%, 0 50%); }
87.5% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 0 100%, 0 0, 0 0); }
100% { clip-path: polygon(50% 50%, 50% 0, 100% 0, 100% 100%, 0 100%, 0 0, 50% 0); }
}
div {
border-radius: 50%;
height: 200px;
overflow: hidden;
position: relative;
width: 200px;
}
img {
height: 100%;
width: 100%;
object-fit: cover;
position: absolute;
}
<div>
<img class="greyscale" src="https://interactive-examples.mdn.mozilla.net/media/examples/balloon-small.jpg">
<img class="color" src="https://interactive-examples.mdn.mozilla.net/media/examples/balloon-small.jpg">
</div>

Is possible to twist the beggining of a progress bar?

I can't figure out how to do this, is it really possible to twist the beggining of a progress bar with css, html, javascript or jquery without using images?
What I mean:
What I got so far (just a normal progress bar..):
#xp-bar{
top: 60%;
left: 5%;
height:10px;
width:90%;
background:#035;
border-radius: 5px;
/*margin:0px 0px 0px 15px;*/
display:inline-block;
vertical-align:middle;
position: absolute; }
#xp-bar-fill{
height:100%;
width:50.1%;
background-color:#d50000;
font-size:12px;
line-height:10px;
text-align:right; }
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 40px 40px; }
.progress-bar-striped.active {
-webkit-animation: progress-bar-stripes 2s linear infinite;
-o-animation: progress-bar-stripes 2s linear infinite;
animation: progress-bar-stripes 2s linear infinite;
}
#-webkit-keyframes progress-bar-stripes {
from { background-position: 40px 0; } to { background-position: 0 0; } }
#keyframes progress-bar-stripes {
from { background-position: 40px 0; } to { background-position: 0 0; } }
<div id='xp-bar'>
<div id='xp-bar-fill' class="progress-bar-striped active">
</div>
</div>
I just want to twist the beggining of that progress bar to be like the designs, I know how to do this with images but I wanted to know if it is really possible without them. Might be interested to a plugin if there's any
Like Rory McCrossan said, I've tried to do the two elements behaving like one and this is the result so far:
function doit(){
$("#xp-increase-fx").css("display","inline-block");
$("#xp-bar-fill").css("box-shadow",/*"0px 0px 15px #06f,*/ "-5px 0px 10px #fff inset");
$("#xp-circle-fill").css("box-shadow",/*"0px 0px 15px #06f,*/ "-5px 0px 10px #fff inset");
setTimeout(function(){
$("#xp-bar-fill").css("-webkit-transition","all 2s ease");
$("#xp-bar-fill").css("width","80%");
$("#xp-circle-fill").css("-webkit-transition","all 0.34s ease").css("width","100%");
},100);
setTimeout(function(){
$("#xp-increase-fx").fadeOut(500);
$("#xp-bar-fill").css({"-webkit-transition":"all 0.5s ease","box-shadow":""});
$("#xp-circle-fill").css({"-webkit-transition":"all 1s ease","box-shadow":""});
},2000);
setTimeout(function(){
$("#xp-bar-fill").css("width", "0.1%");
setTimeout(function(){ $("#xp-circle-fill").css("width", "0.1%"); },200);
},3000);
}
#xp-widget{
position:absolute;
top: 20%;
width: 310px;
left: 50%;
transform: translateX(-50%); }
#xp-bar,#xp-circle,#xp-ol-circle{
left: 16px;
height:10px;
width:92%;
background:#035;
border-radius: 5px;
overflow: hidden;
display:inline-block;
vertical-align:middle;
position: absolute; }
#xp-circle{
top: -18px;
left: 13px;
height: 50px;
width: 50px;
border-radius: 50%; }
#xp-ol-circle{
top: -9px;
left: 21px;
height: 33px;
width: 33px;
border-radius: 50%; }
#xp-bar-fill,#xp-circle-fill{
height:100%;
width:0.1%;
background-color:#d50000;
font-size:12px;
line-height:10px;
text-align:right; }
#xp-circle-fill{ width: 0.1%; border-radius: 50%; }
#xp-increase-fx{
position:relative;
display:none;
height:100%; }
.xp-increase-glow1{
position:absolute;
margin:0px 0px 0px -2px;
left:0px;
top:0px;
background:#fff;
width:5px;
height:100%;
border-radius:0px;
-webkit-filter:blur(2px); }
.xp-increase-glow2{
position:absolute;
margin:-5px 0px 0px -2px;
left:0px;
top:0px;
background:#aaf;
width:5px;
height:200%;
border-radius:0px;
-webkit-filter:blur(10px); }
.xp-increase-glow3{
position:absolute;
margin:0px 0px 0px -5px;
left:0px;
top:0px;
background:#fff;
width:10px;
height:100%;
border-radius:5px;
-webkit-filter:blur(5px); }
.progress-bar-striped {
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
background-size: 40px 40px; }
.progress-bar-striped.active {
-webkit-animation: progress-bar-stripes 2s linear infinite;
-o-animation: progress-bar-stripes 2s linear infinite;
animation: progress-bar-stripes 2s linear infinite; }
.mCharLvl {
top: 8px;
left: 1px;
width: 33px;
position: absolute;
color: #ffffff;
text-shadow: -1px 0px black, 1px 0px black, 0px 1px black, 0px -1px black, 1px 1px black, 2px 2px #000000; }
.debugTest { top: 20%; position: absolute; }
#-webkit-keyframes progress-bar-stripes {
from { background-position: 40px 0; } to { background-position: 0 0; } }
#keyframes progress-bar-stripes {
from { background-position: 40px 0; } to { background-position: 0 0; } }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="xp-widget">
<tr>
<th id='xp-bar'>
<div id='xp-bar-fill' class="progress-bar-striped active">
<div id='xp-increase-fx'>
<div id='xp-increase-fx-flicker'>
<div class='xp-increase-glow1'></div>
<div class='xp-increase-glow2'></div>
<div class='xp-increase-glow3'></div>
</div>
<div class='xp-increase-glow2'></div>
</div>
</div>
</th>
<th id="xp-circle">
<div id='xp-circle-fill' class="progress-bar-striped active">
<div id='xp-increase-fx'>
<div id='xp-increase-fx-flicker'>
<div class='xp-increase-glow1'></div>
<div class='xp-increase-glow2'></div>
<div class='xp-increase-glow3'></div>
</div>
<div class='xp-increase-glow2'></div>
</div>
</div>
</th>
<th id="xp-ol-circle"><span id="mCharLevel" class="mCharLvl">7</span></th>
</tr>
</table>
<button class="debugTest" onclick="doit()">Try Me !</button>
But I will finally try Svg like Nathaniel Flick suggested, useful to be able to use a predefined path and I would say it's the better approach as I want the progress bar following a path that otherwise seems impossible or very tricky to do
Thanks for your suggestions!

Animated offset border css? javascript?

Attached you'll find an image explaining what i'd like to accomplish.
I would like to have my background set, over that I would like to have a border that's a bit offset from the background. In some way I need to find a way to animate every single side of the border by it's own.
I would like the top border to animate in from the right, the bottom one from the left. The left one from the bottom and the right one from the top.
This is giving me a big headache. Anybody have any ideas?
What I've done is:
<div id="#mainsection"></div>
The border is created in CSS:
#mainsection:after {
content: '';
position: absolute;
top: 40px;
right: 40px;
bottom: 40px;
left: 40px;
border: 4px solid #96896C;
}
What I've realised is that this is not going to work as I need every border-part as separate items.
You could perhaps use linear gradients and a couple of ::before and ::after pseudo elements. This wont give you entirely separate animations but the horizontal and vertical borders can be animated separately.
body, html {
height: 100%;
}
#mainsection {
height: 100%;
position: relative;
background: url(https://placehold.it/1000x1000) center center;
}
#mainsection:after {
content: '';
position: absolute;
top: 40px;
right: 40px;
bottom: 40px;
left: 40px;
background-image: linear-gradient(black, black), linear-gradient(transparent, transparent), linear-gradient(black, black);
background-repeat: no-repeat;
background-size: 2px 0%, calc(100% - 4px) 100%, 2px 0%;
background-position: left bottom, 0 0, right top;
transition: background-size 1.5s ease;
}
#mainsection:before {
content: '';
position: absolute;
top: 40px;
right: 40px;
bottom: 40px;
left: 40px;
background-image: linear-gradient(black, black), linear-gradient(transparent, transparent), linear-gradient(black, black);
background-repeat: no-repeat;
background-size: 0% 2px, calc(100% - 4px) 100%, 0% 2px;
background-position: left bottom, 0 0, right top;
transition: background-size 2s ease .5s; /* .5s delay */
}
#mainsection:hover:after {
background-size: 2px 100%, calc(100% - 4px) 100%, 2px 100%;
}
#mainsection:hover:before {
background-size: 100% 2px, calc(100% - 4px) 100%, 100% 2px;
}
<div id="mainsection"></div>
A similar solution to #Turnip but by simply using multiple gradient on the same div. And you can control the animation of each one by playing with initial and final values of background-size and background-position:
body {
margin:0;
}
.container {
height: 100vh;
padding:40px;
background:
linear-gradient(#000,#000) top right content-box,
linear-gradient(#000,#000) top right content-box,
linear-gradient(#000,#000) bottom left content-box,
linear-gradient(#000,#000) bottom left content-box,
url(https://placehold.it/1000x1000) center center;
background-size:0 3px,3px 0,0 3px,3px 0,auto;
background-repeat:no-repeat;
transition:2s;
box-sizing:border-box;
}
.container:hover {
background-size:
100% 3px,
3px 100%,
100% 3px,
3px 100%,
auto; /* This is for image */
}
<div class="container"></div>
Then simply adjust the position to control the animation:
body{
margin:0;
}
.container {
height: 100vh;
padding:40px;
background:
linear-gradient(#000,#000) top left content-box,
linear-gradient(#000,#000) top right content-box,
linear-gradient(#000,#000) bottom right content-box,
linear-gradient(#000,#000) bottom left content-box,
url(https://placehold.it/1000x1000) center center;
background-size:0 3px,3px 0,0 3px,3px 0,auto;
background-repeat:no-repeat;
transition:2s;
box-sizing:border-box;
}
.container:hover {
background-size:
100% 3px,
3px 100%,
100% 3px,
3px 100%,
auto; /* This is for image */
}
<div class="container"></div>
Another one:
body {
margin:0
}
.container {
height: 100vh;
padding:40px;
background:
linear-gradient(#000,#000) top content-box,
linear-gradient(#000,#000) right content-box,
linear-gradient(#000,#000) bottom content-box,
linear-gradient(#000,#000) left content-box,
url(https://placehold.it/1000x1000) center center;
background-size:0 3px,3px 0,0 3px,3px 0,auto;
background-repeat:no-repeat;
transition:2s;
box-sizing:border-box;
}
.container:hover {
background-size:
100% 3px,
3px 100%,
100% 3px,
3px 100%,
auto; /* This is for image */
}
<div class="container"></div>

Categories