Progress Bar Along The Borders Of A Rectangle
Solution 1:
Pure CSS:
This effect can be achieved with CSS using multiple linear gradients as background and positioning them appropriately. The approach is as follows:
- Create 4 thin
linear-gradient
backgrounds for each border of the element. The thickness of the border determines thebackground-size
. That is, if border thickness is 5px then the linear gradients that produce the top and bottom borders would be100% 5px
(100% width 5px height) whereas those that produce left and right borders would be5px 100%
(3px width 100% height). - Initially the
background-position
is set such that none of the borders would be visible. During animation we animate each of the background gradients into its correct position. This produces the effect of having an animated border.
I have used CSS keyframes in the below snippet and so it automatically animates from start to end (that is, it stops only after full border is painted) but if you wish to have more control over it (and say stop it midway as in a progress bar) then you could use JS and modify background-position
based on the percentage of progress.
.progress {
height: 300px;
width: 500px;
background: linear-gradient(to right, black 99.99%, transparent), linear-gradient(to bottom, black 99.99%, transparent), linear-gradient(to right, black 99.99%, transparent), linear-gradient(to bottom, black 99.99%, transparent);
background-size: 100%5px, 5px100%, 100%5px, 5px100%;
background-repeat: no-repeat;
animation: progress 4s linear forwards;
background-position: -500px0px, 495px -300px, 500px295px, 0px300px;
}
@keyframes progress {
0% {
background-position: -500px0px, 495px -300px, 500px295px, 0px300px;
}
25% {
background-position: 0px0px, 495px -300px, 500px295px, 0px300px;
}
50% {
background-position: 0px0px, 495px0px, 500px295px, 0px300px;
}
75% {
background-position: 0px0px, 495px0px, 0px295px, 0px300px;
}
100% {
background-position: 0px0px, 495px0px, 0px295px, 0px0px;
}
}
<!-- prefix free library is only to avoid browser prefixes --><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><divclass="progress"></div>
CSS version without automatic animation:
Here is the CSS version of the snippet which accepts an input percentage value and sets the border based on that. Provide a value between 0 and 100 in the text box and click Enter.
window.onload = function() {
var progress = document.querySelector('.progress'),
totalLength = (progress.offsetWidth * 2) + (progress.offsetHeight * 2);
var btn = document.querySelector('#enter'),
progressVal = document.querySelector('#progress');
btn.addEventListener('click', function() {
input = (progressVal.value > 100) ? 100 : progressVal.value;
borderLen = (input / 100) * totalLength;
console.log(borderLen);
if (borderLen <= progress.offsetWidth) {
backgroundPos = 'background-position: ' + (-500 + borderLen) + 'px 0px, 495px -300px, 500px 295px, 0px 300px';
progress.setAttribute('style', backgroundPos);
} elseif (borderLen <= (progress.offsetWidth + progress.offsetHeight)) {
backgroundPos = 'background-position: 0px 0px, 495px ' + (-300 + (borderLen - progress.offsetWidth)) + 'px, 500px 295px, 0px 300px';
progress.setAttribute('style', backgroundPos);
} elseif (borderLen <= (progress.offsetWidth * 2 + progress.offsetHeight)) {
backgroundPos = 'background-position: 0px 0px, 495px 0px, ' + (500 - (borderLen - progress.offsetWidth - progress.offsetHeight)) + 'px 295px, 0px 300px';
progress.setAttribute('style', backgroundPos);
} else {
backgroundPos = 'background-position: 0px 0px, 495px 0px, 0px 295px, 0px ' + (300 - (borderLen - (progress.offsetWidth * 2) - progress.offsetHeight)) + 'px';
progress.setAttribute('style', backgroundPos);
}
});
};
.progress {
height: 300px;
width: 500px;
margin-top: 20px;
background: linear-gradient(to right, black 99.99%, transparent), linear-gradient(to bottom, black 99.99%, transparent), linear-gradient(to right, black 99.99%, transparent), linear-gradient(to bottom, black 99.99%, transparent);
background-size: 100%5px, 5px100%, 100%5px, 5px100%;
background-repeat: no-repeat;
background-position: -500px0px, 495px -300px, 500px295px, 0px300px;
}
<!-- prefix free library is only to avoid browser prefixes --><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script><inputid='progress'type='text' /><buttonid='enter'>Set Progress</button><divclass="progress"></div>
With SVG:
With SVG, the approach would be as follows:
- Create a single
path
element such that it forms the border of the boxand get its length using thegetTotalLength()
method. - Set the
stroke-dasharray
andstroke-dashoffset
properties of thepath
such that the path is invisible initially. - By modifying the
stroke-dashoffset
based on the percentage of progress we can produce a progress bar like effect.
Again I have used animations to automatically trigger the movement from start to finish but if you want a progress bar like effect, you can remove the animation and just set the offset based on percentage of progress.
window.onload = function() {
var progress = document.querySelector('.progress path');
var borderLen = progress.getTotalLength() + 5,
offset = borderLen;
progress.style.strokeDashoffset = borderLen;
progress.style.strokeDasharray = borderLen + ',' + borderLen;
anim = window.requestAnimationFrame(progressBar);
functionprogressBar() {
offset -= 1;
progress.style.strokeDashoffset = offset;
anim = window.requestAnimationFrame(progressBar);
if (offset < 0)
window.cancelAnimationFrame(anim);
}
};
.progress {
height: 300px;
width: 500px;
}
.progress svg {
height: 100%;
width: 100%;
}
path {
stroke: black;
stroke-width: 5;
fill: none;
}
<divclass="progress"><svgviewBox='0 0 510 310'preserveAspectRatio='none'><pathd='M5,5 505,5 505,305 5,305 5,2.5' /><!-- end is start point - stroke width/2 --></svg></div>
SVG version without automatic animation:
Here is the SVG version of the snippet which accepts an input percentage value and sets the border based on that. Provide a value between 0 and 100 in the text box and click Enter.
window.onload = function() {
var progress = document.querySelector('.progress path');
var borderLen = progress.getTotalLength() + 5,
offset;
progress.style.strokeDashoffset = borderLen;
progress.style.strokeDasharray = borderLen + ',' + borderLen;
var btn = document.querySelector('#enter'),
progressVal = document.querySelector('#progress');
btn.addEventListener('click', function(){
input = (progressVal.value > 100) ? 100 : progressVal.value;
offsetToSet = (input/100) * borderLen;
console.log(borderLen - offsetToSet);
progress.style.strokeDashoffset = borderLen - offsetToSet;
});
};
.progress {
height: 300px;
width: 500px;
}
.progress svg {
height: 100%;
width: 100%;
}
path {
stroke: black;
stroke-width: 5;
fill: none;
}
<inputid='progress'type='text'/><buttonid='enter'>Set Progress</button><divclass="progress"><svgviewBox='0 0 510 310'preserveAspectRatio='none'><pathd='M5,5 505,5 505,305 5,305 5,2.5' /><!-- end is start point - stroke width/2 --></svg></div>
Post a Comment for "Progress Bar Along The Borders Of A Rectangle"