SVG from Zero to Senior · Part 4 — Text & textPath
SVG text is real, selectable, accessible text living in the coordinate system. Master baseline positioning, text-anchor, multi-line and styled tspans, and the showpiece — flowing a label along any curve with textPath. With a live lab.
Most people reach for HTML when they need words, and SVG when they need shapes. {Đa số dùng HTML khi cần chữ, dùng SVG khi cần hình.} But SVG text is its own superpower: it lives in the coordinate system, scales perfectly, can be filled with gradients, clipped, animated — and crucially, it stays real, selectable, accessible text, not a picture of text. {Nhưng text SVG là siêu năng lực riêng: nó sống trong hệ toạ độ, scale hoàn hảo, có thể tô gradient, clip, animate — và quan trọng, nó vẫn là chữ thật, chọn được, truy cập được, không phải ảnh chụp chữ.}
Drag the controls — move the baseline, change the anchor, bend the curve — then read the rules. {Kéo các control — dịch baseline, đổi anchor, uốn đường cong — rồi mới đọc luật.}
Open the full demo {Mở demo đầy đủ}: /tools/svg-text-demo/.
The baseline gotcha {Cái bẫy baseline}
The number one surprise: in SVG, y is the baseline, not the top of the text. {Bất ngờ số một: trong SVG, y là baseline, không phải đỉnh chữ.}
<text x="20" y="40" font-size="28">Hello SVG</text>
That text sits above y=40, with descenders (the tails of g, y, p) dropping below it. {Chữ đó nằm trên y=40, với phần descender (đuôi g, y, p) thả xuống dưới.} If your text seems to be clipped at the top of the viewBox, you set y too small. {Nếu chữ bị cắt ở đỉnh viewBox, con đặt y quá nhỏ.} Use dominant-baseline="middle" (or central) when you want true vertical centring, e.g. labels inside a circle. {Dùng dominant-baseline="middle" (hoặc central) khi muốn canh giữa dọc thật sự, ví dụ nhãn trong vòng tròn.}
text-anchor — horizontal alignment {text-anchor — canh ngang}
text-anchor decides what the x point means: {text-anchor quyết định điểm x có nghĩa gì:}
start(default) —xis the left edge (in LTR). {xlà mép trái (với văn bản trái-sang-phải).}middle—xis the centre. The go-to for centred labels. {xlà tâm. Lựa chọn cho nhãn canh giữa.}end—xis the right edge. {xlà mép phải.}
<text x="150" y="80" text-anchor="middle">Centred</text>
This is the tool for labels in charts and badges — anchor to a fixed point and the text grows symmetrically. {Đây là công cụ cho nhãn trong biểu đồ và huy hiệu — neo vào một điểm cố định và chữ nở đối xứng.}
tspan — spans, offsets, and fake line breaks {tspan — span, offset, và xuống dòng giả}
SVG text does not wrap automatically and ignores \n. {Text SVG không tự xuống dòng và bỏ qua \n.} To style part of a string or make multiple lines, use <tspan>: {Để style một phần chuỗi hoặc tạo nhiều dòng, dùng <tspan>:}
<text x="20" y="40" font-size="24">
Total:
<tspan fill="#c8ff00" font-weight="600">$1,240</tspan>
</text>
<!-- multi-line: each tspan resets x and nudges y with dy -->
<text x="20" y="40">
<tspan x="20" dy="0">Line one</tspan>
<tspan x="20" dy="1.2em">Line two</tspan>
</text>
dx/dy shift relative to the previous glyph — perfect for superscripts, kerning tweaks, and the line-break pattern above. {dx/dy dịch tương đối so với glyph trước — hoàn hảo cho chỉ số trên, tinh chỉnh kerning, và mẫu xuống dòng ở trên.} If you need real paragraph wrapping, that is a job for HTML inside <foreignObject> — but use it sparingly. {Nếu cần wrap đoạn văn thật, đó là việc của HTML trong <foreignObject> — nhưng dùng tiết kiệm.}
textPath — the showpiece {textPath — món đinh}
Here is the effect you cannot do in plain CSS: text that follows a curve. {Đây là hiệu ứng con không làm được bằng CSS thuần: chữ đi theo đường cong.} Define a path, then reference it from a <textPath>: {Định nghĩa một path, rồi tham chiếu từ <textPath>:}
<defs>
<path id="curve" d="M 20 110 Q 150 40 280 110" />
</defs>
<text font-size="18" fill="#60a5fa">
<textPath href="#curve" startOffset="0%">
SVG TEXT ON A CURVE •
</textPath>
</text>
- The text rides along the path’s length, each glyph rotated to the local tangent. {Chữ chạy dọc theo chiều dài path, mỗi glyph xoay theo tiếp tuyến cục bộ.}
startOffset(a length or%) slides where the text begins — animate it and the text scrolls along the path. {startOffset(độ dài hoặc%) dời chỗ chữ bắt đầu — animate nó và chữ trượt dọc path.}- The referenced path is not drawn unless you also render it; in production give it
stroke="none". {Path được tham chiếu không được vẽ trừ khi con render nó; trong production cho nóstroke="none".}
This powers circular badges (”★ OFFICIAL ★ SELECTION ★”), ribbon labels, and curved chart annotations. {Cái này tạo nên huy hiệu tròn, nhãn ruy băng, và chú thích biểu đồ cong.} Use the old xlink:href only if you must support ancient browsers; modern SVG uses plain href. {Chỉ dùng xlink:href cũ nếu phải hỗ trợ trình duyệt cổ; SVG hiện đại dùng href thường.}
Fonts and the portability trap {Font và cái bẫy chuyển giao}
SVG text uses whatever font is available at render time, exactly like CSS. {Text SVG dùng font nào có sẵn lúc render, y như CSS.} If you ship an SVG that references “Brand Sans” and the viewer doesn’t have it, they get a fallback. {Nếu con ship SVG tham chiếu “Brand Sans” mà người xem không có, họ nhận font dự phòng.} For pixel-perfect logos that must look identical everywhere, designers convert text to paths (outlines) on export — at the cost of losing selectability and accessibility. {Cho logo cần giống hệt mọi nơi, designer chuyển text thành path (outline) khi export — đánh đổi mất khả năng chọn và truy cập.} Senior call: keep text as text for UI and content; outline it only for fixed brand artwork. {Quyết định senior: giữ text là text cho UI và nội dung; chỉ outline cho artwork thương hiệu cố định.}
The master’s warnings {Lời cảnh báo của sư phụ}
yis the baseline. Text disappearing off the top? Increasey. {ylà baseline. Chữ biến mất trên đỉnh? Tăngy.}- No auto-wrap. Long strings overflow the viewBox silently. Plan line breaks with
<tspan>. {Không tự wrap. Chuỗi dài tràn viewBox lặng lẽ. Lên kế hoạch xuống dòng bằng<tspan>.} - textPath needs a real path id in the same document. A broken
hrefrenders nothing, no error. {textPath cần id path thật trong cùng tài liệu.hrefhỏng thì không render gì, không báo lỗi.}
Practice, or it didn’t happen {Luyện tập, không thì coi như chưa học}
- Centred badge label {Nhãn huy hiệu canh giữa}: text with
text-anchor="middle"anddominant-baseline="central"dead-centre in a circle. {text vớitext-anchor="middle"vàdominant-baseline="central"ngay giữa vòng tròn.} - Price line {Dòng giá}: one
<text>with a muted label and a bright<tspan>for the number. {một<text>với nhãn mờ và một<tspan>sáng cho con số.} - Circular stamp {Con dấu tròn}: a circle path +
<textPath>so a slogan wraps around the top. AnimatestartOffsetto rotate it. {path tròn +<textPath>để khẩu hiệu chạy vòng trên. AnimatestartOffsetđể xoay.}
What’s next {Phần tiếp theo}
You can now draw, paint, and letter. {Giờ con vẽ, sơn, và viết chữ được.} But everything so far has been static and flat in one coordinate system. {Nhưng mọi thứ tới giờ vẫn tĩnh và phẳng trong một hệ toạ độ.} In Part 5 we learn to move and reuse: the transform attribute (translate/scale/rotate/skew), why order matters, grouping with <g>, and the mind-bending power of nested coordinate systems with inner <svg> elements. {Ở Phần 5 ta học di chuyển và tái dùng: thuộc tính transform (translate/scale/rotate/skew), vì sao thứ tự quan trọng, gom nhóm bằng <g>, và sức mạnh xoắn não của hệ toạ độ lồng nhau với <svg> bên trong.}