jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 13 — Generative Patterns & Backgrounds

Make tiny, resolution-independent textures from a few numbers: repeating <pattern> tiles for hero backgrounds, an organic blob generator with smooth curves, and shipping SVG as a compact data-URI. With a live generator.

Một ảnh nền hero PNG 12 KB, hay một SVG 250 byte sắc lẹm trên mọi màn hình và đổi theme bằng một biến? Cho lưới chấm, gạch chéo, texture tinh tế, và blob hữu cơ, SVG thắng cách biệt. Phần này là phần vui — sinh đồ hoạ từ một nắm con số.

Đổi pattern, chỉnh ô, rồi re-roll máy sinh blob.

Mở demo đầy đủ:

Ôn pattern lặp → nâng cấp

Ở Phần 3 con đã gặp <pattern>. Đây là thực tế production: một ô tí hon lấp đầy vùng bất kỳ kích thước, sắc vô hạn, gần như không tốn byte.

<svg>
  <defs>
    <pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
      <circle cx="11" cy="11" r="3" fill="#c8ff00" />
    </pattern>
  </defs>
  <rect width="100%" height="100%" fill="url(#dots)" />
</svg>

Đổi nội dung ô lấy texture con muốn:

  • một <circle>.
  • <path d="M22 0H0V22">.
  • <path d="M0 22L22 0">.
  • cả hai đường chéo trong một ô.

patternUnits="userSpaceOnUse" giữ ô kích thước cố định; patternTransform="rotate(30)" xoay cả texture mà không vẽ lại ô.

Blob hữu cơ — ngẫu nhiên có kiểm soát

Các hình “blob” mềm sau các section hero hiện đại trông như vẽ tay nhưng thuần là toán. Công thức:

  1. Đặt n điểm đều quanh một vòng tròn (góc 0 → 2π).
  2. Random bán kính mỗi điểm một chút — đó là độ bất quy tắc.
  3. Nối chúng bằng Bézier bậc ba mượt qua một path kín để không có góc.
function makeBlob(n, irregularity, base = 70, cx = 100, cy = 100) {
  const pts = Array.from({ length: n }, (_, i) => {
    const a = (i / n) * Math.PI * 2;
    const r = base + (Math.random() * 2 - 1) * irregularity;
    return [cx + Math.cos(a) * r, cy + Math.sin(a) * r];
  });
  // Catmull-Rom → cubic control points for a smooth CLOSED path
  let d = `M ${pts[0][0]} ${pts[0][1]}`;
  for (let i = 0; i < n; i++) {
    const p0 = pts[(i - 1 + n) % n], p1 = pts[i],
          p2 = pts[(i + 1) % n], p3 = pts[(i + 2) % n];
    const c1 = [p1[0] + (p2[0] - p0[0]) / 6, p1[1] + (p2[1] - p0[1]) / 6];
    const c2 = [p2[0] - (p3[0] - p1[0]) / 6, p2[1] - (p3[1] - p1[1]) / 6];
    d += ` C ${c1[0]} ${c1[1]}, ${c2[0]} ${c2[1]}, ${p2[0]} ${p2[1]}`;
  }
  return d + ' Z';
}

Ít điểm + bất quy tắc thấp = viên sỏi êm; nhiều điểm + bất quy tắc cao = vệt bắn. Phép chuyển Catmull-Rom→Bézier (control point /6) là mánh giữ đường cong mượt kín.

Ship nó dưới dạng data-URI

Một SVG sinh ra có thể sống trọn trong background-image của CSS — không request mạng thêm, không file:

.hero {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' \
    width='22' height='22'%3E%3Ccircle cx='11' cy='11' r='3' fill='%23c8ff00'/%3E%3C/svg%3E");
}

Luật cho data-URI sạch:

  • Dùng dấu nháy đơn trong SVG để khỏi escape nháy kép của CSS.
  • URL-encode # thành %23</> nếu cần; ưu tiên URL-encode hơn base64.
  • Giữ nó nhỏ — data-URI không cache riêng, nên đừng inline minh hoạ khổng lồ kiểu này.

Các công cụ như Hero PatternsSVG Backgrounds chỉ là kỹ thuật này kèm UI.

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

  • Đóng path blob bằng Z và cấp control point vòng quanh, nếu không sẽ có khe hở hoặc gãy ở mối nối.
  • userSpaceOnUse vs objectBoundingBox đổi việc kích thước ô là tuyệt đối hay tương đối.
  • Đừng base64 SVG nhỏ cho CSS — URL-encode nhỏ hơn và đọc được.

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

  1. Hero lưới chấm: dựng <pattern> chấm, fill rect tràn viền, rồi export thành data-URI background-image.
  2. Khung avatar blob: sinh một blob và dùng làm clipPath cho một ảnh.
  3. Texture động: animate patternTransform để nền đường chéo trôi chậm.

Phần tiếp theo

Giờ con sinh texture và hình theo lập trình được. Tiếp theo ta đặt SVG vào framework đa số các con dùng. Ở Phần 14 ta nói về SVG trong React/JSX: inline vs import, các bẫy thuộc tính JSX (className, strokeWidth), biến icon thành component có kiểu với props, theme currentColor, và render SVG theo dữ liệu kiểu React.