SVG path with border - css

How can I create a path with a fill and outline similar to
So far I have found a couple of ways but none that is particularly clean.
One way would be to use paint-order but this does not work in mobile and IE.
Another way duplicate the path... but this would create needless amounts of data.
Is there a different way to use CSS to simply create an outline or border for an SVG path?
<svg height="50" width="300">
<path d="M5 20 1215 20" />
</svg>
path {
fill: red;
stroke: #646464;
stroke-width:10px;
stroke-linejoin: round;
}
Here is a codepen

You have to draw the path as an outline as so:
<svg xmlns="http://www.w3.org/2000/svg" width="220" height="220" viewBox="0 0 220 220">
<path fill="#ddd" stroke="#3f4141" d="M0 0h220v220H0z"/>
<path fill="#fff" stroke="#00b400" stroke-width="4"
d="M 159.8 30.3
h -110
v 120
h-20
l 30 40
30 -40
h-20
v-100
h90"/>
</svg>
Sketched in Inkscape, optimised in SVGOMG then tweaked by hand.
EDIT
I have a working solution using markers that works as follows:
Create the line (any line) as a symbol
Create a faux - stroke by layering two instances of the line on top of each other, with different line widths
Add arrow with pre-defined stroke as marker
Hairline stroke shows through sometimes at start of line ... solve this using another marker that masks using the background color.
this technique would only work over a plain background.
<svg style="display: inline-block; margin-left: 2em;" width="220" height="220" viewBox="0 0 220 220" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<style>
.arrow-stroke {
stroke: #00b400;
stroke-width: 28;
/* marker-end etc should be supported but unsure of browser support */
}
.arrow-fill {
stroke: white;
stroke-width: 20
}
</style>
<marker id="arrow" markerWidth="45" markerHeight="70" refX="5" refY="35" orient="auto" markerUnits="userSpaceOnUse">
<path fill="#fff" stroke="#00b400" stroke-width="4" d="M 2 25 v-20 l 40,30 -40,30 v-20"/>
</marker>
<!-- Used to hide hairline that shows through, fill color must match background color -->
<marker id="startMask" markerWidth="2" markerHeight="30" refX="1" refY="15" orient="auto" markerUnits="userSpaceOnUse">
<path fill="#ddd" d="M0 0 v30 h2 v-30 z" />
</marker>
<symbol id="line">
<path d="M 159.8 30.3 h -110 v 120"/>
</symbol>
<symbol id="line2">
<path d="M 140 60 l 20 30"/>
</symbol>
<symbol id="line3">
<path d="M 100 80 q 0 40 20 70"/>
</symbol>
</defs>
<path id="grey-box" fill="#ddd" stroke="#3f4141" d="M0 0h220v220H0z"/>
<g fill="none">
<use xlink:href="#line" class="arrow-stroke" />
<use xlink:href="#line" class="arrow-fill" marker-end="url(#arrow)" marker-start="url(#startMask)" />
<use xlink:href="#line2" class="arrow-stroke" />
<use xlink:href="#line2" class="arrow-fill" marker-end="url(#arrow)" marker-start="url(#startMask)" />
<use xlink:href="#line3" class="arrow-stroke" />
<use xlink:href="#line3" class="arrow-fill" marker-end="url(#arrow)" marker-start="url(#startMask)" />
</g>
</svg>
Hope this helps

Related

Before pseudo element not showing up on path element

