Why isn't my SVG text centered vertically in Microsoft Edge? - css

I have a SVG that is well presented in Firefox and Chrome, but in Edge the text doesn't center vertically.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect fill="#ff0000" x="0" y="0" width="64" height="64" rx="8" ry="8" />
<text font-size="32px" alignment-baseline="middle" dominant-baseline="center" fill="#fff" text-anchor="middle" lengthAdjust="spacingAndGlyphs" textLength="85%" x="32" y="32">
dev
</text>
</svg>
This is what it looks like when its well presented:
And this is how Edge is presenting it:

This is what you can do: You keep alignment-baseline="baseline". This works correctly on Edge. Then you offset the text on y with dy = font-size/4
Also I've removed lengthAdjust="spacingAndGlyphs" textLength="85%"from your code since this was offseting the text to the right in Edge.
svg{width:90vh;}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect fill="#ff0000" x="0" y="0" width="64" height="64" rx="8" ry="8" />
<text font-size="32px" dy="8" dominant-baseline="baseline" text-anchor="middle" fill="#fff" x="32" y="32">dev</text>
</svg>

For the most reliable cross-browser behaviour, you should consider not using the x-baseline attributes at all. Instead, position the text baseline exactly where you want it.
For example:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<rect fill="#ff0000" x="0" y="0" width="64" height="64" rx="8" ry="8" />
<text font-size="32px" fill="#fff" text-anchor="middle" lengthAdjust="spacingAndGlyphs" textLength="85%" x="32" y="39">
dev
</text>
</svg>

Related

Svg lines on edges mask only in mobile

How can i remove lines on a svg masck. It only shows in mobile. See it live on bakar.store
I've tried everything and don't understand why it shows only on mobile.
i've change the svg, the css and always shows lines in image
`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 196.9 88.3" >
<defs>
<mask id="mask" x="0" y="0" width="100%" height="100%" >
<rect x="0" y="0" width="100%" height="100%" />
<path shape-rendering="geometricPrecision" d="M70.3,74.9c-1.9,4.3-4.8,7.2-12.9,7.2H7.1V7.8h20c5,0,8.4,1.6,10.8,3.8c3.3,3,4.2,6,4.2,18.7
c0,9.7-0.7,11.9-4.8,14.7c2.6,9.7,28.1,8.6,32,15.6C72.8,66.9,71.9,71.3,70.3,74.9z M28,32.7H15.2v8.8H28c3.6,0,5.6-1.4,5.6-4.2
C33.6,34.4,31.8,32.7,28,32.7z M27.6,48.5H15.2v9.1h12.7c4.9,0,6.5-1.6,6.5-4.7C34.4,49.9,31.8,48.5,27.6,48.5z"/>
<path shape-rendering="geometricPrecision" d="M66.9,53.4V40H53.6l0,9.4h-5l0-29c0-5.5,1.2-8,3.4-10.1c1.9-1.9,4.5-3.6,8.5-3.6c2.7,0,6.7,1.4,8.9,4.3
c1.8,2.3,2.7,3.8,2.7,9.5v33H66.9z M66.9,30.5c0-4.6-2.7-7.7-6.6-7.7c-4.3,0-6.8,3.6-6.8,7.7v5h13.4V30.5z"/>
<path shape-rendering="geometricPrecision" d="M95.2,76.4c-4.5-3.6-7.4-9.5-8.1-17.1h-0.3v22.7h-8.1V7.8h8.1v23h0.3c1-6,2.6-11.9,8.5-17.2
c4.9-4.3,39.7-5.5,47.8-5.8v24.5h-41.9c-9.4,0-14.7,5.1-14.7,12.8c0,7.6,6,12.5,14.5,12.5h11.3v24.5
C103.7,82.1,100.6,80.7,95.2,76.4z"/>
<path shape-rendering="geometricPrecision" d="M180.8,47.6c4.9,2.1,6.1,6.2,6.1,12v24.5h-8.1v-23c0-4.6-0.4-5.8-2.7-8.2c-1.4-1.7-3.6-2.5-7.5-2.5h-9.4v33.7
h-8.1V9.8h20.3c5,0,8.4,1.6,10.8,3.8c3.3,3,4.8,6,4.8,16.5C187.1,41.9,186.6,44.5,180.8,47.6z M172,34.8h-12.7v8.7H172
c4.5,0,6.5-1.3,6.5-4.1C178.5,36.4,177.3,34.8,172,34.8z"/>
<path shape-rendering="geometricPrecision" d="M137.8,82.6V69.3h-13.4v13.4h-5v-33c0-5.5,1.2-8,3.4-10.1c1.9-1.9,4.5-3.6,8.5-3.6c2.7,0,6.3,1.4,8.5,4.3
c1.8,2.3,3.1,3.8,3.1,9.5v33H137.8z M137.8,59.8c0-4.6-2.7-7.7-6.6-7.7c-4.3,0-6.8,3.6-6.8,7.7v5h13.4V59.8z"/>
</mask>
</defs>
<rect x="0" y="0" width="100%" height="100%" />
</svg>
`

