Lane along the borders of the rectangle

I am trying to figure out how to implement a progressbar around a rectangle. Suppose I have a div 500x300 with a border of 5px (black).

I would like the progress indicator to start in the upper left corner, then move to โ†’ right corner โ†’ lower right corner โ†’ lower left corner โ†’ and return to the starting point.

The execution line around the rectangle

+5
source share
1 answer

Pure CSS:

This effect can be achieved using CSS using several linear gradients as the background and corresponding positioning. This approach is as follows:

  • Create 4 subtle linear-gradient backgrounds for each border of the element. The thickness of the border determines the background-size . That is, if the border thickness is 5 pixels, then the linear gradients that form the upper and lower borders will be 100% 5px (height 100% 5 pixels), while those that produce the left and right borders will be 5px 100% (3px width 100% of height).
  • Initially, the background-position set so that no border is visible. During the animation, we animate each of the background gradients to the correct position. This creates the effect of having an animated border.

I used the CSS keywords in the snippet below and therefore it automatically animates from start to finish (i.e. it stops only after the full frame is painted), but if you want to have more control over it (and, say stop it halfway as in the progress bar), you can use JS and change the 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, 5px 100%, 100% 5px, 5px 100%; background-repeat: no-repeat; animation: progress 4s linear forwards; background-position: -500px 0px, 495px -300px, 500px 295px, 0px 300px; } @keyframes progress { 0% { background-position: -500px 0px, 495px -300px, 500px 295px, 0px 300px; } 25% { background-position: 0px 0px, 495px -300px, 500px 295px, 0px 300px; } 50% { background-position: 0px 0px, 495px 0px, 500px 295px, 0px 300px; } 75% { background-position: 0px 0px, 495px 0px, 0px 295px, 0px 300px; } 100% { background-position: 0px 0px, 495px 0px, 0px 295px, 0px 0px; } } 
 <!-- prefix free library is only to avoid browser prefixes --> <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script> <div class="progress"></div> 

CSS version without automatic animation:

Here is a CSS version of the snippet that takes a percentage of input and sets a border based on this. In the text box, enter a value from 0 to 100 and press "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); } else if (borderLen <= (progress.offsetWidth + progress.offsetHeight)) { backgroundPos = 'background-position: 0px 0px, 495px ' + (-300 + (borderLen - progress.offsetWidth)) + 'px, 500px 295px, 0px 300px'; progress.setAttribute('style', backgroundPos); } else if (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, 5px 100%, 100% 5px, 5px 100%; background-repeat: no-repeat; background-position: -500px 0px, 495px -300px, 500px 295px, 0px 300px; } 
 <!-- prefix free library is only to avoid browser prefixes --> <script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script> <input id='progress' type='text' /> <button id='enter'>Set Progress</button> <div class="progress"></div> 

With SVG:

With SVG, the approach would be:

  • Create one path element so that it forms the border of the field and getTotalLength() its length using the getTotalLength() method.
  • Set stroke-dasharray and stroke-dashoffset path property, so the path is invisible first.
  • By changing the stroke-dashoffset based on the percentage of progress, we can create a progress bar as an effect.

Again, I used animation to automatically start moving from start to finish, but if you need a progress bar, such as an effect, you can remove the animation and just set the offset based on the 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); function progressBar() { 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; } 
 <div class="progress"> <svg viewBox='0 0 510 310' preserveAspectRatio='none'> <path d='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 a version of the SVG fragment that takes an input percentage value and sets a border based on this. In the text box, enter a value from 0 to 100 and press "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; } 
 <input id='progress' type='text'/> <button id='enter'>Set Progress</button> <div class="progress"> <svg viewBox='0 0 510 310' preserveAspectRatio='none'> <path d='M5,5 505,5 505,305 5,305 5,2.5' /> <!-- end is start point - stroke width/2 --> </svg> </div> 
+9
source

Source: https://habr.com/ru/post/1012003/


All Articles