Hi i am trying to create a 'pin' on a SVG map of the whole world, the SVG is build with path elements, my thought was to use a before or after element and show the pin accordingly.
Apparently it is not showing on the path element, i can see it in the debugger/console and if i put it on a div element it works fine and shows up, i have cut out all countries except the first one in the SVG for simplicity.
CSS
.map-pin::after{
content: url('pin.svg');
background-size: 30px 30px;
background-repeat: no-repeat;
background-position: left top;
width: 30px;
height: 30px;
z-index: 10;
font-size: 1px;
display: inline-block;
position: absolute;
left: -999px;
top: -999px;
/*display: none;*/
}
.map-pin.active::after{
display: block;
}
.map-pin.active[data-id="AF"]::after{
top: 0;
left: 0;
}
SVG
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" style="stroke-linejoin: round; stroke:#000; fill: none;" viewBox="0 0 2000 1001" id="svg2" inkscape:version="0.48.4 r9939" sodipodi:docname="world.svg">
<defs id="defs4">
<style type="text/css" id="style6">path { fill-rule: evenodd; }</style>
</defs>
<g id="countries">
<path id="AF" data-name="Afghanistan" data-id="AF" class="map-pin active" d="m 1369.9,333.8 -5.4,0 -3.8,-0.5 -2.5,2.9 -2.1,0.7 -1.5,1.3 -2.6,-2.1 -1,-5.4 -1.6,-0.3 0,-2 -3.2,-1.5 -1.7,2.3 0.2,2.6 -0.6,0.9 -3.2,-0.1 -0.9,3 -2.1,-1.3 -3.3,2.1 -1.8,-0.8 -4.3,-1.4 -2.9,0 -1.6,-0.2 -2.9,-1.7 -0.3,2.3 -4.1,1.2 0.1,5.2 -2.5,2 -4,0.9 -0.4,3 -3.9,0.8 -5.9,-2.4 -0.5,8 -0.5,4.7 2.5,0.9 -1.6,3.5 2.7,5.1 1.1,4 4.3,1.1 1.1,4 -3.9,5.8 9.6,3.2 5.3,-0.9 3.3,0.8 0.9,-1.4 3.8,0.5 6.6,-2.6 -0.8,-5.4 2.3,-3.6 4,0 0.2,-1.7 4,-0.9 2.1,0.6 1.7,-1.8 -1.1,-3.8 1.5,-3.8 3,-1.6 -3,-4.2 5.1,0.2 0.9,-2.3 -0.8,-2.5 2,-2.7 -1.4,-3.2 -1.9,-2.8 2.4,-2.8 5.3,-1.3 5.8,-0.8 2.4,-1.2 2.8,-0.7 -1.4,-1.9 z" style="fill:#f2f2f2;fill-rule:evenodd"></path>
</g>
</svg>
I also tried a more simple way by just adding an element inside the SVG after all the path elements, but this breaks the whole SVG.
Anyone able to help me out here, is it not possible in SVG path elements? and if so, what other options am i left with?
PIN:
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" style="enable-background:new 0 0 512 512;" viewBox="0 0 512 512" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#454545;stroke-width:18;stroke-miterlimit:10;}
</style>
<g>
<g id="XMLID_4245_">
<path class="st0" d="M389.3,208.7c0-73.6-59.7-133.3-133.3-133.3c-73.6,0-133.3,59.7-133.3,133.3 c0,32.6,12.1,62,31.5,85.1l55.3,75.4l46.6,67.5l101.8-142.9C377.2,270.7,389.3,241.2,389.3,208.7z" id="XMLID_4247_"></path>
<path class="st0" d="M311,170.9L311,170.9c-12.1-11.6-31.7-11.6-43.8,0l-10.9,10.5L245.3,171 c-12.1-11.6-31.7-11.6-43.8,0c-12.1,11.6-12.1,30.4,0,42l54.7,52.5L311,213C323.1,201.4,323.1,182.6,311,170.9z" id="XMLID_4246_"></path>
</g>
</g>
</svg>
As I've commented you can't have a before pseudo element for a path. However in your case you can have a symbol for the pin and use it at the end of your document. This way it will stay above all the other paths. (a z-index won't work either in SVG).
If you are using a symbol with a viewBox attribute you can give the <use> element a position (x and y attributes) and a size (width and height attributes)
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" style="stroke-linejoin: round; stroke:#000; fill: none;" viewBox="1280 320 100 100" id="svg2" >
<defs id="defs4">
<style type="text/css" id="style6">path { fill-rule: evenodd; }</style>
</defs>
<symbol id="map-pin-after" viewBox="0 0 30 30">
<circle cx="15" cy="8" r="8" /> <polygon points="15,30 22.7,10 7.3,10 15,30"/>
</symbol>
<g id="countries">
<path id="AF" data-name="Afghanistan" data-id="AF" class="map-pin active" d="m 1369.9,333.8 -5.4,0 -3.8,-0.5 -2.5,2.9 -2.1,0.7 -1.5,1.3 -2.6,-2.1 -1,-5.4 -1.6,-0.3 0,-2 -3.2,-1.5 -1.7,2.3 0.2,2.6 -0.6,0.9 -3.2,-0.1 -0.9,3 -2.1,-1.3 -3.3,2.1 -1.8,-0.8 -4.3,-1.4 -2.9,0 -1.6,-0.2 -2.9,-1.7 -0.3,2.3 -4.1,1.2 0.1,5.2 -2.5,2 -4,0.9 -0.4,3 -3.9,0.8 -5.9,-2.4 -0.5,8 -0.5,4.7 2.5,0.9 -1.6,3.5 2.7,5.1 1.1,4 4.3,1.1 1.1,4 -3.9,5.8 9.6,3.2 5.3,-0.9 3.3,0.8 0.9,-1.4 3.8,0.5 6.6,-2.6 -0.8,-5.4 2.3,-3.6 4,0 0.2,-1.7 4,-0.9 2.1,0.6 1.7,-1.8 -1.1,-3.8 1.5,-3.8 3,-1.6 -3,-4.2 5.1,0.2 0.9,-2.3 -0.8,-2.5 2,-2.7 -1.4,-3.2 -1.9,-2.8 2.4,-2.8 5.3,-1.3 5.8,-0.8 2.4,-1.2 2.8,-0.7 -1.4,-1.9 z" fill="#f2f2f2"></path>
</g>
<use xlink:href="#map-pin-after" stroke="none" fill="red" width="30" height="30" x="1310" y="327"/>
</svg>
UPDATE
An update where I'm using the OP's pin:
Since the new pin is not a square, and in order to preserve the aspect ratio, I had to recalculate the height of the pin.
<svg viewBox="1280 320 100 100" >
<defs>
<symbol id="map-pin-after" viewBox="111 60 290 397">
<g id="XMLID_4245_" fill="none" stroke="#454545" stroke-width="18" stroke-mitterlimit="10">
<path d="M389.3,208.7c0-73.6-59.7-133.3-133.3-133.3c-73.6,0-133.3,59.7-133.3,133.3 c0,32.6,12.1,62,31.5,85.1l55.3,75.4l46.6,67.5l101.8-142.9C377.2,270.7,389.3,241.2,389.3,208.7z" ></path>
<path d="M311,170.9L311,170.9c-12.1-11.6-31.7-11.6-43.8,0l-10.9,10.5L245.3,171 c-12.1-11.6-31.7-11.6-43.8,0c-12.1,11.6-12.1,30.4,0,42l54.7,52.5L311,213C323.1,201.4,323.1,182.6,311,170.9z" ></path>
</g>
</symbol>
</defs>
<g id="countries">
<path id="AF" data-name="Afghanistan" data-id="AF" class="map-pin active" d="m 1369.9,333.8 -5.4,0 -3.8,-0.5 -2.5,2.9 -2.1,0.7 -1.5,1.3 -2.6,-2.1 -1,-5.4 -1.6,-0.3 0,-2 -3.2,-1.5 -1.7,2.3 0.2,2.6 -0.6,0.9 -3.2,-0.1 -0.9,3 -2.1,-1.3 -3.3,2.1 -1.8,-0.8 -4.3,-1.4 -2.9,0 -1.6,-0.2 -2.9,-1.7 -0.3,2.3 -4.1,1.2 0.1,5.2 -2.5,2 -4,0.9 -0.4,3 -3.9,0.8 -5.9,-2.4 -0.5,8 -0.5,4.7 2.5,0.9 -1.6,3.5 2.7,5.1 1.1,4 4.3,1.1 1.1,4 -3.9,5.8 9.6,3.2 5.3,-0.9 3.3,0.8 0.9,-1.4 3.8,0.5 6.6,-2.6 -0.8,-5.4 2.3,-3.6 4,0 0.2,-1.7 4,-0.9 2.1,0.6 1.7,-1.8 -1.1,-3.8 1.5,-3.8 3,-1.6 -3,-4.2 5.1,0.2 0.9,-2.3 -0.8,-2.5 2,-2.7 -1.4,-3.2 -1.9,-2.8 2.4,-2.8 5.3,-1.3 5.8,-0.8 2.4,-1.2 2.8,-0.7 -1.4,-1.9 z" fill="#f2f2f2" stroke="black"></path>
</g>
<use xlink:href="#map-pin-after" stroke="none" fill="red" width="41" height="30" x="1305" y="327"/>
</svg>

SVG "vector-effect: non-scaling-stroke" in <marker>: Firefox vs Chrome

Consider the following snippet, which contains two versions of an SVG with an arrowhead defined by a <marker>. Lines and paths are styled with vector-effect: non-scaling-stroke. The second version is simply the first version with all coordinates divided by 10 (and the marker id changed to something else).
JSFiddle: https://jsfiddle.net/nkevo5ja
On Windows 10:
Firefox 78.0.2 (64-bit): Arrowheads are the same size.
Chrome 84.0.4147.89 (64-bit): Arrowheads are different sizes.
If vector-effect: non-scaling-stroke is removed, the arrowheads become the same size (but this breaks the line-width).
Whose implementation is incorrect?
<!-- Styles -->
<svg width="0" height="0">
<style>
line, path {
stroke: black;
vector-effect: non-scaling-stroke;
}
</style>
</svg>
<!-- Larger version -->
<svg width="120px" height="100%" viewBox="0 0 400 300">
<defs>
<marker id="larger"
viewBox="0 -20 70 40"
refX="70" refY="0"
markerWidth="70" markerHeight="40"
orient="auto"
>
<path d="M 70 0 L 0 -20 L 0 20 z"/>
</marker>
</defs>
<line x1="400" y1="300" x2="0" y2="0" marker-end="url(#larger)"/>
</svg>
<!-- Smaller version (larger version with all coordinates divided by 10) -->
<svg width="120px" height="100%" viewBox="0 0 40 30">
<defs>
<marker id="smaller"
viewBox="0 -2 7 4"
refX="7" refY="0"
markerWidth="7" markerHeight="4"
orient="auto"
>
<path d="M 7 0 L 0 -2 L 0 2 z"/>
</marker>
</defs>
<line x1="40" y1="30" x2="0" y2="0" marker-end="url(#smaller)"/>
</svg>
Chromium issue: https://crbug.com/1107791
Firefox has the correct behavior, there is even a note in the specs about this exact case:
When ‘markerUnits’ has the value strokeWidth, the size of the marker is relative to the stroke-width after it has had any transforms applied that affect the width of the stroke in the user coordinate system for the stroke. This means that, for example, the vector-effect attribute with a value of non-scaling-stroke will result in the markers also being non scaling.
strokeWidth being the default value for markerUnits.
Edit: Turns out my reading of the specs was wrong and that what should happen is the markerWidth and markerHeight are multiplied by the final computed strokewidth of the stroked line – 1px here – just like Chrome did.
You can refer to Robert Longson's answer, who did push a fix for Firefox so it aligns with Chrome and the specs.
Using this exact snippet, you can get the same results in both Chrome and Firefox by setting this markerUnits attribute to userSpaceOnUse.
<!-- Styles -->
<svg width="0" height="0">
<style>
line, path {
stroke: black;
vector-effect: non-scaling-stroke;
}
</style>
</svg>
<!-- Larger version -->
<svg width="120px" height="100%" viewBox="0 0 400 300">
<defs>
<marker id="larger"
viewBox="0 -20 70 40"
refX="70" refY="0"
markerUnits="userSpaceOnUse"
markerWidth="70" markerHeight="40"
orient="auto"
>
<path d="M 70 0 L 0 -20 L 0 20 z"/>
</marker>
</defs>
<line x1="400" y1="300" x2="0" y2="0" marker-end="url(#larger)"/>
</svg>
<!-- Smaller version (larger version with all coordinates divided by 10) -->
<svg width="120px" height="100%" viewBox="0 0 40 30">
<defs>
<marker id="smaller"
viewBox="0 -2 7 4"
refX="7" refY="0"
markerUnits="userSpaceOnUse"
markerWidth="7" markerHeight="4"
orient="auto"
>
<path d="M 7 0 L 0 -2 L 0 2 z"/>
</marker>
</defs>
<line x1="40" y1="30" x2="0" y2="0" marker-end="url(#smaller)"/>
</svg>
Firefox was wrong and I've just fixed it, it now has the same rendering as Chrome for this case.
There are two effects here, non-scaling-stroke on the path within the marker and non-scaling-stroke on the markerWidth that the marker is using. That markerWidth is based on the marked line's stroke-width and that stroke is also non-scaling.
Firefox and Chrome did apply the non-scaling-stroke transform to the marker's lines but only Chrome corrected the strokeWidth too. Firefox nightlies will deal with the strokeWidth correctly from tomorrow. Firefox 83 will be the first release containing the fix.

Manipulation of SVG icon's dimensions

I have the following SVG file
<svg width="523" height="524" style='background-color: teal;' xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-ec2d25d9" viewBox="0 0 60 30">
<g stroke="#000" fill="#fff">
<path d="M0 0h60v60H0z" fill="#FFF"/>
<path d="M0 0l30 37.1v-18l30 37.2" fill="none"/>
</g>
<g>
<path fill="none" d="M-1-1h583v403H-1z"/>
</g>
</symbol>
<path d="M85 84 127 84 127 126 85 126 "/>
<use href="#icon-ec2d25d9" x="85" y="84" width="22" height="36" fill="none" stroke="black" class="icon 4"/>
</svg>
(https://jsfiddle.net/L5xz73j4/) and I would like to modify the dimensions of the small icon inside the black rectangle to match the width and height of the rectangle. I'm generating these kinds of SVG's on the fly so I cannot start playing with the width and height attributes by hand. My question is that can I use the path element of the black rectangle to achieve this or what's the appropriate way?
I've changed the viewBox of the symbol to viewBox="0 0 60 60" acording to the size of the group inside. Now the symbol is square. In order to make the use fill the black square I've changed the width and the height of the use to width="42" height="42" i.e, the size of the black square.
I hope this is what you are asking
<svg width="523" height="524" style='background-color: teal;' xmlns="http://www.w3.org/2000/svg">
<symbol id="icon-ec2d25d9" viewBox="0 0 60 60">
<g stroke="#000" fill="#fff">
<path d="M0 0h60v60H0z"/>
<path d="M0 0l30 37.1v-18l30 37.2" fill="none"/>
</g>
<!--<g><path fill="none" d="M-1-1h583v403H-1z"/></g>-->
</symbol>
<path d="M85 84 127 84 127 126 85 126 " />
<use href="#icon-ec2d25d9" x="85" y="84" width="42" height="42" fill="none" stroke="black" class="icon 4"/>
</svg>

clip-path url fails to find id

I have an SVG that I am trying to use to clip a div, but the id I give to the <clipPath> tag does not work.
I have tried changing the ID, and have made sure that the SVG does indeed exist in the same file, and the ID is visible.
The svg is like so:
<svg id="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 149.559">
<defs>
<clipPath id="clipper">
<g id="svgg" stroke="none" fill-rule="evenodd">
<path id="path0" d= .../>
<path id="path1" d= .../>
<path id="path2" d= .../>
<path id="path3" d= .../>
<path id="path4" d= .../>
</g>
</clipPath>
</defs>
</svg>
I added the <defs> and <clipPath> tag so I could use the svg I had as a clipping mask.
The html element being used is:
<div class="logo-bg" style="clipPath: url(#clipper)"></div>
the div does have a width and height.
Within developer tools, the css property of the div I am trying to clip with clip-path: url(#clip-id) shows "could not load the image". Ideally I would be able to clip the div with the SVG.
here's the code I am working with: https://jsfiddle.net/mzLtsqva/6/
I am new to working with SVGs and so would appreciate any help to solve this issue.
Inside the <clipPath> don't wrap the paths in a group element.
In the next example I'm using a clipping path that is not working: #no and one that is working: #yes. In the one that is not working I'm wrapping the elements inside in a <g> element.
svg{border:1px solid;}
<svg width="250" height="250" viewBox="0 0 250 250" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="rect" x ="0" y ="0" height ="150" width ="70" style ="stroke:#000;" transform="translate(90, 50)"/>
<clipPath id="no">
<g>
<use xlink:href="#rect" fill="none"></use>
<use xlink:href="#rect" fill="none" transform="rotate(60 125 125)"></use>
<use xlink:href="#rect" fill="none" transform="rotate(-60 125 125)"></use>
</g>
</clipPath>
</defs>
<image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" height="250" width="250" x="-15" y ="50" clip-path="url(#no)"></image>
</svg>
<svg width="250" height="250" viewBox="0 0 250 250" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<clipPath id="yes">
<use xlink:href="#rect" fill="none"></use>
<use xlink:href="#rect" fill="none" transform="rotate(60 125 125)"></use>
<use xlink:href="#rect" fill="none" transform="rotate(-60 125 125)"></use>
</clipPath>
</defs>
<image xlink:href="https://s3-us-west-2.amazonaws.com/s.cdpn.io/222579/beagle400.jpg" height="250" width="250" x="-15" y ="50" clip-path="url(#yes)"></image>
</svg>

How to create an inset shadow on an svg circle stroke?

How can i create the following widget in SVG?
I'm fine with the shapes itself but i'm struggling with the inset shadow on the back circle.
I've tried a radial gradient, which 'works' but it doesn't look that great and I have to fiddle with the stop values on the order of thousandths of a percent to get it exactly right and it just feels totally hacky.
Is there a better way?
Code to produce the SVG:
<svg width="180" height="180" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="90" cy="90" r="72" fill="none" stroke="#ddd" stroke-width="18"></circle>
<path class="main-arc" d="M 90 18 A 72 72 0 1 1 85.47908259388944 18.142075553164446" fill="transparent" stroke-width="18" stroke="black" stroke-linecap="round" style="stroke-dasharray: 452.389; stroke-dashoffset: 366.435;">
</path>
</svg>
Well you can do it the easy way with an inset shadow:
<svg width="180" height="180">
<defs>
<filter id="inset-shadow">
<feFlood flood-color="black"/>
<feComposite operator="out" in2="SourceGraphic"/>
<feGaussianBlur stdDeviation="2"/>
<feComposite operator="atop" in2="SourceGraphic"/>
</filter>
</defs>
<circle filter="url(#inset-shadow)" cx="90" cy="90" r="72" fill="none" stroke="#ddd" stroke-width="18"></circle>
<path class="main-arc" d="M 90 18 A 72 72 0 1 1 85.47908259388944 18.142075553164446" fill="transparent" stroke-width="18" stroke="black" stroke-linecap="round" style="stroke-dasharray: 452.389; stroke-dashoffset: 366.435;">
</path>
</svg>
But if you really want a 3D effect, then you'll need a lighting effect:
<svg width="180" height="180" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter id="inset-shadow">
<feFlood flood-color="black"/>
<feComposite operator="xor" in2="SourceGraphic"/>
<feGaussianBlur stdDeviation="1"/>
<feComposite operator="in" in2="SourceGraphic" result="map"/>
<feDiffuseLighting lighting-color="white" surfaceScale="2" diffuseConstant="1">
<feSpotLight x="-30" y="-30" z="230"/>
</feDiffuseLighting>
<feBlend mode="multiply" in="SourceGraphic" />
<feComposite operator="in" in2="SourceGraphic"/>
</filter>
</defs>
<circle filter="url(#inset-shadow)" cx="90" cy="90" r="72" fill="none" stroke="#ddd" stroke-width="18"></circle>
<path class="main-arc" d="M 90 18 A 72 72 0 1 1 85.47908259388944 18.142075553164446" fill="transparent" stroke-width="18" stroke="black" stroke-linecap="round" style="stroke-dasharray: 452.389; stroke-dashoffset: 366.435;">
</path>
</svg>
Draw a pale grey stroked circle on a darker grey background, apply a gaussian blur filter, and clip the results with a clipPath:
<svg width="360" height="360" viewBox="0 0 180 180">
<defs>
<!-- Gaussian blur filter used to soften the shadow edges -->
<filter id="blur" filterUnits="userSpaceOnUse" x="-90" y="-90"
width="180" height="180">
<feGaussianBlur in="SourceGraphic" stdDeviation="1" />
</filter>
<!-- Annular clip path for the progress meter background -->
<clipPath id="ring" clip-rule="evenodd">
<path d="M0-81A81 81 0 0 1 0 81A81 81 0 0 1 0-81z
M0-63A63 63 0 0 1 0 63A63 63 0 0 1 0-63z" />
</clipPath>
</defs>
<!-- Set orgin to centre of drawing -->
<g transform="translate(90,90)">
<!-- Start with pale yellow background -->
<rect x="-90" y="-90" width="180" height="180" fill="#e8e0ce"
stroke="none" />
<!-- Draw the progress ring on top, and clip using the above clip path -->
<g clip-path="url(#ring)">
<!-- Dark grey background -->
<rect x="-85" y="-85" width="170" height="170" fill="#433"
stroke="none" />
<!-- Lighter grey circle with blur filter applied -->
<circle cx="0" cy="2.5" r="72" stroke="#655" stroke-width="18"
stroke="#655" fill="none" filter="url(#blur)"/>
</g>
<!-- Progress bar and text -->
<path class="main-arc" d="M 0 -72 A 72 72 0 1 1 -4.52 -71.86"
style="stroke-dasharray: 452.389; stroke-dashoffset: 366.435;"
fill="transparent" stroke-width="18" stroke="#b65"
stroke-linecap="round" />
<text x="0" y="0" font-size="40" font-family="'Trebuchet MS', sans-serif"
fill="#655" text-anchor="middle" dominant-baseline="central">
20%
</text>
</g>
</svg>

Resources