jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 1 — Foundations & the viewBox

Start SVG the right way: what SVG really is, the coordinate system, the basic shapes, and the one concept that confuses everyone — viewBox. With a live pan/zoom playground you can drag.

Welcome, young padawan. {Chào mừng, đồ đệ.} For the next ten parts the old master will take you from “I copy-paste SVG icons and pray” to “I can build, animate, and ship vector graphics like a senior.” {Trong mười phần tới, sư phụ già sẽ đưa con từ “tôi copy-paste icon SVG rồi cầu nguyện” lên “tôi dựng, animate, và ship đồ hoạ vector như một senior.”}

Here is the first truth: SVG is not an image format, it is a drawing language. {Sự thật đầu tiên: SVG không phải định dạng ảnh, nó là một ngôn ngữ vẽ.} A PNG is a grid of fixed pixels; an SVG is a set of instructions (“draw a circle here, this big”) that the browser re-draws at any size, perfectly sharp. {PNG là lưới pixel cố định; SVG là tập chỉ dẫn (“vẽ hình tròn ở đây, to cỡ này”) mà trình duyệt vẽ lại ở mọi kích thước, sắc nét tuyệt đối.} That is why your logo looks crisp on a 4K monitor and a smartwatch from the same file. {Vì thế logo của con sắc nét cả trên màn 4K lẫn smartwatch từ cùng một file.}

Play with the demo first — drag the viewBox sliders, feel how the window moves over the drawing, then read why. {Nghịch demo trước — kéo slider viewBox, cảm nhận cửa sổ di chuyển trên bản vẽ, rồi mới đọc lý do.}

Open the full demo {Mở demo đầy đủ}: /tools/svg-shapes-demo/.

The skeleton of every SVG {Bộ xương của mọi SVG}

You can write SVG straight into HTML — no <img> needed. {Con có thể viết SVG thẳng vào HTML — không cần <img>.} This is inline SVG, and it is what unlocks styling and scripting later. {Đây là inline SVG, và nó mở khoá việc style và scripting sau này.}

<svg viewBox="0 0 100 100" width="200" height="200">
  <circle cx="50" cy="50" r="40" fill="#c8ff00" />
</svg>

Read it like a sentence: {Đọc nó như một câu:} “In a coordinate space 100×100, draw a circle centred at (50,50) with radius 40, painted lime, and display it 200×200 pixels on the page.” {“Trong không gian toạ độ 100×100, vẽ hình tròn tâm (50,50) bán kính 40, tô màu lime, và hiển thị 200×200 pixel trên trang.”}

The coordinate system — graph paper, but Y points down {Hệ toạ độ — giấy kẻ ô, nhưng Y hướng xuống}

The single most important picture to burn into your mind: {Bức tranh quan trọng nhất phải khắc vào đầu:}

(0,0) ───────────► +X

  │     • (50,30)


 +Y
  • The origin (0,0) is the top-left, not the centre. {Gốc (0,0)góc trên-trái, không phải tâm.}
  • X grows to the right — same as maths. {X tăng sang phải — giống toán.}
  • Y grows downward — the opposite of school maths, the same as every screen. {Y tăng xuống dưới — ngược với toán phổ thông, giống mọi màn hình.}

Every cx, cy, x, y you ever write lives in this space. {Mọi cx, cy, x, y con từng viết đều sống trong không gian này.}

viewBox — the idea that confuses everyone {viewBox — khái niệm làm ai cũng rối}

Beginners think width/height and viewBox are the same. They are not, and understanding the difference is the whole point of Part 1. {Người mới tưởng width/heightviewBox giống nhau. Không phải, và hiểu khác biệt này chính là trọng tâm Phần 1.}

  • width/height (or CSS) = how big the SVG box is on the page, in real pixels. {= cái khung SVG to cỡ nào trên trang, tính bằng pixel thật.}
  • viewBox="min-x min-y width height" = which slice of the infinite drawing surface you crop out, in user units. {= con cắt ra lát nào của mặt vẽ vô hạn, tính bằng user unit.}

The browser then stretches that cropped slice to fill the box. {Trình duyệt rồi kéo lát cắt đó cho đầy cái khung.} So viewBox gives you free pan and zoom: {Nên viewBox cho con pan và zoom miễn phí:}

<!-- Same drawing, two windows over it -->
<svg viewBox="0 0 200 200">...</svg>   <!-- full scene -->
<svg viewBox="50 50 100 100">...</svg>  <!-- zoomed into the middle -->

