I’ve long been an advocate of wrapping (or “flowing” or “multi-line”) text in SVG. This is basic functionality, and people have been asking for it since SVG started.
I’m also an advocate for moving features out of SVG and into CSS, like gradients, animation, compositing, filters, and so on; the benefits of a single code base for HTML and SVG applications, and ease of learning and maintenance, are obvious.
So, I was excited when the CSS WG took up work to allow wrapping text to arbitrary shapes, like circles or stars, not just boxes. This will enable a whole new magazine-style layout that will benefit web sites and ebooks alike. But I was disappointed when I found out that this work had some recent setbacks and delays.
So, I’m calling for a simple solution now, while we wait for the more complete solution later. And the nice thing is, my solution also relies on CSS!
Text in SVG is text. That might seem obvious. But it means that it’s readable, selectable, indexible, searchable, findable, and accessible. Wrapping text might seem like the next logical step for a language that displays text. But believe it or not, about a decade ago, this was considered controversial! In response to SVG 1.2 adding text wrapping, some influential people complained about SVG “duplicating” functionality from HTML and CSS, arguing that SVG is a graphics language, not a text language, and that any line wrapping should only be done using embedded HTML fragments; they also opined (but could not back up with facts) that SVG’s line-wrapping was somehow in “conflict” with the line-wrapping of CSS. The reality was that SVG, being an XML format, was collateral damage in the incipient HTML5 vs. XHTML2 battle, but to appease those who were waging a Distributed Denial of Spec attack, we ultimately ended up removing text-wrapping from SVGT 1.2, deferring to SVG 2.
We didn’t realize how long it would be before we could start in earnest on SVG 2. And all those using SVG in the meantime have suffered not because of technological limitations, but because of politics.
People are forced to embed HTML in their SVG, or manually break the SVG into chunks and use the <tspan> element to specify each line, rather than letting the browser just make the break for them dynamically.
It’s time for that to end.
Simple Text Wrapping
The main use for text in SVG is labels and other short runs of text. We need to prioritize making wrapping and positioning such text easy-peasy.
Since wrapping text in boxes was always easy in SVG, and we were getting pushback about text-wrapping in general, the idea many years ago was to do fancy text-wrapping that you couldn’t do with HTML+CSS: wrap to arbitrary shapes, put text in an hourglass and animate the letters flowing down, make it easy to do the stuff it would be hard to do otherwise. So, the SVG Working Group focused on that. And now that that’s eventually going to be enabled through CSS, we can go back to basics, and meet the needs of people using SVG now.
For simple stuff. Like labels.
But how can we do this incredibly difficult task? What Herculean undertaking, what Rube Goldberg device can let us split a single line of text into multiple lines?
width property (or attribute).
Stay with me, I know it’s hard to understand. By specifying the
width property on a <
text> element, I’m proposing that the text stops when it gets to that point, and that subsequent words are rendered on the next line, where the line-height is dictated by factors like the
line-height properties… you know, like in CSS.
Still fuzzy? Let me draw you a picture:
Really want a ”paragraph” to break the flow of some text into chunks? Use a
<tspan> with a
dy="1em" to create that break in the flow. Want to restrict the height, or use with vertical text? Use the
height property. Want overflow ellipses? Use
text-overflow: clip ellipsis.
I’m all for us also adding support for even more nifty CSS layout features like Flexbox, or even margins and padding… later.
Right now, I want text to wrap when I specify a width on a <
text> element. Basic line-wrapping code already exists in all the major browsers, and SVG is supported in all those browsers. So, browser vendors, let’s see some prototypes! Here’s the code sample for you:
<svg xmlns="http://www.w3.org/2000/svg"> <text x="10" y="25" style="width:150px; font-size:20px; font-family:Georgia, serif; fill:green;"> Wrapping text in SVG is easy! <tspan x="10" dy="2em">And fun, too!</tspan> </text> </svg>
First browser to do something sensible with this wins a prize!
Update: I’ve written up a few more thoughts about simple wrapping of text, including internationalized options, on the SVG Working Group wiki.
Another Update: Mozilla wins the (as-yet-undefined) prize!
Cameron McCormack, SVG WG co-chair, Firefox implementer, and all-around swell guy, responded within a day to my proposal:
I tried implementing part of what you proposed for text wrapping in a rectangular area. I just did the width property bit, not the height property, and you can’t set them using presentation attributes… It also only works for simple length values, not percentages or calc() values… it shows that my quick patch has some problems… For one thing there is a blank line at the top of the rectangle… but try these [temporary] experimental builds out if you’re interested (you need to go to about:config and set the svg.text.css-frames.enabled pref to true):
This is just a rough first pass, but it’s a proof-of-concept that this should be pretty easy to do.
Yet Another Update: Both the SVG and CSS Working Groups have accepted my initial proposal, so the next step is to put it in the SVG 2 spec and incrementally improve it, then persuade implementers to release it in the next major revision of browsers!
(Pipe down, Boromir!)