Textos en SVG

La etiqueta <text> y <tspan>


Es posible que en algunos casos necesitemos incluir textos en nuestras imágenes o fragmentos de código SVG. Para ello, podemos utilizar la etiqueta <text>, que nos permite incluir un bloque de texto en nuestra imagen.

El elemento <text>

Este elemento se utiliza de forma que en su interior se escribe el texto en cuestión que queremos mostrar. Por otro lado, en la propia etiqueta <text> podemos definir una serie de atributos que modificarán la forma en la que se muestra el texto. En la siguiente tabla puedes encontrar una lista de estos elementos:

AtributoValor por defectoDescripción
x / y0Posición en horizontal y vertical del texto respecto al viewBox del elemento.
dx / dynoneDesplazamiento en horizontal y vertical del texto respecto a su posición.
rotatenoneIndica una rotación para cada uno de los carácteres del texto (por separado).
lengthAdjustspacingIndica el tipo de ajuste de carácteres. spacingAndGlyphs evita solapamiento.
textLengthnoneIndica una distancia entre carácteres. Usado junto al atributo anterior.

Ten en cuenta, que al margen de estos atributos, también es posible usar atributos de la familia de tipografías de CSS, tanto como atributo HTML del elemento SVG, como de propiedad CSS aplicada a él. Tienes una lista un poco más adelante, en Atributos CSS de tipografía.

Posición del texto (x / y)

Mediante los atributos x e y, puedes indicar la posición respecto al viewBox del elemento SVG del texto en cuestión. Observa el siguiente ejemplo, donde tenemos 3 elementos <text> con sus respectivas posiciones x e y. Además, fíjate en las clases que tienen definidas y que uno de ellos, también tiene una transformación de rotación:

<svg viewBox="0 0 300 100" height="300">
  <text class="name" x="35" y="40">ManzDev</text>
  <text class="fragment" x="85" y="55" transform="rotate(-5)">En busca de</text>
  <text class="subtitle" x="35" y="55">La documentación de SVG perfecta</text>
</svg>
.name {
  font-family: Jost;
  font-size: 20px;
  font-weight: 800;
}

.fragment {
  font-family: Jost;
  font-size: 8px;
  font-weight: 600;
  font-style: italic;
  fill: red;
}

.subtitle {
  font-family: EnterCommand;
  font-size: 15px;
  font-weight: 600;
  fill: indigo;
}

Observa que hemos añadido toda la cuestión de estilos de texto en la parte de CSS, aplicada a los elementos mediante sus clases, aunque podríamos haberlo hecho como atributos del elemento, en el código HTML. Sin embargo, se ha separado para que el ejemplo se vea más claro.

Desplazamiento (dx / dy)

Mediante los atributos dx y dy, podemos conseguir desplazamientos tanto en horizontal como en vertical, respecto a la posición que ya tenía en x e y. Vamos a modificar el ejemplo anterior, para añadirle un desplazamiento, que puedes modificar de forma interactiva en el siguiente ejemplo:

<p>Valor de <code>dx</code> del fragmento rojo:
  <input class="dx" type="range" min="0" max="25" value="5">
  <output>5</output>
</p>
<p>Valor de <code>dy</code> del subtítulo:
  <input class="dy" type="range" min="0" max="25" value="10">
  <output>10</output>
</p>

<svg viewBox="0 0 300 100" height="300">
  <text class="name" x="35" y="40">ManzDev</text>
  <text class="fragment" x="85" y="55" dx="5" transform="rotate(-5)">En busca de</text>
  <text class="subtitle" x="35" y="55" dy="10">La documentación de SVG perfecta</text>
</svg>
const [dx, dy] = document.querySelectorAll(".dx, .dy");
const fragment = document.querySelector(".fragment");
const subtitle = document.querySelector(".subtitle");

dx.addEventListener("input", () => {
  fragment.setAttribute("dx", dx.value);
  dx.nextElementSibling.value = dx.value;
});
dy.addEventListener("input", () => {
  subtitle.setAttribute("dy", dy.value);
  dy.nextElementSibling.value = dy.value;
});
.name {
  font-family: Jost;
  font-size: 20px;
  font-weight: 800;
}

.fragment {
  font-family: Jost;
  font-size: 8px;
  font-weight: 600;
  font-style: italic;
  fill: red;
}

.subtitle {
  font-family: EnterCommand;
  font-size: 15px;
  font-weight: 600;
  fill: indigo;
}

Observa que en el caso del fragmento rojo, el elemento tiene una transformación, por lo que el desplazamiento se realiza teniendo en cuenta la transformación realizada previamente.

Rotación de carácteres (rotate)

Mediante el atributo rotate podemos establecer rotaciones independientes a cada caracter del texto. Ten muy presente que no se trata de una transformación de rotación transform="rotate()", que se aplicaría en conjunto a todo el texto, sino que se aplica carácter por carácter.

El valor a indicar en el atributo rotate debe ser un valor numérico que indica el número de grados. Veamos un ejemplo aplicado a nuestra demostración anterior:

<p>Rotación del subtítulo:
  <input class="rotate" type="range" min="0" max="360" value="0">
  <output>0</output>
</p>

