部分填充形状的边框颜色

4
我正在尝试创建一种进度效果,其中颜色填充DOM对象的边框(或可能是背景)。附图应该能让你更好地理解我的想法。我通过添加一个带有纯色背景的对象并设置其高度来实现当前结果。此对象应用了mix-blend-mode: color-burn;,这就是为什么它只着色了它下面的灰线。

这个方法还可以,但会破坏圆形周围的抗锯齿效果,并且产生的颜色是不可预测的(取决于线条的颜色)。

我觉得一定有更好的方法来实现这一点,也许可以使用canvas元素。请问有人能指点我一下吗?

提前感谢!

Example


2
创建两个重复的div,将顶部颜色版本设置为隐藏,并相应地调整高度。 - David Nguyen
啊,我明白你的意思了。我会试一试的! - Ben Guest
渐变?背景:线性渐变(向下,#7db9e8 50%,#1e5799 50%); - Sergio Tx
我不确定是否可以使用渐变,因为圆是另一个对象放在线的上面。为线设置背景可能可行,但我不确定当颜色到达圆时如何为圆设置背景。同样的原因,文本也会成为问题。 - Ben Guest
1个回答

5
这应该可以使用 Canvas 实现,甚至使用 CSS 本身也可能通过操作多个元素等来实现,但我强烈建议您使用 SVG。SVG 在编写、维护和生成响应式输出方面都具有很多优点(与 Canvas 不同,当缩放时 Canvas 往往会变得像素化)。
以下是组件:
- 一个 rect 元素,其大小与父 svg 相同,并具有线性渐变填充。渐变有两种颜色 - 一种是基色(浅灰色),另一种是进度色(青色)。 - 应用于 rect 元素的 mask。掩码具有一个路径,这只是线条和圆形。当将掩码应用于 rect 时,只有此 path 会显示在 rect 的实际背景(或填充)中,其他区域将被添加到 mask 中的另一个 rect 掩盖。 - mask 还具有一个 text 元素,用于显示进度值。 - linear-gradientstop 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>


如果您对SVG不熟悉,可以参考以下MDN文档了解更多关于元素、属性和值的信息。

1
这听起来非常有前途!感谢您抽出时间进行解释。 - Ben Guest
不客气,@BenGuest。很高兴能帮到你。我也将SVG标签添加到问题中。希望你对此没有任何疑虑 :) - Harry
1
没问题,@Harry!再次感谢 :) - Ben Guest
1
与Canvas不同,当进行缩放时,它往往会变得像素化,更像是保证会变得像素化,因为它不是基于矢量的SVG。 :) - John Weisz
@JohnWhite:哦,是的,你说得对。虽然可以通过在窗口调整大小时重新绘制整个内容来克服这个问题,但与使用SVG轻松完成的工作相比,这太费力了。 - Harry

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接