background color not appying on Text tag inside svg [duplicate]

I want to color the background of svg text similar to background-color in css
I was only able to find documentation on fill, which colors the text itself
Is it even possible?
You could use a filter to generate the background.
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" result="bg" />
<feMerge>
<feMergeNode in="bg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">solid background</text>
</svg>
No this is not possible, SVG elements do not have background-... presentation attributes.
To simulate this effect you could draw a rectangle behind the text attribute with fill="green" or something similar (filters). Using JavaScript you could do the following:
var ctx = document.getElementById("the-svg"),
textElm = ctx.getElementById("the-text"),
SVGRect = textElm.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", SVGRect.x);
rect.setAttribute("y", SVGRect.y);
rect.setAttribute("width", SVGRect.width);
rect.setAttribute("height", SVGRect.height);
rect.setAttribute("fill", "yellow");
ctx.insertBefore(rect, textElm);
The solution I have used is:
<svg>
<line x1="100" y1="100" x2="500" y2="100" style="stroke:black; stroke-width: 2"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.6em">Hello World!</text>
<text x="150" y="105" style="fill:black">Hello World!</text>
</svg>
A duplicate text item is being placed, with stroke and stroke-width attributes. The stroke should match the background colour, and the stroke-width should be just big enough to create a "splodge" on which to write the actual text.
A bit of a hack and there are potential issues, but works for me!
Instead of using a <text> tag, the <foreignObject> tag can be used, which allows for XHTML content with CSS.
No, you can not add background color to SVG elements. You can do it programmatically with d3.
var text = d3.select("text");
var bbox = text.node().getBBox();
var padding = 2;
var rect = self.svg.insert("rect", "text")
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + (padding*2))
.attr("height", bbox.height + (padding*2))
.style("fill", "red");
Answer by Robert Longson (#RobertLongson) with modifications:
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow"/>
<feComposite in="SourceGraphic" operator="xor"/>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50"> solid background </text>
<text x="20" y="50" font-size="50">solid background</text>
</svg>
and we have no bluring and no heavy "getBBox" :)
Padding is provided by white spaces in text-element with filter.
It's worked for me
Going further with #dbarton_uk answer, to avoid duplicating text you can use paint-order=stroke style:
<svg>
<line x1="100" y1="100" x2="350" y2="100" style="stroke:grey; stroke-width: 100"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.5em; fill:black; paint-order:stroke; stroke-linejoin:round">Hello World!</text>
</svg>
Note the stroke-linejoin:round which is needed to avoid seeing spikes for the W sharp angle.
You can combine filter with the text.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
</head>
<body>
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter x="0" y="0" width="1" height="1" id="bg-text">
<feFlood flood-color="white"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<!-- something has already existed -->
<rect fill="red" x="150" y="20" width="100" height="50" />
<circle cx="50" cy="50" r="50" fill="blue"/>
<!-- Text render here -->
<text filter="url(#bg-text)" fill="black" x="20" y="50" font-size="30">text with color</text>
<text fill="black" x="20" y="50" font-size="30">text with color</text>
</svg>
</body>
</html>
this is my favorite hack (not sure it should work). It refer an element that is not yet displayed, and it works pretty well
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 40" preserveAspectRatio="xMidYMid meet">
<defs>
<filter x="-0.02" y="0" width="1.04" height="1.1" id="removebackground">
<feFlood flood-color="#00ffff"/>
</filter>
</defs>
<!--Draw the text-->
<use xlink:href="#mygroup" filter="url(#removebackground)" />
<g id="mygroup">
<text id="text1" x="9" y="20" style="text-anchor:start;font-size:14px;">custom text with background</text>
<line x1="200" y1="18" x2="200" y2="36" stroke="#000" stroke-width="5"/>
<line x1="120" y1="27" x2="203" y2="27" stroke="#000" stroke-width="5"/>
</g>
</svg>
For those wondering how to apply padding to a text element when it has a background like in the Robert's answer, do the following:
<svg>
<defs>
<filter x="-0.1" y="-0.1" width="1.2" height="1.2" id="solid">
<feFlood flood-color="#171717"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">Hello</text>
</svg>
In the example above, filter's x and y positions can be used as transform: translate(-10%, -10%) would, and width and height values can be read as 120% and 120%. So we made background 20% bigger, and offsetted it -10%, so background is now 10% bigger on each side of the text.
The previous answers relied on doubling up text and lacked sufficient whitespace.
By using atop and I was able to get the results I wanted.
This example also includes arrows, a common use case for SVG text labels:
<svg viewBox="-105 -40 210 234">
<title>Size Guide</title>
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="white"></feFlood>
<feComposite in="SourceGraphic" operator="atop"></feComposite>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z"></path>
</marker>
</defs>
<g id="garment">
<path id="right-body" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 0 l30 0 l0 154 l-30 0"></path>
<path id="right-sleeve" d="M30 0 l35 0 l0 120 l-35 0" fill="none" stroke-linejoin="round" stroke="black" stroke-width="1"></path>
<use id="left-body" href="#right-body" transform="scale(-1,1)"></use>
<use id="left-sleeve" href="#right-sleeve" transform="scale(-1,1)"></use>
<path id="collar-right-top" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 -6.5 l11.75 0 l6.5 6.5"></path>
<use id="collar-left-top" href="#collar-right-top" transform="scale(-1,1)"></use>
<path id="collar-left" fill="white" stroke="black" stroke-width="1" stroke-linejoin="round" d="M-11.75 -6.5 l-6.5 6.5 l30 77 l6.5 -6.5 Z"></path>
<path id="front-right" fill="white" stroke="black" stroke-width="1" d="M18.25 0 L30 0 l0 154 l-41.75 0 l0 -77 Z"></path>
<line x1="0" y1="0" x2="0" y2="154" stroke="black" stroke-width="1" stroke-dasharray="1 3"></line>
<use id="collar-right" href="#collar-left" transform="scale(-1,1)"></use>
</g>
<g id="dimension-labels">
<g id="dimension-sleeve-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="85" y1="0" x2="85" y2="120" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="85" y="60" class="dimension" text-anchor="middle" dominant-baseline="middle"> 120 cm</text>
</g>
<g id="dimension-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-85" y1="0" x2="-85" y2="154" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="-85" y="77" text-anchor="middle" dominant-baseline="middle" class="dimension"> 154 cm</text>
</g>
<g id="dimension-sleeve-to-sleeve">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-65" y1="-20" x2="65" y2="-20" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="-20" text-anchor="middle" dominant-baseline="middle" class="dimension"> 130 cm </text>
</g>
<g title="Back Width" id="dimension-back-width">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-30" y1="174" x2="30" y2="174" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="174" text-anchor="middle" dominant-baseline="middle" class="dimension"> 60 cm </text>
</g>
</g>
</svg>
An obvious workaround to the problem of the blur produced by the filter effect is to render the <text> two times: once for the background (with transparent characters) and once for the characters (without a background filter).
For me, this was the only way to make the text readable in Safari.
<svg width="100%" height="100%">
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" />
</filter>
<g transform="translate(20, 50)" font-size="50">
<text aria-hidden="true" fill="none" filter="url(#solid)">solid background</text>
<text fill="blue">solid background</text>
</g>
</svg>
The aria-hidden="true" attribute is there to prevent screen readers from speaking the text twice, if the user uses a screen reader.
You can add style to your text:
style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
text-shadow: rgb(255, 255, 255) -2px -2px 0px, rgb(255, 255, 255) -2px 2px 0px,
rgb(255, 255, 255) 2px -2px 0px, rgb(255, 255, 255) 2px 2px 0px;"
White, in this example.
Does not work in IE :)

