Color de fondo del texto en SVG

101

Quiero colorear el fondo de svg de manera textsimilar a background-coloren css

Solo pude encontrar documentación sobre fill, que colorea el texto en sí

¿Es siquiera posible?

Nick Ginanto
fuente
¿Puedes compartir tu código hasta ahora?
gotohales
stackoverflow.com/questions/12260370/… también muestra cómo hacer esto usando filtros.
Erik Dahlström
1
@RobertLongson Cerrar esta pregunta como duplicada cuando se hizo 2 años antes que la otra parece incorrecto, especialmente cuando la única respuesta es la suya.
Balthazar
@ Aperçu: La edad de una pregunta no es el factor principal a la hora de elegir un objetivo duplicado, consulte, por ejemplo, aquí .
bocinazo

Respuestas:

93

No, esto no es posible, los elementos SVG no tienen background-... atributos de presentación .

Para simular este efecto, puede dibujar un rectángulo detrás del atributo de texto con fill="green"o algo similar (filtros). Con JavaScript, puede hacer lo siguiente:

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);
sluijs
fuente
8
Eso o use un filtro svg (feFlood + feComposite) en el texto. Vea una pregunta ligeramente similar stackoverflow.com/questions/12260370/… .
Erik Dahlström
3
Esta solución que usa getBBox (), aunque funciona bien, puede ser bastante lenta cuando es necesario realizar una gran cantidad de cálculos. El problema con el uso de un filtro svg (feFlood + feComposite) es que el texto sale un poco irregular. He ofrecido una solución simple pero hacky a continuación.
dbarton_uk
¿Es mejor usar textElm = document.getElementById ("el-texto") en lugar de textElm = ctx.getElementById ("el-texto")?
Simon Hola
¿Cómo puedo usar la misma función getBBox en nodeJS?
Ali
77

Puede utilizar un filtro para generar el fondo.

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

Robert Longson
fuente
1
¿Qué significa "SourceGraphic" aquí? ¿"Url (#sólido)" genera realmente un acceso web adicional?
Ben Slade
7
el texto está borroso aquí :(
teran
5
¿Puedes darle relleno al fondo ?
vsync
2
Me encanta esta solución en teoría, pero puedo confirmar que el texto está borroso. Parece que el filtro rompe el suavizado.
Paulmelnikow
2
Agregue operator="xor"a feCompositepara evitar texto borroso. @RobertLongson @teran @paulmelnikow @bill
Saeid Zebardast
20

La solución que he usado es:

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

Se está colocando un elemento de texto duplicado, con los atributos de trazo y ancho de trazo. El trazo debe coincidir con el color de fondo y el ancho del trazo debe ser lo suficientemente grande para crear una "mancha" en la que escribir el texto real.

Un poco complicado y hay problemas potenciales, ¡pero funciona para mí!

dbarton_uk
fuente
1
Encontré que esta solución es la más fácil.
Morgan Wilde
Confirmó esto como la solución más fácil
scipper
También imprime muy bien donde la solución de filtro estaba muy borrosa cuando se imprimió.
David Hunt
17

No, no puede agregar color de fondo a los elementos SVG. Puedes hacerlo programáticamente con 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");
nnattawat
fuente
3
Esto no funciona; solo cambia el color del texto, no el color de fondo.
David J.
Incluya el texto en un div o span y aplique estilo a cualquiera de los dos últimos que haya utilizado.
Arif Burhan
Esta publicación lo explica bien: cambridge-intelligence.com/…
intercambio el
4

Respuesta de Robert Longson (@RobertLongson) con modificaciones:

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

y no tenemos bluring ni "getBBox" pesado :) El relleno lo proporcionan los espacios en blanco en el elemento de texto con filtro. Ha funcionado para mi

Roman Belov
fuente
2

este es mi truco favorito (no estoy seguro de que funcione). Hace referencia a un elemento que aún no se muestra y funciona bastante bien

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

Calimero100582
fuente
2

Puede combinar el filtro con el texto.

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

Vu Phan
fuente
1

Para aquellos que se preguntan cómo aplicar relleno a un elemento de texto cuando tiene un fondo como en la respuesta de Robert , haga lo siguiente:

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

En el ejemplo anterior, de filtros de x y Y posiciones pueden ser utilizados como transform: translate(-10%, -10%)lo haría, y la anchura y altura valores pueden leerse como 120%y 120%. Así que hicimos el fondo un 20% más grande y lo compensamos un -10%, por lo que el fondo ahora es un 10% más grande en cada lado del texto.

momciloo
fuente
0

Las respuestas anteriores se basaron en duplicar el texto y carecían de suficiente espacio en blanco.

Al usar atopy&nbsp; pude obtener los resultados que quería.

Este ejemplo también incluye flechas, un caso de uso común para etiquetas de texto SVG:

<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">&nbsp;130 cm&nbsp;</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">&nbsp;60 cm&nbsp;</text>
    </g>
</g>
</svg>
El gato de Henry
fuente
-1

Puede agregar estilo a su texto:

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

Blanco, en este ejemplo. No funciona en IE :)

Jan Pi
fuente