SVG/Tutorials/Text/mehrzeiliger Text

Aus SELFHTML-Wiki
< SVG‎ | Tutorials‎ | Text
Wechseln zu: Navigation, Suche

Eines der großen Mankos von SVG ist die Tatsache, dass Sie längere Texte nicht einfach so notieren können, dass er sich mehrzeilig auf den verfügbaren Platz aufteilt. Genauso ist, anders als in HTML, eine Färbung und Umrahmung der Fläche hinter dem Text nur über Umwege möglich.

  • In HTML bilden alle Elemente Blöcke (→ Box-Modell) mit einer Breite und Höhe. So kann Text eine Farbe, aber auch eine Hintergrundfarbe oder einen Rand erhalten.
  • In SVG besteht Text nur aus den Zeichen oder Glyphen, denen eine Füllung (fill) oder Randlinie (stroke) geben kannst. Der „Hintergrund“ existiert nicht und muss erst erzeugt werden.


mehrzeiliger Text in SVG 2

In SVG 2 erhalten text-Elemente einen Inhaltsbereich (content-area), der mit Breitenangaben oder Formen gestaltet werden kann. Das text-Element gilt als Block-Element, evtl. darin enthaltene Elemente wie tspan und textPath gelten als inline-Elemente.

Hinweis:
Diese Eigenschaften sind neu in SVG2. Sie werden von Browsern noch nicht unterstützt!

inline-size

Die inline-size-Eigenschaft ermöglicht es künftig, Breitenangaben für text festzulegen.

Folgende Werte sind möglich:

Falls kein Wert angegeben wird, gilt es als nicht festgelegt und wird theoretisch unendlich groß, d. h. faktisch nimmt es die Länge des Textes ein.


Beispiel ansehen …
<rect x="10" y="10" width="200" height="150" fill="#5a9905"/>
  <text x="20" y="10" inline-size="180" role="heading">
    Überschrift
  </text>
  <text x="20" y="60" inline-size="180" >
    Dies ist ein Textabsatz mit einem 
    <tspan class="strong">fetten</tspan> 
    Wort und automatischem Zeilenumbruch.
  </text>

In diesem Beispiel besteht der Text aus zwei Text-Elementen mit einer Breite von 180 Einheiten.

Die Überschrift erhält ein role-Attribut mit dem Wert heading - das Aussehen wird mit CSS festgelegt.
Gleiches gilt für den Text, der sich nun automatisch an die festgelegte Breite anpasst und entsprechend umbricht.

shape-inside

Die shape-inside-Eigenschaft ermöglicht es, den Inhaltsbereich auf eine CSS-Form (shape) oder eine SVG-Grundform anzuwenden.

Hauptartikel: CSS/Tutorials/Ausrichtung/Shapes#shape-inside


Beispiel für text-wrap, Quelle: W3C

shape-outside

Die shape-outside-Eigenschaft definiert ein Element, um das Text herumgeführt wird.

Hauptartikel: CSS/Tutorials/Ausrichtung/Shapes#shape-outside


Text mit mehreren tspan-Elementen

Bis dahin bleibt keine andere Möglichkeit als jede vorgesehene Textzeile in ein eigenes tspan-Element zu packen.

Beispiel ansehen …
<text class="mehrzeilig" x="20" y="130">
	<tspan x="10" dy="2em">Mehrzeiliger Text ist möglich, wenn Sie</tspan>
	<tspan x="10" dy="2em">die einzelnen Zeilen in &lt;tspan>-Elemente notieren.</tspan>
	<tspan x="10" dy="2em">Allerdings sind diese Zeilen nicht responsiv.</tspan>
</text>
Jede Zeile des Texts wird von einem eigenen tspan-Element umschlossen und im x-Attribut mit dem jeweils gleichen Wert absolut, mit einer vertikalen Verschiebung durch das dy-Attribut um 2em nach unten relativ positioniert.
text.mehrzeilig tspan {
  x: 20;
  dy: 2em;
  /* funktioniert nicht! */
}

Eine Festlegung mit CSS funktioniert nicht. Der X-Wert würde sich auf das jeweils vorhergehende tspan-Element beziehen. dy ist kein Präsentationsattribut.


Nachteile dieser Methode sind …

  • der aufgeblähte Markup durch die zusätzlichen tspan-Elemente
  • keine Möglichkeit prozentuale Breitenangaben (und damit einen automatischen Umbruch) zu verwenden.

Rahmen um Text erzeugen

Wie oben bereits erwähnt, besteht SVG-Text nur aus den Zeichen oder Glyphen. Der „Hintergrund“ existiert nicht, kann aber mit JavaScript dynamisch erzeugt werden.

