Partially fill the border of the form with color

I am trying to create a progress effect in which color fills the border of a DOM object (or perhaps a background). The attached image should give you a better idea of ​​what I'm going for. I got the current result by adding an object with a solid background color over the gray lines and setting its height. This object has to it mix-blend-mode: color-burn;, so it only colors the gray lines below it.

This works fine, but destroys the smoothing around the circle, and the color produced is unpredictable (varies depending on the color of the lines).

I believe that there should be a better way to achieve this, perhaps with a canvas element. Can someone point me in the right direction?

Thanks in advance!

Example

+4
source share
1 answer

It should be possible to do this with Canvas, and even possibly using CSS itself, playing with multiple elements, etc., but I definitely recommend you use SVG. SVG offers many advantages in terms of how easy it is to code, maintain, and also produce responsive outputs (as opposed to Canvas, which tends to pixelize when scaled).

The following are the components:

  • A rect, which is the same size as the parent svg, and has padding linear-gradient. The gradient has two colors: one is the base (light gray), and the other is progress (blue).
  • A mask, rect. path, , . mask rect, path ( ) rect, rect, mask.
  • mask text .
  • linear-gradient stop offset, , . offset, , path (-) .

window.onload = function() {
  var progress = document.querySelector('#progress'),
    base = document.querySelector('#base'),
    prgText = document.querySelector('#prg-text'),
    prgInput = document.querySelector('#prg-input');
  prgInput.addEventListener('change', function() {
    prgText.textContent = this.value + '%';
    progress.setAttribute('offset', this.value + '%');
    base.setAttribute('offset', this.value + '%');
  });
}
svg {
  width: 200px;
  height: 300px;
}
path {
  stroke-width: 4;
}
#rect {
  fill: url(#grad);
  mask: url(#path);
}

/* just for demo */
.controls {
  position: absolute;
  top: 0;
  right: 0;
  height: 100px;
  line-height: 100px;
  border: 1px solid;
}
.controls * {
  vertical-align: middle;
}

body {
  background-image: radial-gradient(circle, #3F9CBA 0%, #153346 100%);
}
<svg viewBox='0 0 200 300' id='shape-container'>
  <linearGradient id='grad' gradientTransform='rotate(90 0 0)'>
    <stop offset='50%' stop-color='rgb(0,218,235)' id='progress' />
    <stop offset='50%' stop-color='rgb(238,238,238)' id='base' />
  </linearGradient>
  <mask id='path' maskUnits='userSpaceOnUse' x='0' y='0' width='200' height='300'>
    <rect x='0' y='0' width='200' height='300' fill='black' />
    <path d='M100,0 100,100 A50,50 0 0,0 100,200 L100,300 M100,200 A50,50 0 1,0 100,100' stroke='white' />
    <text id='prg-text' x='100' y='155' font-size='20' text-anchor='middle' fill='white'>50%</text>
  </mask>
  <rect id='rect' x='0' y='0' width='200' height='300' />
</svg>

<!-- just for demo -->
<div class='controls'>
  <label>Set Progress:</label>
  <input type='range' id='prg-input' min='0' max='100' value='50' />
</div>
Hide result

SVG, MDN (, ) , ​​.

+4

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


All Articles