jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

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.

3 MIN READ

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. Hết phần này con sẽ không bao giờ nhầm nữa.

Kéo vị trí để di cả hai cut-out, rồi kéo slider feather — để ý chỉ mask mềm đi.

Mở demo đầy đủ:

Khác biệt một câu

clipPath dù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). mask dù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).

Khuôn cắt bánh vs sơn xịt qua khuôn giấy.

clipPath — khuôn cắt bánh

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)" />
  • Chỉ hình học của shape clip quan trọng — fill/stroke của chúng bị bỏ qua.
  • 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.
  • Nó cũng clip hit-test: vùng bị cắt không nhận pointer event.

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 — khuôn giấy với các sắc xám

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:

  • trắng → hiện hẳn,
  • đen → ẩn hẳn,
  • 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)" />

Đó là vignette — ảnh nhoà mượt về không ở mép, điều clipPath không làm được. Kéo slider feather trong demo để mở rộng vành đen và xem mép mềm đi.

Mặc định mask là mask luminance. 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.

Chọn cái nào?

NeedUse
Cắt ảnh thành tròn/hình, mép sắcclipPath
Nhoà, vignette, lộ mềm, đèn rọimask
Cắt ảnh theo hình chữcái nào cũng được
Chặn pointer ngoài vùngclipPath
Animate quét gradient / tan biếnmask

CSS clip-path — anh em họ

CSS có clip-path riêng nhận hình kiểu SVG 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 */

Chúng chạy trên mọi element HTML, không chỉ SVG, và animate đẹp. Quyết định senior: cho hình UI HTML dùng CSS clip-path; cho clip trong cảnh SVG dùng <clipPath> SVG.

Lời cảnh báo của sư phụ

  • 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 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 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).

Luyện tập, không thì coi như chưa học

  1. Avatar tròn: clip ảnh vuông thành tròn bằng clipPath.
  2. Vignette mép: mask cùng ảnh với gradient toả trắng→đen và so sánh.
  3. Khoét chữ: đặt <text> trắng to trong một <mask> trên rectangle gradient, để gradient lộ qua các chữ.

Phần tiếp theo

Giờ con vẽ, sơn, animate, filter, và lộ được — đủ bộ công cụ tĩnh và thị giác. Đến lúc làm SVG biết suy nghĩ. Ở 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.