I have a position:relative
green ring with a position:absolute
red clone :before
and a position:absolute
white clone
In your radial progress bar scenario, you can use the approach described here : Circular percent progress bar. Using inline svg and animating the stroke-dasharray attribute for the progress bar.
Adapted to your use case, it can look like this:
body{background:lavender;}
svg{width:200px;height:200px;}
<svg viewbox="-2.5 -2.5 105 105">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="#fff"/>
<path fill="none" stroke-width="25" stroke="tomato" stroke-dasharray="251.2,0" d="M50 10 a 40 40 0 0 1 0 80 a 40 40 0 0 1 0 -80">
<animate attributeName="stroke-dasharray" from="0,251.2" to="251.2,0" dur="5s"/>
</path>
</svg>
Note that in this example the animation is made with SMIL. But you can also do it with JS as descirbed in the radial progress bar answer.
Previous answer:
If your aim is to remove the bleed, one solution would be to hide it by making the pseudo elements border wider.
Depending on your actual use case this solution can be apropriate.
Here is an example :
body{background:lavender}
#ring {
position: relative;
width: 100px;
height: 100px;
border-radius: 50%;
border: 50px solid green;
}
#ring:before {
content: '';
position: absolute;
top: -51px;
left: -51px;
width: 98px;
height: 98px;
border: 52px solid red;
border-radius: 50%;
}
#ring:after {
content: '';
position: absolute;
top: -52px;
left: -52px;
width: 96px;
height: 96px;
border-radius: 50%;
border: 54px solid white;
}
<div id="ring"></div>
The reason for the problem is antialiasng in the limiting (border) pixels. To make the border of the circle less pixelated, the pixels that are only half-way inside the circle are rendered semitransparents.
The problem is that the circle under the top one is also rendering semitransparent pixels. (in another color, of course). So, half transparent white is rendered on top of semitransparent red (that is rendered on top of semitransparent green).
The net result is that the pixel is not pure white.
To solve the root of the problem, you would need to turn off antialiasing, that AFAIK is not posible with borders (only text, and images under develoopment). Besides, such a solution would make the circle quite ugly
To mitigate it, you can do several hacks, with sizes, shadows, or whatever.
For another way to solve your original issue in CSS, (besides the excellent one that you already have using SVG) see this answer.
On the right side of the following snippet is the result of the @web-tiki svg ring with 2 clones of the same size/place (but different colors) with the anti-aliasing disabled (shape-rendering="crispEdges"
) just like @vals have mentioned:
body {
background: lavender;
margin: 0;
overflow: hidden;
}
div {
width: 200px;
height: 200px;
display: inline-block;
position: relative;
}
svg {
width: 200px;
height: 200px;
position: absolute;
top: 0;
left: 0;
}
span {
font-family: arial, sans-serif;
text-align: center;
position: absolute;
left: 0;
right: 0;
margin: auto;
top: 45%;
}
<div>
<svg viewbox="-2.5 -2.5 105 105">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="green"/>
</svg>
<svg viewbox="-2.5 -2.5 105 105">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="tomato"/>
</svg>
<svg viewbox="-2.5 -2.5 105 105">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="#fff"/>
</svg><span><small>shape-rendering="auto"</small></span>
</div><div>
<svg viewbox="-2.5 -2.5 105 105" shape-rendering="crispEdges">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="green"/>
</svg>
<svg viewbox="-2.5 -2.5 105 105" shape-rendering="crispEdges">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="tomato"/>
</svg>
<svg viewbox="-2.5 -2.5 105 105" shape-rendering="crispEdges">
<circle cx="50" cy="50" r="40" fill="transparent" stroke-width="25" stroke="#fff"/>
</svg><span><small>shape-rendering="crispEdges"</small></span>
</div>
Since the OP example uses the :before
and :after
pseudo-elements, I have tried to apply this same shape-rendering="crispEdges"
on the svg clip-path, but had no success in any browser: Link
Source: MDN