Couleur d'arrière-plan du texte en SVG

101

Je veux colorer l'arrière-plan du svg textcomme background-coloren css

Je n'ai pu trouver de documentation que sur les fillcouleurs du texte lui-même

Est-ce même possible?

Nick Ginanto
la source
Pouvez-vous partager votre code jusqu'à présent?
gotohales
stackoverflow.com/questions/12260370/… montre également comment faire cela en utilisant des filtres.
Erik Dahlström
1
@RobertLongson Fermer cette question en double alors qu'elle a été posée 2 ans avant l'autre semble erronée, surtout quand la seule réponse est la vôtre.
Balthazar
@ Aperçu: L'âge d'une question n'est pas le facteur principal lors du choix d'une cible en double, voir par exemple ici .
klaxonner

Réponses:

93

Non, ce n'est pas possible, les éléments SVG n'ont pas d' background-... attributs de présentation .

Pour simuler cet effet, vous pouvez dessiner un rectangle derrière l'attribut de texte avec fill="green"ou quelque chose de similaire (filtres). En utilisant JavaScript, vous pouvez effectuer les opérations suivantes:

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
la source
8
Ou utilisez un filtre svg (feFlood + feComposite) sur le texte. Voir la question légèrement similaire stackoverflow.com/questions/12260370/… .
Erik Dahlström
3
Cette solution utilisant getBBox (), bien qu'elle fonctionne très bien, peut être assez lente lorsqu'un grand nombre de calculs doivent être effectués. Le problème avec l'utilisation d'un filtre svg (feFlood + feComposite) est que le texte sort un peu irrégulier. Ont proposé une solution simple, mais piratée ci-dessous.
dbarton_uk
Mieux vaut utiliser textElm = document.getElementById ("le-texte") au lieu de textElm = ctx.getElementById ("le-texte")?
Simon Hi
Comment j'utilise la même fonction getBBox dans nodeJS
Ali
78

Vous pouvez utiliser un filtre pour générer l'arrière-plan.

<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
la source
1
Que signifie «SourceGraphic» ici? "Url (#solid)" entraîne-t-il réellement un accès Web supplémentaire?
Ben Slade
7
le texte est flou ici :(
teran
5
Pouvez-vous donner le rembourrage de fond ?
vsync
2
J'adore cette solution en théorie, mais peut confirmer que le texte est flou. Il semble que le filtre brise l'anti-crénelage.
paulmelnikow
2
Ajoutez operator="xor"à feCompositepour éviter un texte flou. @RobertLongson @teran @paulmelnikow @bill
Saeid Zebardast
20

La solution que j'ai utilisée est:

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

Un élément de texte en double est placé, avec des attributs de trait et de largeur de trait. Le trait doit correspondre à la couleur d'arrière-plan, et la largeur du trait doit être juste assez grande pour créer un "splodge" sur lequel écrire le texte réel.

Un peu de hack et il y a des problèmes potentiels, mais ça marche pour moi!

dbarton_uk
la source
1
J'ai trouvé cette solution la plus simple.
Morgan Wilde
Confirmé cela comme la solution la plus simple
scipper
Imprime également bien là où la solution de filtre était très floue lors de l'impression.
David Hunt
17

Non, vous ne pouvez pas ajouter de couleur d'arrière-plan aux éléments SVG. Vous pouvez le faire par programmation avec 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
la source
3
Cela ne fonctionne pas; il ne modifie que la couleur du texte, pas la couleur d'arrière-plan.
David J.
1
Entourez le texte d'un div ou d'un intervalle et appliquez le style à celui des deux derniers que vous avez utilisé.
Arif Burhan
Ce post l'explique bien: cambridge-intelligence.com/...
échange
4

Réponse de Robert Longson (@RobertLongson) avec 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>

et nous n'avons pas de flou et pas de "getBBox" lourd :) Le remplissage est fourni par des espaces blancs dans l'élément de texte avec filtre. Ça a marché pour moi

Roman Belov
la source
2

c'est mon hack préféré (pas sûr que ça marche). Il fait référence à un élément qui n'est pas encore affiché, et cela fonctionne plutôt 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
la source
2

Vous pouvez combiner le filtre avec le texte.

<!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
la source
1

Pour ceux qui se demandent comment appliquer un remplissage à un élément de texte lorsqu'il a un arrière-plan comme dans la réponse de Robert , procédez comme suit:

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

Dans l'exemple ci-dessus, les positions x et y du filtre peuvent être utilisées comme le transform: translate(-10%, -10%)feraient, et les valeurs de largeur et de hauteur peuvent être lues comme 120%et 120%. Nous avons donc agrandi le fond de 20% et l'avons compensé de -10%, de sorte que le fond est maintenant 10% plus grand de chaque côté du texte.

momciloo
la source
0

Les réponses précédentes reposaient sur le doublage du texte et manquaient d'espaces blancs suffisants.

En utilisant atopet &nbsp;j'ai pu obtenir les résultats que je voulais.

Cet exemple inclut également des flèches, un cas d'utilisation courant pour les étiquettes de texte 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>
Le chat d'Henry
la source
-1

Vous pouvez ajouter du style à votre texte:

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

Blanc, dans cet exemple. Ne fonctionne pas dans IE :)

Jan Pi
la source