SVG中文本的背景颜色

149

我想要给svg中的text文字涂上类似于css中的background-color的背景色。

我只能找到关于fill的文档,这个属性只能让文字本身变色。

这种操作是否可能呢?


你能分享一下你目前的代码吗? - gotohales
这些也可能有所帮助 https://dev59.com/pmw15IYBdhLWcg3wQ5hi 和 https://dev59.com/Isgoz4gBFxS5KdRjbnWN - gotohales
https://dev59.com/wmjWa4cB1Zd3GeqPmwkR#12263962 这里还展示了如何使用滤镜来实现。 - Erik Dahlström
1
@RobertLongson 在这个问题在另一个问题之前2年被提出,尤其是当那里唯一的答案是你的时候,将其关闭为重复似乎是错误的。 - Preview
@预览:选择重复目标时,问题的年龄并不是主要因素,例如请参见此处 - honk
@RobertLongson,您认为这个问题与另一个问题相比质量不可比(如果不是更好),即使它有42个赞成票而另一个只有8个?您的回答得分与这两个问题中较低的那个相同,且少于排名第一的三分之一。您的回答质量相当主观,不应该真正影响到您。 - Preview
13个回答

133

你可以使用滤镜来生成背景。

<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>


2
这里的“SourceGraphic”是什么意思?“url(#solid)”是否会导致额外的网络访问? - Ben Slade
10
抱歉,我不能读取模糊的文本。请重新输入清晰的内容以进行翻译。 - teran
13
你能给一下“padding”的背景说明吗? - vsync
4
理论上我喜欢这个解决方案,但可以确认文本模糊不清。看起来滤镜破坏了抗锯齿效果。 - paulmelnikow
6
operator="xor" 添加到 feComposite 可以防止文本模糊。@RobertLongson @teran @paulmelnikow @bill - Saeid
显示剩余7条评论

121

不,这是不可能的,SVG元素没有background-...演示属性

要模拟此效果,您可以在文本属性后面绘制一个带有fill="green"或类似颜色(过滤器)的矩形。使用JavaScript,您可以执行以下操作:

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);

10
您可以使用 SVG 滤镜(feFlood + feComposite)对文本进行处理。请参考类似的问题:https://dev59.com/wmjWa4cB1Zd3GeqPmwkR。 - Erik Dahlström
3
虽然使用 getBBox() 可以正常运行,但在需要进行大量计算时可能会非常缓慢。使用 SVG 滤镜(feFlood + feComposite)的问题在于文本会有些锯齿状。以下提供了一种简单但不太正式的解决方案。 - dbarton_uk
最好使用textElm = document.getElementById("the-text")而不是textElm = ctx.getElementById("the-text")吗? - Simon Hi
如何在nodeJS中使用相同的getBBox函数? - Ali

42

我使用的解决方案是:

<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>

正在放置一个具有描边和描边宽度属性的重复文本项。描边应该与背景颜色相匹配,描边宽度应该足够大,以创建一个“斑点”,在其上编写实际文本。

这是一种有些取巧的方法,可能存在潜在问题,但对我来说起作用!


2
我发现这个解决方案是最简单的。 - Morgan Wilde
1
确认这是最简单的解决方案。 - scipper
1
同时,它打印得很漂亮,而过滤器解决方案在打印时非常模糊。 - David Hunt
1
最佳解决方案!! - Jonio
1
太棒了!!! - Stu Blair
显示剩余2条评论

25

可以使用<foreignObject>标签来代替<text>标签,它支持具有CSS的XHTML内容。


1
你能给一个例子吗? - IgniteCoders
6
被低估的答案。https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject包含一个有用的示例。在您的foreignObject中,您可以使用div和span以及CSS定义。 - dr jerry
1
如果您想对SVG中的foreignObject内部的DIV应用CSS转换,则在Safari浏览器中无法正常工作。 - Kernel James
foreignObject 是 SVG 世界中的一个 hack,正如 @KernelJames 所提到的,并非所有浏览器都完全支持它。 - Maciej Bukowski

18

不可以为SVG元素添加背景颜色。你可以使用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");

4
这样行不通,它只会改变文本的颜色,而不是背景颜色。 - David J.
1
文本放入一个divspan中,并对您使用的最后一个元素应用样式。 - Arif Burhan
这篇文章讲解得很清楚:https://cambridge-intelligence.com/customize-graph-visualization-d3-keylines/ - exchange

10

结合@dbarton_uk的回答,为避免重复文本,您可以使用paint-order=stroke样式:

<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>

注意stroke-linejoin:round,这是必须的,以避免在W尖角处看到尖峰。

1
这正是我想要的。可以添加到CSS中而不改变文档本身。 - Tao Starbow

8

由Robert Longson(@RobertLongson)进行修改的答案:

<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>

我们没有模糊和重量级的“getBBox” :) 在文本元素中,填充由空格提供,并带有过滤器。 对我很有效


关于填充,最好使用filter的参数xywidthheight。默认值提供了一个漂亮的填充(我的意思是,默认的SVG值,如果您没有定义它们)。 - FlorianT
使用运算符 "xor" 会使文本呈透明状态,而不是选定的颜色(如果我们排除带有 alpha 的洪水颜色的更复杂情况)。难道你不想使用运算符 "over" 吗? - FlorianT
@FlorianT那为什么文本有颜色呢?在文本上添加fill="red"会使文本变成红色。 - theonlygusti
@theonlygusti 这是因为文本是重复的。我的意思是,如果你使用over操作符而不是xor,你只能使用第一个文本元素。 - undefined

4

如果你想在文本元素具有背景时如Robert's answer中所示应用填充,可以按照以下步骤进行:

<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>

在上面的示例中,过滤器的xy位置可以像transform: translate(-10%, -10%)一样使用,而widthheight值可以读取为120%120%。因此,我们使背景增大了20%,并将其偏移了-10%,所以背景现在在文本的每一侧都增大了10%。

3
您可以将筛选器与文本组合使用。

<!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> 


2

这是我最喜欢的技巧(不确定它是否有效)。它引用了一个尚未显示的元素,并且效果非常好。

<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>


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