Rotate svg text around central text position using css

I want to apply a single css rotation transformation to a set of elements in an SVG, such that each element is rotated independently, without having to calculate the centre of each element in the css. For example, I have an SVG that looks like the picture on the left, and want to apply css to achieve the effect on the right
I'm writing the svg myself, and am creating something like this
<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
<text transform="translate(50 100)" text-anchor="middle">Text 1</text>
<text transform="translate(100 100)" text-anchor="middle">Text 2</text>
</svg>
When I apply a css rotation, e.g. by inserting <style>text {transform: rotate(10deg)}</style>, it seems to overwrite the first transformation, and the rotated text is placed in the top left corner:
I can modify the svg to use `x="X" y="Y" instead of a transform attribute, but that results in the transformation being applied around a different centre instead:
<svg baseProfile="full" height="200" version="1.1" width="200" xmlns="http://www.w3.org/2000/svg">
<style>text {transform: rotate(10deg)}</style>
<text x="50" y="100" text-anchor="middle">Text 1</text>
<text x="100" y="100" text-anchor="middle">Text 2</text>
</svg>
How can I structure the svg so that I can apply a rotation which works independently on each element without overwriting the initial transform?
This is a possible solution:
-The text has x="0" y="0" and is rotated with CSS.
-You put the text in the <defs>.
-You use the text and the <use> element has the x and y values you need.
text{transform:rotate(90deg)}
<svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<text id="a" text-anchor="middle" >Text 1</text>
<text id="b" text-anchor="middle" >Text 2</text>
</defs>
<use xlink:href="#a" x="50" y="50" />
<use xlink:href="#b" x="100" y="50" />
</svg>
Yet another solution (inspired by the comment of Robert Longson) would wrapping the rotated text in a g element and translate the g
text{transform:rotate(90deg)}
<svg baseProfile="full" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50,50)"><text text-anchor="middle" >Text 1</text></g>
<g transform="translate(100,50)"><text text-anchor="middle" >Text 2</text></g>
</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>

Background color of text in SVG

I want to color the background of svg text similar to background-color in css
I was only able to find documentation on fill, which colors the text itself
Is it even possible?
You could use a filter to generate the background.
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" result="bg" />
<feMerge>
<feMergeNode in="bg"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">solid background</text>
</svg>
No this is not possible, SVG elements do not have background-... presentation attributes.
To simulate this effect you could draw a rectangle behind the text attribute with fill="green" or something similar (filters). Using JavaScript you could do the following:
var ctx = document.getElementById("the-svg"),
textElm = ctx.getElementById("the-text"),
SVGRect = textElm.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("x", SVGRect.x);
rect.setAttribute("y", SVGRect.y);
rect.setAttribute("width", SVGRect.width);
rect.setAttribute("height", SVGRect.height);
rect.setAttribute("fill", "yellow");
ctx.insertBefore(rect, textElm);
The solution I have used is:
<svg>
<line x1="100" y1="100" x2="500" y2="100" style="stroke:black; stroke-width: 2"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.6em">Hello World!</text>
<text x="150" y="105" style="fill:black">Hello World!</text>
</svg>
A duplicate text item is being placed, with stroke and stroke-width attributes. The stroke should match the background colour, and the stroke-width should be just big enough to create a "splodge" on which to write the actual text.
A bit of a hack and there are potential issues, but works for me!
Instead of using a <text> tag, the <foreignObject> tag can be used, which allows for XHTML content with CSS.
No, you can not add background color to SVG elements. You can do it programmatically with d3.
var text = d3.select("text");
var bbox = text.node().getBBox();
var padding = 2;
var rect = self.svg.insert("rect", "text")
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + (padding*2))
.attr("height", bbox.height + (padding*2))
.style("fill", "red");
Answer by Robert Longson (#RobertLongson) with modifications:
<svg width="100%" height="100%">
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow"/>
<feComposite in="SourceGraphic" operator="xor"/>
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50"> solid background </text>
<text x="20" y="50" font-size="50">solid background</text>
</svg>
and we have no bluring and no heavy "getBBox" :)
Padding is provided by white spaces in text-element with filter.
It's worked for me
Going further with #dbarton_uk answer, to avoid duplicating text you can use paint-order=stroke style:
<svg>
<line x1="100" y1="100" x2="350" y2="100" style="stroke:grey; stroke-width: 100"/>
<text x="150" y="105" style="stroke:white; stroke-width:0.5em; fill:black; paint-order:stroke; stroke-linejoin:round">Hello World!</text>
</svg>
Note the stroke-linejoin:round which is needed to avoid seeing spikes for the W sharp angle.
You can combine filter with the text.
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8 />
<title>SVG colored patterns via mask</title>
</head>
<body>
<svg viewBox="0 0 300 300" xmlns="http://www.w3.org/2000/svg">
<defs>
<filter x="0" y="0" width="1" height="1" id="bg-text">
<feFlood flood-color="white"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<!-- something has already existed -->
<rect fill="red" x="150" y="20" width="100" height="50" />
<circle cx="50" cy="50" r="50" fill="blue"/>
<!-- Text render here -->
<text filter="url(#bg-text)" fill="black" x="20" y="50" font-size="30">text with color</text>
<text fill="black" x="20" y="50" font-size="30">text with color</text>
</svg>
</body>
</html>
this is my favorite hack (not sure it should work). It refer an element that is not yet displayed, and it works pretty well
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 620 40" preserveAspectRatio="xMidYMid meet">
<defs>
<filter x="-0.02" y="0" width="1.04" height="1.1" id="removebackground">
<feFlood flood-color="#00ffff"/>
</filter>
</defs>
<!--Draw the text-->
<use xlink:href="#mygroup" filter="url(#removebackground)" />
<g id="mygroup">
<text id="text1" x="9" y="20" style="text-anchor:start;font-size:14px;">custom text with background</text>
<line x1="200" y1="18" x2="200" y2="36" stroke="#000" stroke-width="5"/>
<line x1="120" y1="27" x2="203" y2="27" stroke="#000" stroke-width="5"/>
</g>
</svg>
For those wondering how to apply padding to a text element when it has a background like in the Robert's answer, do the following:
<svg>
<defs>
<filter x="-0.1" y="-0.1" width="1.2" height="1.2" id="solid">
<feFlood flood-color="#171717"/>
<feComposite in="SourceGraphic" operator="xor" />
</filter>
</defs>
<text filter="url(#solid)" x="20" y="50" font-size="50">Hello</text>
</svg>
In the example above, filter's x and y positions can be used as transform: translate(-10%, -10%) would, and width and height values can be read as 120% and 120%. So we made background 20% bigger, and offsetted it -10%, so background is now 10% bigger on each side of the text.
The previous answers relied on doubling up text and lacked sufficient whitespace.
By using atop and I was able to get the results I wanted.
This example also includes arrows, a common use case for SVG text labels:
<svg viewBox="-105 -40 210 234">
<title>Size Guide</title>
<defs>
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="white"></feFlood>
<feComposite in="SourceGraphic" operator="atop"></feComposite>
</filter>
<marker id="arrow" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z"></path>
</marker>
</defs>
<g id="garment">
<path id="right-body" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 0 l30 0 l0 154 l-30 0"></path>
<path id="right-sleeve" d="M30 0 l35 0 l0 120 l-35 0" fill="none" stroke-linejoin="round" stroke="black" stroke-width="1"></path>
<use id="left-body" href="#right-body" transform="scale(-1,1)"></use>
<use id="left-sleeve" href="#right-sleeve" transform="scale(-1,1)"></use>
<path id="collar-right-top" fill="none" stroke="black" stroke-width="1" stroke-linejoin="round" d="M0 -6.5 l11.75 0 l6.5 6.5"></path>
<use id="collar-left-top" href="#collar-right-top" transform="scale(-1,1)"></use>
<path id="collar-left" fill="white" stroke="black" stroke-width="1" stroke-linejoin="round" d="M-11.75 -6.5 l-6.5 6.5 l30 77 l6.5 -6.5 Z"></path>
<path id="front-right" fill="white" stroke="black" stroke-width="1" d="M18.25 0 L30 0 l0 154 l-41.75 0 l0 -77 Z"></path>
<line x1="0" y1="0" x2="0" y2="154" stroke="black" stroke-width="1" stroke-dasharray="1 3"></line>
<use id="collar-right" href="#collar-left" transform="scale(-1,1)"></use>
</g>
<g id="dimension-labels">
<g id="dimension-sleeve-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="85" y1="0" x2="85" y2="120" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="85" y="60" class="dimension" text-anchor="middle" dominant-baseline="middle"> 120 cm</text>
</g>
<g id="dimension-length">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-85" y1="0" x2="-85" y2="154" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="-85" y="77" text-anchor="middle" dominant-baseline="middle" class="dimension"> 154 cm</text>
</g>
<g id="dimension-sleeve-to-sleeve">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-65" y1="-20" x2="65" y2="-20" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="-20" text-anchor="middle" dominant-baseline="middle" class="dimension"> 130 cm </text>
</g>
<g title="Back Width" id="dimension-back-width">
<line marker-start="url(#arrow)" marker-end="url(#arrow)" x1="-30" y1="174" x2="30" y2="174" stroke="black" stroke-width="1"></line>
<text font-size="10" filter="url(#solid)" fill="black" x="0" y="174" text-anchor="middle" dominant-baseline="middle" class="dimension"> 60 cm </text>
</g>
</g>
</svg>
An obvious workaround to the problem of the blur produced by the filter effect is to render the <text> two times: once for the background (with transparent characters) and once for the characters (without a background filter).
For me, this was the only way to make the text readable in Safari.
<svg width="100%" height="100%">
<filter x="0" y="0" width="1" height="1" id="solid">
<feFlood flood-color="yellow" />
</filter>
<g transform="translate(20, 50)" font-size="50">
<text aria-hidden="true" fill="none" filter="url(#solid)">solid background</text>
<text fill="blue">solid background</text>
</g>
</svg>
The aria-hidden="true" attribute is there to prevent screen readers from speaking the text twice, if the user uses a screen reader.
You can add style to your text:
style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
text-shadow: rgb(255, 255, 255) -2px -2px 0px, rgb(255, 255, 255) -2px 2px 0px,
rgb(255, 255, 255) 2px -2px 0px, rgb(255, 255, 255) 2px 2px 0px;"
White, in this example.
Does not work in IE :)

Resources