> [Site index](https://perfectvector.com/llms.txt) — available pages and descriptions.

# SVG-Textumbruch: Gemessene Zeilen mit tspan erstellen

> Brich SVG-Beschriftungen um, indem du Wörter mit der tatsächlichen Schrift misst und tspans erzeugst. Prüfe schmale Labels, lehne Überlauf ab und speichere das Ergebnis.

Source: https://perfectvector.com/de/blog/svg-text-wrap-tspan

Language: de
Author: Irene Kim
Published: 2026-10-06T08:00:00+09:00
Updated: 2026-10-06T08:00:00+09:00

Um eine wechselnde SVG-Beschriftung in ausdrückliche Zeilen umzubrechen, miss mögliche Wortgruppen mit `getComputedTextLength()` und schreibe dann für jede akzeptierte Zeile ein `<tspan>`. Warte zuerst auf die Schriften des Dokuments und entscheide, was geschieht, wenn ein Wort breiter als die Beschriftung ist oder das Ergebnis die Zeilengrenze überschreitet.

Die folgende Vorlage verwendet durch Leerraum getrennte Wörter und lehnt beide Überlauffälle ab, ohne eine teilweise Beschriftung auszugeben. Sie hält eine selbst erstellte Illustration einer hohlen Raute vom Wortlaut getrennt. Eine Änderung der Beschriftungsbreite zeichnet die Grafik deshalb nicht neu.

## Wähle eine Umbruchregel, bevor du Zeilen platzierst

Mit dem [`tspan`-Element](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/tspan) kannst du Teile von SVG-Text positionieren. Unsere Routine setzt an jeder Zeile dasselbe `x` und an Folgezeilen einen `dy`-Versatz. Die Routine entscheidet über den Zeilenumbruch; das Element hält das Ergebnis.

Das ist ein Ansatz mit ausdrücklichem Layout. Die [SVG-2-Textspezifikation](https://www.w3.org/TR/SVG2/text.html) definiert auch automatischen Umbruch über einen Inhaltsbereich und CSS-Textlayout. Dieser Artikel testet diese Funktionen nicht und behauptet nicht, dass diese Funktionen in allen Browsern fehlen.

Für einen HTML-Absatz außerhalb der Illustration kannst du mit CSS [Text um eine schwebende SVG-Silhouette fließen lassen](https://perfectvector.com/de/blog/css-text-around-svg-shape). Dieses Layout folgt einer Bildkontur, während der Wortlaut gewöhnliches HTML bleibt, statt zu positionierten SVG-Beschriftungszeilen zu werden.

Für dieses kleine Beispiel mit englischer Beschriftung gilt:

* Fasse Leerraum zusammen und probiere Wörter in ihrer ursprünglichen Reihenfolge mit einfachen Leerzeichen dazwischen.
* Behalte eine mögliche Zeile nur, solange ihre gemessene Länge in die verfügbare Breite passt.
* Lehne ein Wort ab, das allein nicht passt. Erfinde keine Silbentrennungsstelle.
* Lehne das ganze Ergebnis ab, wenn es mehr als `maxLines` benötigt. Lass die letzten Wörter nicht unbemerkt weg.

Eine Zeilengrenze ist eine Layoutentscheidung. Wähle sie zusammen mit Startgrundlinie, Zeilenabstand und verfügbarer Höhe. Der Umbruchcode berechnet keinen vertikalen Inhaltsrahmen für dich.

**Beschriftungsbreite ändern, Grafik behalten**

![Schematischer Vergleich einer Illustration einer hohlen Raute neben längeren Zeilen in einer breiten und kürzeren Zeilen in einer schmalen Beschriftung](https://perfectvector.com/blog/svg-text-wrap-tspan/measured-lines.webp)

*Illustration: Eine schmalere Beschriftung kann mehr Zeilen benötigen. Abstrakte Balken und gepunktete Rahmen sind schematische Hinweise. Tatsächlicher Wortlaut, Messungen und Ablehnungszustände unten stammen aus der unabhängigen Browservorlage.*

## Miss mit der Schrift, die die Beschriftung zeichnet

[`getComputedTextLength()`](https://developer.mozilla.org/en-US/docs/Web/API/SVGTextContentElement/getComputedTextLength) misst die berechnete Länge von SVG-Text. Diese Vorlage klont das Textelement der Beschriftung als unsichtbare Messprobe innerhalb desselben eingebundenen SVGs. Nach der Zeilenplanung entfernt sie die Probe. Beide verwenden ausdrücklich `Arial, sans-serif` mit 22 Einheiten.

Der Code wartet vor dem Messen auf [`document.fonts.ready`](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready). Das wartet auf das Laden der Dokumentschriften und das zugehörige Layout. Es bettet keine Schrift in das exportierte SVG ein. Eine andere verfügbare Schrift kann andere Zeilenlängen ergeben. Führe das Layout bei geändertem Wortlaut, Schrifteinstellungen oder verfügbarer Breite erneut aus.

## Führe die vollständige Vorlage ohne Abhängigkeiten aus

Speichere dies als `starter.html` und öffne es im Browser. Es erstellt sechs Fälle, gibt ihre Messungen aus und serialisiert jedes entstandene SVG. Die ersten beiden ändern nur die Beschriftungsbreite, der dritte den Wortlaut. Die übrigen prüfen Ablehnungen und wörtlichen Text.

```html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Measured SVG label lines</title>
<style>
  body { margin: 24px; font: 16px system-ui; background: #f6f2e8; }
  #cases { display: grid; grid-template-columns: repeat(2, 360px); gap: 20px; }
  figure { margin: 0; }
  svg { display: block; background: white; }
  figcaption { margin: 6px 0; }
  pre { white-space: pre-wrap; font-size: 12px; }
</style>
<h1>Keep artwork and label layout separate</h1>
<div id="cases"></div>
<pre id="report"></pre>
<script>
  const ns = 'http://www.w3.org/2000/svg';
  const emblem = 'M60 32 L100 72 L60 112 L20 72 Z M60 54 L78 72 L60 90 L42 72 Z';
  function element(name, attributes) {
    const node = document.createElementNS(ns, name);
    for (const [key, value] of Object.entries(attributes)) node.setAttribute(key, value);
    return node;
  }
  function wrapWords(text, source, { width, maxLines, lineHeight }) {
    text.replaceChildren();
    if (!(width > 0 && lineHeight > 0 && Number.isInteger(maxLines) && maxLines > 0)) {
      return { status: 'invalid-options', lines: [] };
    }
    const words = source.trim().split(/\s+/u).filter(Boolean);
    const probe = text.cloneNode(false);
    probe.setAttribute('visibility', 'hidden');
    text.parentNode.append(probe);
    const measure = value => { probe.textContent = value; return probe.getComputedTextLength(); };
    const lines = [];
    let line = '';
    try {
      for (const word of words) {
        const wordWidth = measure(word);
        if (wordWidth > width) {
          return { status: 'overlong-word', word, measuredWidth: wordWidth, lines: [] };
        }
        const candidate = line ? line + ' ' + word : word;
        if (line && measure(candidate) > width) {
          lines.push(line);
          line = word;
        } else line = candidate;
      }
      if (line) lines.push(line);
      if (lines.length > maxLines) {
        return { status: 'too-many-lines', requiredLines: lines.length, lines: [] };
      }
      const x = text.getAttribute('x');
      lines.forEach((value, index) => {
        const span = element('tspan', { x, dy: index ? lineHeight : 0 });
        span.textContent = value;
        text.append(span);
      });
      return { status: 'ok', lines,
        lengths: [...text.children].map(span => span.getComputedTextLength()) };
    } finally { probe.remove(); }
  }
  const cases = [
    { id: 'normal', source: 'Keep artwork and labels separate', width: 200, maxLines: 4 },
    { id: 'narrow', source: 'Keep artwork and labels separate', width: 110, maxLines: 5 },
    { id: 'changed', source: 'Keep the original artwork beside every exported label', width: 200, maxLines: 4 },
    { id: 'long-word', source: 'Artwork supercalifragilisticexpialidocious', width: 110, maxLines: 5 },
    { id: 'line-limit', source: 'Keep artwork and labels separate', width: 110, maxLines: 2 },
    { id: 'literal', source: 'Cove <g> & field', width: 200, maxLines: 4 },
  ];
  const entries = cases.map(test => {
    const figure = document.createElement('figure');
    const svg = element('svg', { width: 360, height: 240, viewBox: '0 0 360 240' });
    svg.append(element('path', { d: emblem, fill: '#176b5b', 'fill-rule': 'evenodd' }));
    svg.append(element('rect', { x: 140, y: 34, width: test.width, height: 170,
      fill: 'none', stroke: '#ce7b55', 'stroke-dasharray': '4 4' }));
    const text = element('text', { x: 140, y: 60, 'font-family': 'Arial, sans-serif',
      'font-size': 22, fill: '#172b34' });
    svg.append(text);
    const caption = document.createElement('figcaption');
    figure.append(svg, caption);
    document.getElementById('cases').append(figure);
    return { test, svg, text, caption };
  });
  async function run() {
    await document.fonts.ready;
    const results = entries.map(({ test, svg, text, caption }) => {
      const result = wrapWords(text, test.source, { ...test, lineHeight: 30 });
      caption.textContent = test.id + ': ' + result.status;
      return { ...test, ...result, fontFamily: getComputedStyle(text).fontFamily,
        fontSize: getComputedStyle(text).fontSize, tspanCount: text.children.length,
        pathD: svg.querySelector('path').getAttribute('d'),
        pathCount: svg.querySelectorAll('path').length,
        imageCount: svg.querySelectorAll('image').length,
        foreignObjectCount: svg.querySelectorAll('foreignObject').length,
        serialized: new XMLSerializer().serializeToString(svg) };
    });
    document.getElementById('report').textContent = JSON.stringify({
      fontStatus: document.fonts.status, policy: 'Whitespace words; reject a long word or too many lines without partial output', results,
    }, null, 2);
  }
  run();
</script>
</html>
```

Die Routine erstellt jede Zeile mit [`textContent`](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent), statt den Wortlaut als Markup einzufügen. Im Fall mit wörtlichem Text bleibt `Cove <g> & field` gewöhnlicher Text. Das serialisierte SVG enthält maskierte spitze Klammern und ein kaufmännisches Und, kein zusätzliches Gruppenelement.

Der Messklon ist eingebunden, aber verborgen und hat dieselben Schriftattribute wie die sichtbare Beschriftung. Er wird in `finally` entfernt, auch bei einer Ablehnung. Zeilen werden erst nach bestandener Wortbreiten- und Maximalzeilenprüfung angehängt. Die Routine löscht zuerst jede vorherige Beschriftung. Eine abgelehnte Aktualisierung hinterlässt daher weder alten noch teilweisen Text. Behandle den zurückgegebenen Status in deiner Anwendungsoberfläche.

## Was die sechs ursprünglichen Fälle ergaben

Wir führten genau diese Vorlage in Chrome aus, wobei die Dokumentschriften `loaded` meldeten. Die folgenden Messlängen sind SVG-Textlängen in dieser Umgebung, keine gezeichneten Glyphengrenzen oder Garantie für Schriftportabilität.

| Fall                                             | Breite / maximale Zeilen | Ergebnis                                         | Beobachtete längste Zeile     |
| ------------------------------------------------ | ------------------------ | ------------------------------------------------ | ----------------------------- |
| Ursprünglicher Satz                              | 200 / 4                  | Zwei Zeilen: Keep artwork and; labels separate   | 172.44                        |
| Derselbe Satz, schmaler Rahmen                   | 110 / 5                  | Vier Zeilen: Keep; artwork; and labels; separate | 100.30                        |
| Längerer Wortlaut                                | 200 / 4                  | Drei Zeilen                                      | 198.13                        |
| Überlanges Wort                                  | 110 / 5                  | overlong-word; null tspans                       | Gemessene Wortbreite 311.82   |
| Schmaler Satz, Grenze zwei Zeilen                | 110 / 2                  | too-many-lines; vier erforderlich; null tspans   | Keine Beschriftung ausgegeben |
| Wörtliche spitze Klammern und kaufmännisches Und | 200 / 4                  | Eine wörtliche Zeile                             | 162.66                        |

Der ursprüngliche Satz lautet `Keep artwork and labels separate`. Die längere Version lautet `Keep the original artwork beside every exported label`. Jede akzeptierte Zeile blieb gemessen innerhalb ihrer gewählten Breite. Die Ablehnungsfälle ließen die Illustration sichtbar und die Beschriftung weg. So war der Fehlerzustand leicht zu prüfen.

Alle sechs serialisierten Dateien behielten den identischen ursprünglichen Rautenpfad, ein natives Textelement und kein Bild oder `foreignObject`. Die akzeptierten Fälle enthielten jeweils zwei, vier, drei und ein tspan. Beide abgelehnten Fälle enthielten null. Wir öffneten außerdem die sechs serialisierten SVGs im selben Browser erneut als Bilder. Alle wurden mit 360×240 geladen. Das prüft diese Dateien und diesen Browser, nicht jeden Editor oder Renderer.

## Speichere das gesetzte SVG und teste die Ausgabe

[`XMLSerializer.serializeToString()`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer/serializeToString) erstellt das serialisierte Markup im Bericht. Speichere die `serialized`-Zeichenfolge eines erfolgreichen Falls als `.svg`-Datei. Die Datei enthält bereits ausdrückliche Zeilen. Sie benötigt diese JavaScript-Routine nicht, um sie wiederherzustellen.

Die Wörter bleiben aktiver Text. Die gespeicherte Datei behält die Schriftfamilienanforderung, keine Schriftdatei oder in Pfade umgewandelte Glyphen. Ein Ziel mit anderer Schrift kann die Buchstaben verändern, obwohl Zeilenzeichenfolgen und Positionen bestehen bleiben. Behalte ursprünglichen Wortlaut und Layouteingaben neben der exportierten Kopie und prüfe das tatsächliche Ziel vor der Übergabe. Für eine feste Buchstabenform erstelle in einem geeigneten Quelleditor eine Ausgabekopie mit Schriftpfaden und bewahre aktiven Text in der Masterdatei.

Der [foreignObject-Textleitfaden](https://perfectvector.com/de/blog/svg-foreignobject-text) behandelt HTML-Beschriftungen, die in einem anderen Renderer verschwinden. Diese Vorlage erstellt stattdessen von Anfang an nativen Text. Der [textLength-Leitfaden](https://perfectvector.com/de/blog/svg-textlength-fit) behandelt das Einpassen einer einzelnen Zeile durch Längenanpassung. Das ist eine andere Entscheidung als das Hinzufügen gemessener Zeilen. Nutze den [Leitfaden zur vertikalen Ausrichtung](https://perfectvector.com/de/blog/svg-text-vertical-alignment), wenn du die gesamte Beschriftung relativ zur umgebenden Grafik positionieren musst.

## Halte die Grenzen des Umbruchcodes ausdrücklich fest

Die Trennung an Leerraum ist bewusst eine kleine Regel. Sie fasst wiederholte Leerzeichen, Tabulatoren und ausdrückliche Zeilenumbrüche zusammen. Sprachspezifische Umbruchregeln, Silbentrennung, bidirektionale Absätze und formatierte Textteile mit gemischten Stilen behandelt sie nicht. Wähle ein anderes Layoutsystem oder erweitere und teste die Regel, wenn dein Text diese Funktionen braucht.

Die Breitenprüfung garantiert auch nicht, dass dekorative Glyphenüberhänge innerhalb eines gezeichneten Rahmens bleiben oder fünf Grundlinien in deine gewählte Höhe passen. Prüfe die sichtbare Schrift bei Ausgabegröße. Unsere Testdatei verwendet horizontale Beschriftungen, feste Schriftattribute und einen Zeilenschritt von 30 Einheiten. Übertrage ihre Messzahlen nicht auf eine andere Schrift, ohne erneut zu messen.

Liegt deine Illustration nur als PNG oder JPG vor und brauchst du bearbeitbare Grafik, [bereite mit PerfectVector ein Clipart-SVG vor](https://perfectvector.com/de/clipart-to-svg). Prüfe Kanten und innere Öffnungen und halte diese Grafik von der Beschriftung getrennt. Tippe den Wortlaut als nativen Text neu, führe die Umbruchregel aus und prüfe den zusammengesetzten Export. Vektorisierung bereitet Illustrationspfade vor. Sie wählt keine Zeilenumbrüche und gewinnt keine bearbeitbaren Wörter aus nachgezeichneten Buchstaben zurück. Vorhandene gute Pfade können bleiben. Der [Vektorisierungsleitfaden](https://perfectvector.com/de/blog/what-is-image-vectorization) erklärt diesen Wiederherstellungsschritt.

## Häufige Fragen

**Entscheidet tspan automatisch, wo jede Zeile umbricht?**
Diese Vorlage entscheidet durch Messen von Wortgruppen und erstellt dann für jede akzeptierte Zeile ein positioniertes tspan. Sie testet den CSS-basierten automatischen Umbruch von SVG 2 nicht.

**Was passiert mit einem Wort, das breiter als die Beschriftung ist?**
Die Routine gibt overlong-word zurück und erzeugt keine Beschriftung. Verbreitere den Bereich, kürze den Wortlaut oder stelle eine separat getestete Umbruchregel bereit, statt ihn unbemerkt abzuschneiden.

**Entfernt maxLines die übrigen Wörter?**
Nein. Diese Regel lehnt ein Ergebnis mit zu vielen Zeilen ab, meldet die erforderliche Anzahl und lässt null tspans zurück. Die Anwendung muss diesen Status behandeln.

**Sehen exportierte Zeilen mit einer anderen Schrift identisch aus?**
Die ausdrücklichen Wörter und Positionen bleiben, aber die Datei bettet keine Schrift ein und wandelt Glyphen nicht in Pfade um. Prüfe verfügbare Schrift und Buchstaben am tatsächlichen Ziel.

## Quellen

1. [MDN-tspan-Element](https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Element/tspan) – Positionierter Teiltext und Zeilenversatzattribute.
2. [W3C-SVG-2-Text](https://www.w3.org/TR/SVG2/text.html) – Ausdrückliche Positionierung und separates automatisches Umbruchmodell.
3. [MDN getComputedTextLength](https://developer.mozilla.org/en-US/docs/Web/API/SVGTextContentElement/getComputedTextLength) – Tatsächlichen SVG-Text messen.
4. [MDN FontFaceSet.ready](https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/ready) – Auf Schriftladen und Layout warten.
5. [MDN textContent](https://developer.mozilla.org/en-US/docs/Web/API/Node/textContent) – Klartext statt Markup einfügen.
6. [MDN XMLSerializer](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer/serializeToString) – Fertig gesetztes SVG-Markup speichern.

***

Für deine eigene Rasterillustration [bereite bearbeitbare Clipart-Grafik vor](https://perfectvector.com/de/clipart-to-svg), prüfe ihre Formen und behalte die Masterdatei. Füge den Wortlaut separat hinzu und prüfe vor der Übergabe akzeptierte Zeilen und sichtbare Schrift im gespeicherten SVG.

## Explore

- [Read the HTML article](https://perfectvector.com/de/blog/svg-text-wrap-tspan)
- [SVG.js: Grafik importieren, Pfad ändern und SVG exportieren](https://perfectvector.com/de/blog/svgjs-import-export-artwork.md)
- [Leaflet-SVG-Marker: Spitze mit iconAnchor ausrichten](https://perfectvector.com/de/blog/leaflet-svg-marker-anchor.md)
- [Product facts](https://perfectvector.com/product-facts.md)
- [FAQ](https://perfectvector.com/faq.md)
- [Pricing and credits](https://perfectvector.com/pricing.md)