<svg viewBox="0 0 300 100" height="300">
  <text class="name" x="35" y="40">ManzDev</text>
  <text class="fragment" x="85" y="55" transform="rotate(-5)">En busca de</text>
  <text class="subtitle" x="35" y="55" rotate="0">La documentación de SVG perfecta</text>
</svg>
const rotate = document.querySelector(".rotate");
const subtitle = document.querySelector(".subtitle");

rotate.addEventListener("input", () => {
  subtitle.setAttribute("rotate", rotate.value);
  rotate.nextElementSibling.value = rotate.value;
});
.name {
  font-family: Jost;
  font-size: 20px;
  font-weight: 800;
}

.fragment {
  font-family: Jost;
  font-size: 8px;
  font-weight: 600;
  font-style: italic;
  fill: red;
}

.subtitle {
  font-family: EnterCommand;
  font-size: 15px;
  font-weight: 600;
  fill: indigo;
}

Tamaño y ajuste de texto

El atributo textLength permite establecer un grado de compactación y expansión en cada caracter. De esta forma puedes conseguir que los carácteres están más o menos unidos entre sí. Además, puedes utilizar el atributo lengthAdjust para indicar si quieres que se solapen los carácteres (valor por defecto), o si prefieres usar la opción spacingAndGlyphs, donde los carácteres no se solapan unos con otros, y se modifica su tamaño.

Veamos un ejemplo donde se refleja mejor estos detalles:

<p>Valor de <code>textLength<code>:
  <input class="tl" type="range" min="0" max="250" value="0">
  <output>0</output>
</p>
<p>Valor de <code>lengthAdjust</code>:</p>
<select class="la">
  <option>spacing</option>
  <option>spacingAndGlyphs</option>
</select>

<svg viewBox="0 0 300 100" height="300">
  <text class="name" x="35" y="40">ManzDev</text>
  <text class="fragment" x="85" y="55" transform="rotate(-5)">En busca de</text>
  <text class="subtitle" x="35" y="55">La documentación de SVG perfecta</text>
</svg>
const tl = document.querySelector(".tl");
const la = document.querySelector(".la");
const subtitle = document.querySelector(".subtitle");

tl.addEventListener("input", () => {
  subtitle.setAttribute("textLength", tl.value);
  tl.nextElementSibling.value = tl.value;
});
la.addEventListener("change", () => subtitle.setAttribute("lengthAdjust", la.value));
.name {
  font-family: Jost;
  font-size: 20px;
  font-weight: 800;
}

.fragment {
  font-family: Jost;
  font-size: 8px;
  font-weight: 600;
  font-style: italic;
  fill: red;
}

.subtitle {
  font-family: EnterCommand;
  font-size: 15px;
  font-weight: 600;
  fill: indigo;
}

select {
  font-size: 1.5rem;
  padding: 0.5rem;
}

Atributos CSS de tipografías

Habrás observado que en los elementos relacionados con tipografías de SVG, hemos utilizado atributos o propiedades CSS para definir como se verá la tipografía. Esta es una lista de dichas propiedades o atributos que podemos utilizar:

Atributo CSSValor por defectoDescripciónMás información
font-familyTipografía a usarVer propiedad font-family.
font-sizemediumTamaño de la tipografía.Ver propiedad font-size.
font-size-adjustnoneAjuste de tipografía.Ver propiedad font-size-adjust.
font-stretchnormalGrado de compactación de la fuente.Ver propiedad font-stretch.
font-stylenormalEstilo: normal, cursiva, etc...Ver propiedad font-style.
font-variantnormalVariaciones de la tipografías.Ver propiedad font-variant.
font-weightnormalPeso o grosor de la tipografía.Ver propiedad font-weight.

El elemento <tspan>

Hasta ahora, habrás comprobado que los textos indicados en el elemento <text> son un texto en conjunto, sin embargo, puede ser que necesitemos crear pequeños fragmentos dentro de ese texto. Para ello, se utilizará la etiqueta <tspan>. Esta etiqueta tiene los mismos atributos que la etiqueta <text>, sin embargo, la diferencia es que se utiliza para crear fragmentos pequeños de un texto mayor.

Veamos un ejemplo donde se vea su utilización:

<svg viewBox="0 0 300 100" height="300">
  <text class="name" x="35" y="40">ManzDev</text>
  <text class="fragment" x="85" y="55" transform="rotate(-5)">En busca de</text>
  <text class="subtitle" x="35" y="55">La
    <tspan fill="deeppink" textLength="110">documentación</tspan>
    de SVG <tspan fill="black">perfecta</tspan>
  </text>
</svg>
.name {
  font-family: Jost;
  font-size: 20px;
  font-weight: 800;
}

.fragment {
  font-family: Jost;
  font-size: 8px;
  font-weight: 600;
  font-style: italic;
  fill: red;
}

.subtitle {
  font-family: EnterCommand;
  font-size: 15px;
  font-weight: 600;
  fill: indigo;
}

¿Quién soy yo?

Soy Manz, vivo en Tenerife (España) y soy streamer partner en Twitch y profesor. Me apasiona el universo de la programación web, el diseño y desarrollo web y la tecnología en general. Aunque soy full-stack, mi pasión es el front-end, la terminal y crear cosas divertidas y locas.

Puedes encontrar más sobre mi en Manz.dev