SVG from Zero to Senior · Part 8 — Clipping & Masking
The two ways to hide parts of a drawing: clipPath (a hard, binary cookie-cutter) and mask (soft, luminance-based transparency you can feather). When to use each, alpha vs luminance masks, and CSS clip-path — with a side-by-side lab.
Clipping and masking both answer the same question — “show only part of this drawing” — but they answer it very differently, and mixing them up is one of the most common SVG mistakes. {Clipping và masking đều trả lời cùng một câu hỏi — “chỉ hiện một phần bản vẽ này” — nhưng cách trả lời rất khác, và nhầm lẫn chúng là một trong những lỗi SVG phổ biến nhất.} By the end of this part you’ll never confuse them again. {Hết phần này con sẽ không bao giờ nhầm nữa.}
Drag the position to move both cut-outs, then drag the feather slider — notice only the mask softens. {Kéo vị trí để di cả hai cut-out, rồi kéo slider feather — để ý chỉ mask mềm đi.}
Open the full demo {Mở demo đầy đủ}: /tools/svg-clip-mask-demo/.
The one-sentence difference {Khác biệt một câu}
clipPathuses geometry: a pixel is either fully inside the shape or fully outside (binary, crisp).maskuses brightness: each pixel’s opacity comes from the mask’s luminance, so edges can fade (continuous, soft). {clipPathdùng hình học: một pixel hoặc hoàn toàn trong hình hoặc hoàn toàn ngoài (nhị phân, sắc).maskdùng độ sáng: độ mờ mỗi pixel đến từ luminance của mask, nên mép có thể nhoà (liên tục, mềm).}
Cookie-cutter vs spray-paint-through-a-stencil. {Khuôn cắt bánh vs sơn xịt qua khuôn giấy.}
clipPath — the cookie-cutter {clipPath — khuôn cắt bánh}
A <clipPath> holds shapes; anything outside their combined outline is cut away with a hard edge. {Một <clipPath> chứa các hình; mọi thứ ngoài đường viền gộp của chúng bị cắt với mép cứng.}
<defs>
<clipPath id="clip">
<circle cx="100" cy="80" r="55" />
</clipPath>
</defs>
<image href="photo.jpg" width="200" height="160" clip-path="url(#clip)" />
- Only the geometry of the clip shapes matters — their
fill/strokeare ignored. {Chỉ hình học của shape clip quan trọng —fill/strokecủa chúng bị bỏ qua.} - Edges are always crisp (with normal anti-aliasing). No partial transparency. {Mép luôn sắc (với khử răng cưa thường). Không có trong suốt một phần.}
- It clips hit-testing too: clipped-away areas don’t receive pointer events. {Nó cũng clip hit-test: vùng bị cắt không nhận pointer event.}
clipPathUnits defaults to userSpaceOnUse (real coordinates); set it to objectBoundingBox to define the clip in 0→1 fractions of the element — handy for reusable clips. {clipPathUnits mặc định là userSpaceOnUse (toạ độ thật); đặt objectBoundingBox để định nghĩa clip theo phân số 0→1 của element — tiện cho clip tái dùng.}
mask — the stencil with shades of gray {mask — khuôn giấy với các sắc xám}
A <mask> is itself a little drawing. Its luminance becomes the alpha of whatever it’s applied to: {Một <mask> tự nó là một bản vẽ nhỏ. Luminance của nó trở thành alpha của thứ nó áp lên:}
- white → fully visible, {trắng → hiện hẳn,}
- black → fully hidden, {đen → ẩn hẳn,}
- gray / gradient → partial opacity (the soft part). {xám / gradient → mờ một phần (phần mềm).}
<defs>
<radialGradient id="g">
<stop offset="0%" stop-color="white" />
<stop offset="100%" stop-color="black" />
</radialGradient>
<mask id="fade">
<circle cx="100" cy="80" r="55" fill="url(#g)" />
</mask>
</defs>
<image href="photo.jpg" mask="url(#fade)" />
That’s a vignette — the image fades smoothly to nothing at the edge, impossible with clipPath. {Đó là vignette — ảnh nhoà mượt về không ở mép, điều clipPath không làm được.} Drag the feather slider in the demo to widen the black ring and watch the edge soften. {Kéo slider feather trong demo để mở rộng vành đen và xem mép mềm đi.}
By default masks are luminance masks. {Mặc định mask là mask luminance.} You can switch to an alpha mask (use the mask content’s transparency instead of brightness) with CSS mask-type: alpha or the style="mask-type:alpha" — useful when your mask art is colored but you only care about its shape’s opacity. {Con có thể chuyển sang mask alpha (dùng độ trong suốt của nội dung mask thay vì độ sáng) bằng CSS mask-type: alpha — hữu ích khi art mask có màu nhưng con chỉ quan tâm độ mờ của hình.}
Which one do I reach for? {Chọn cái nào?}
| Need | Use |
|---|---|
| Crop a photo to a circle/shape, crisp edge {Cắt ảnh thành tròn/hình, mép sắc} | clipPath |
| Fade, vignette, soft reveal, spotlight {Nhoà, vignette, lộ mềm, đèn rọi} | mask |
| Text-shaped cut-out of an image {Cắt ảnh theo hình chữ} | either (clip for crisp, mask for glow) {cái nào cũng được} |
| Block pointer events outside a region {Chặn pointer ngoài vùng} | clipPath |
| Animate a gradient wipe / dissolve {Animate quét gradient / tan biến} | mask |
CSS clip-path — the cousin {CSS clip-path — anh em họ}
CSS has its own clip-path that accepts SVG-style shapes and friendly functions: {CSS có clip-path riêng nhận hình kiểu SVG và các hàm thân thiện:}
.card { clip-path: inset(10% round 12px); }
.badge { clip-path: circle(40%); }
.arrow { clip-path: polygon(0 0, 100% 50%, 0 100%); }
.fancy { clip-path: url(#clip); } /* reference an SVG clipPath */
These work on any HTML element, not just SVG, and animate beautifully. {Chúng chạy trên mọi element HTML, không chỉ SVG, và animate đẹp.} Senior call: for HTML UI shapes use CSS clip-path; for clipping inside an SVG scene use the SVG <clipPath>. {Quyết định senior: cho hình UI HTML dùng CSS clip-path; cho clip trong cảnh SVG dùng <clipPath> SVG.}
The master’s warnings {Lời cảnh báo của sư phụ}
- clip = binary, mask = grayscale. If you wanted a soft edge and got a hard one, you used the wrong tool. {clip = nhị phân, mask = thang xám. Muốn mép mềm mà ra mép cứng nghĩa là dùng sai công cụ.}
- Mask luminance, not color. A red shape and a gray shape of the same brightness mask identically; pure black hides, pure white shows. {Mask theo luminance, không phải màu. Hình đỏ và hình xám cùng độ sáng mask như nhau; đen tuyền ẩn, trắng tinh hiện.}
- clipPath ignores fill/stroke; mask respects them. Forgetting this is why beginners’ masks come out all-black (no white fill on the mask shape). {clipPath bỏ qua fill/stroke; mask thì không. Quên điều này là lý do mask của người mới ra toàn đen (shape mask không tô trắng).}
Practice, or it didn’t happen {Luyện tập, không thì coi như chưa học}
- Circle avatar {Avatar tròn}: clip a square photo into a circle with
clipPath. {clip ảnh vuông thành tròn bằngclipPath.} - Edge vignette {Vignette mép}: mask the same photo with a radial white→black gradient and compare. {mask cùng ảnh với gradient toả trắng→đen và so sánh.}
- Text knockout {Khoét chữ}: put big white
<text>inside a<mask>over a gradient rectangle, so the gradient shows through the letters. {đặt<text>trắng to trong một<mask>trên rectangle gradient, để gradient lộ qua các chữ.}
What’s next {Phần tiếp theo}
You can now draw, paint, animate, filter, and reveal — the full static and visual toolkit. {Giờ con vẽ, sơn, animate, filter, và lộ được — đủ bộ công cụ tĩnh và thị giác.} Time to make SVG think. {Đến lúc làm SVG biết suy nghĩ.} In Part 9 we wire SVG to JavaScript: generating shapes from a data array, the crucial screen→user coordinate mapping for accurate hit-testing, pointer events, tooltips, and building a small interactive chart from scratch. {Ở Phần 9 ta nối SVG với JavaScript: sinh hình từ mảng dữ liệu, ánh xạ toạ độ màn-hình→user then chốt cho hit-test chính xác, pointer event, tooltip, và dựng một biểu đồ tương tác nhỏ từ đầu.}