SVG-Markup ansehen …
<svg xmlns="http://www.w3.org/2000/svg">

  <text id="txt" x="20" y="40" font-size="24" >Das ist der Text.</text>

</svg>

Mit Javascript können wir den Text selektieren und seine Dimensionen auslesen.

Beispiel ansehen …
document.querySelector('button').addEventListener('click', drawBanner);	

function drawBanner(){ 
  const horizontalPadding = 1.05,
        lineHeight = 1.25;  //größer wegen der Unterlängen!
  var textobj = document.getElementById('txt'),
      textWidth = textobj.getComputedTextLength().toFixed(1),
      textHeight = textobj.getAttribute("font-size"),
      rectobj = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
  rectobj.setAttribute('x', textobj.getAttribute('x') - 5);
  rectobj.setAttribute('y', textobj.getAttribute('y') - textHeight);
  rectobj.setAttribute('height', (lineHeight * textHeight).toFixed(1));
  rectobj.setAttribute('width', (horizontalPadding * textWidth).toFixed(1));
  textobj.parentNode.insertBefore(rectobj, textobj);
};

Mit getComputedLength() wird die Länge des vorhandenen Texts ermittelt und der Variable textWidth übergeben. Die Höhe wird aus der Schriftgröße, die im font-size-Attribut festgelegt wurde, ermittelt und textHeight zugewiesen. (Wenn die Schriftgröße nur im CSS festgelegt wäre, müsste sie dort mit getPropertyCSSValue()ermittelt werden.)

Jetzt wird mit createElementNS() ein neues SVG-Element erzeugt und ihm mit setAttribute() die Geometrie-Attribute mit den passenden Werten hinzugefügt. Die Breite und Höhe errechnet sich aus den ermittelten Werten des Textes, die mit horizontalPadding und lineHeight, die als Konstanten definiert werden, multipliziert. Da in der font-size Unterlängen nicht berücksichtigt wurden, ist der Wert für lineHeight höher. Anschließend wird das neue rect-Element mit insertBefore vor dem Text gezeichnet, da es ja (noch) keinen z-index bei SVG gibt. So wird erst der Hintergrund und Rahmen und dann davor der Text geszeichnet.

Hauptartikel: SVG/Tutorials/SVG_und_JavaScript/DOM-Scripting#SVG-Elemente erzeugen und löschen

durch ein

HTML in SVG

Leider ist es nicht möglich HTML-Elemente direkt in SVG einzubinden. Mit HTML5 wurde es zwar möglich, dass HTML-Browser auch SVG parsen – bei HTML innerhalb von SVG ist dies aber (noch) nicht der Fall.

So wäre es am einfachsten:
<rect x="10" y="10" width="200" height="150" fill="#5a9905">
  <h2>Überschrift</h2>
  <p>Dies ist ein Textabsatz mit einem <strong>fetten</strong> Wort und automatischem Zeilenumbruch.</p>
</rect>

foreignObject

Mit dem foreignObject-Element können Sie jedoch SVG durch andere XML-Formate, unter anderem auch XHTML oder MathML, erweitern.


Beispiel ansehen …
<rect x="10" y="10" width="200" height="150" fill="#5a9905"/>
  <foreignobject x="20" y="10" width="180" height="150">
    <body xmlns="http://www.w3.org/1999/xhtml">
      <h2>Überschrift</h2>
      <p>
        Dies ist ein Textabsatz mit einem <strong>fetten</strong> Wort und automatischem Zeilenumbruch.
      </p>
    </body>
  </foreignobject>
 
<circle cx="300" cy="200" r="100" fill="#dfac20"/>
 <foreignobject x="230" y="120" width="180" height="180">
   <h2>Überschrift</h2>
   <ol>
     <li>Listenelement</li>
     <li>Listenelement</li>
     <li>Listenelement</li>
   </ol>
  </foreignobject>

Wie Sie sehen, hat das zweite foreignObject weder ein requiredExtensions-Attribut noch einen Namensraum.
Wenn Sie SVG in Webseiten mit HTML5-Doctype einbetten, benötigen Sie keine Namensraumdeklaration für die SVG- und die foreignObject-Elemente mehr.

Achtung!

Bitte öffnen Sie das Beispiel mit einem Klick auf "Vorschau" in einem neuen Tab. Im Frickl überschreibt der Parser den body des HTML-Dokuments mit dem body des foreignObjects, sodass das SVG und die SVG-Elemente nicht gerendert werden. --Matthias Scharwies (Diskussion) 15:27, 24. Jun. 2020 (CEST)


Weblinks