The mental model: viewBox is a camera frame floating over your graph paper. {Mô hình tư duy: viewBox là khung máy ảnh lơ lửng trên giấy kẻ ô.} Move min-x/min-y → the camera pans. Shrink width/height → fewer units fill the same pixels → zoom in. {Dịch min-x/min-y → máy ảnh lia. Thu nhỏ width/height → ít unit lấp đầy cùng số pixel → zoom vào.} The demo’s “world view” draws that camera frame as a dashed rectangle so you can see it. {“World view” trong demo vẽ khung máy ảnh đó thành hình chữ nhật nét đứt để con thấy được.}

Senior habit: set viewBox and let CSS control the rendered size. Drop hard-coded width/height and the SVG becomes fluid. {Thói quen senior: đặt viewBox rồi để CSS điều khiển kích thước hiển thị. Bỏ width/height cứng và SVG trở nên co giãn.}

preserveAspectRatio — what if the box and the viewBox disagree? {preserveAspectRatio — nếu khung và viewBox lệch tỉ lệ?}

If your box is 300×100 but your viewBox is square, something has to give. {Nếu khung 300×100 nhưng viewBox vuông, phải có cái gì nhường.} By default preserveAspectRatio="xMidYMid meet" keeps the aspect ratio and centres the drawing (letterboxing). {Mặc định xMidYMid meet giữ tỉ lệ và canh giữa (viền đen kiểu letterbox).} Use slice to fill-and-crop instead, or none to stretch (rarely what you want). {Dùng slice để lấp-đầy-rồi-cắt, hoặc none để kéo méo (hiếm khi con muốn).}

<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid slice">…</svg>

The basic shapes — your vocabulary {Các hình cơ bản — vốn từ của con}

Before paths (Part 2), six primitives cover a surprising amount: {Trước khi tới path (Phần 2), sáu primitive đã làm được nhiều bất ngờ:}

<rect x="10" y="10" width="80" height="50" rx="6" />     <!-- rounded box -->
<circle cx="50" cy="50" r="40" />                         <!-- center + radius -->
<ellipse cx="50" cy="50" rx="40" ry="25" />               <!-- two radii -->
<line x1="0" y1="0" x2="100" y2="100" />                  <!-- a segment -->
<polyline points="0,40 20,10 40,40 60,10" />             <!-- open path of points -->
<polygon points="50,5 90,90 10,90" />                     <!-- auto-closed shape -->

The one gotcha: a <line> or <polyline> is invisible without a stroke — it has no area to fill. {Một cái bẫy: <line> hay <polyline> vô hình nếu không có stroke — nó không có diện tích để fill.} And <polygon> silently closes itself back to the first point, while <polyline> stays open. {Và <polygon> tự lặng lẽ đóng về điểm đầu, còn <polyline> thì để hở.} Toggle them in the demo and compare. {Bật/tắt chúng trong demo và so sánh.}

The master’s warnings {Lời cảnh báo của sư phụ}

  • Y points down. Half of all “my shape is in the wrong place” bugs are forgetting this. {Y hướng xuống. Phân nửa lỗi “hình của tôi sai chỗ” là quên điều này.}
  • viewBox is unitless. Never write viewBox="0 0 200px 200px" — numbers only. {viewBox không có đơn vị. Đừng viết 200px — chỉ con số.}
  • No fill on a line. Lines and open polylines need stroke, not fill. {Không fill cho line. Line và polyline hở cần stroke, không phải fill.}

Practice, or it didn’t happen {Luyện tập, không thì coi như chưa học}

  1. Draw your initials {Vẽ chữ cái đầu tên con} using only <line> and <polyline> in a viewBox="0 0 100 100". {chỉ bằng <line><polyline>.}
  2. Build a target {Dựng tấm bia}: three concentric <circle>s. Then change only the viewBox width/height and watch it zoom without touching any circle. {ba <circle> đồng tâm. Rồi đổi chỉ width/height của viewBox và xem nó zoom mà không động vào circle nào.}
  3. Break it on purpose {Phá nó có chủ đích}: set preserveAspectRatio="none" on a square drawing inside a wide box and watch it distort. {đặt none cho bản vẽ vuông trong khung rộng và xem nó méo.}

What’s next {Phần tiếp theo}

You can now place a camera over an infinite canvas and draw with six shapes. {Giờ con đã biết đặt máy ảnh trên canvas vô hạn và vẽ bằng sáu hình.} But real icons, logos, and charts are made of curves — and curves mean one element: <path>. {Nhưng icon, logo, biểu đồ thật được làm từ đường cong — và đường cong nghĩa là một element: <path>.} In Part 2 we decode the path language — M, L, the Bézier curves C/Q, and the dreaded elliptical arc A — with a builder that lets you drag control points and watch the d attribute write itself. {Ở Phần 2 ta giải mã ngôn ngữ path — M, L, các đường Bézier C/Q, và cung elip A đáng sợ — với một trình dựng cho con kéo control point và xem thuộc tính d tự viết.}