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.
A 12 KB hero background PNG, or a 250-byte SVG that’s razor-sharp on every screen and re-themes with one variable? {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?} For dot grids, hatching, subtle textures, and organic blobs, SVG wins by a mile. {Cho lưới chấm, gạch chéo, texture tinh tế, và blob hữu cơ, SVG thắng cách biệt.} This part is the fun one — generating graphics from a handful of numbers. {Phần này là phần vui — sinh đồ hoạ từ một nắm con số.}
Switch patterns, tune the tile, then re-roll the blob generator. {Đổi pattern, chỉnh ô, rồi re-roll máy sinh blob.}
Open the full demo {Mở demo đầy đủ}: /tools/svg-generative-demo/.
Repeating patterns recap → power-up {Ôn pattern lặp → nâng cấp}
In Part 3 you met <pattern>. {Ở Phần 3 con đã gặp <pattern>.} Here’s the production reality: a single tiny tile fills an area of any size, infinitely sharp, for almost no bytes. {Đâ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>
Swap the tile content for the texture you want: {Đổi nội dung ô lấy texture con muốn:}
- Dots: a
<circle>. {một<circle>.} - Grid:
<path d="M22 0H0V22">. {<path d="M22 0H0V22">.} - Diagonal lines:
<path d="M0 22L22 0">. {<path d="M0 22L22 0">.} - Cross-hatch: both diagonals in one tile. {cả hai đường chéo trong một ô.}
patternUnits="userSpaceOnUse" keeps the tile a fixed size; patternTransform="rotate(30)" rotates the whole texture without redrawing the tile. {patternUnits="userSpaceOnUse" giữ ô kích thước cố định; patternTransform="rotate(30)" xoay cả texture mà không vẽ lại ô.}
Organic blobs — randomness with control {Blob hữu cơ — ngẫu nhiên có kiểm soát}
Those soft “blob” shapes behind modern hero sections look hand-drawn but are pure math. {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.} The recipe: {Công thức:}
- Place
npoints evenly around a circle (angles0 → 2π). {Đặtnđiểm đều quanh một vòng tròn (góc0 → 2π).} - Randomize each point’s radius a little — that’s the irregularity. {Random bán kính mỗi điểm một chút — đó là độ bất quy tắc.}
- Join them with smooth cubic Béziers through a closed path so there are no corners. {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';
}
Fewer points + low irregularity = a calm pebble; more points + high irregularity = a splat. {Í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.} The Catmull-Rom→Bézier conversion (the /6 control points) is the trick that keeps the curve smooth and closed. {Phép chuyển Catmull-Rom→Bézier (control point /6) là mánh giữ đường cong mượt và kín.}
Ship it as a data-URI {Ship nó dưới dạng data-URI}
A generated SVG can live entirely inside a CSS background-image — no extra network request, no file: {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");
}
Rules for a clean data-URI: {Luật cho data-URI sạch:}
- Use single quotes inside the SVG so you don’t escape the CSS double quotes. {Dùng dấu nháy đơn trong SVG để khỏi escape nháy kép của CSS.}
- URL-encode
#as%23and</>if needed; prefer URL-encoding over base64 (smaller, still readable). {URL-encode#thành%23và</>nếu cần; ưu tiên URL-encode hơn base64.} - Keep it tiny — data-URIs aren’t cached separately, so don’t inline a huge illustration this way. {Giữ nó nhỏ — data-URI không cache riêng, nên đừng inline minh hoạ khổng lồ kiểu này.}
Tools like Hero Patterns and SVG Backgrounds are just this technique with a UI. {Các công cụ như Hero Patterns và SVG Backgrounds chỉ là kỹ thuật này kèm UI.}
The master’s warnings {Lời cảnh báo của sư phụ}
- Close blob paths with
Zand feed wrap-around control points, or you get a gap or a kink at the seam. {Đóng path blob bằngZvà cấp control point vòng quanh, nếu không sẽ có khe hở hoặc gãy ở mối nối.} userSpaceOnUsevsobjectBoundingBoxchanges whether the tile size is absolute or relative — a classic “my pattern is one giant blur” bug. {userSpaceOnUsevsobjectBoundingBoxđổi việc kích thước ô là tuyệt đối hay tương đối.}- Don’t base64 small SVGs for CSS — URL-encoding is smaller and human-readable. {Đừng base64 SVG nhỏ cho CSS — URL-encode nhỏ hơn và đọc được.}
Practice, or it didn’t happen {Luyện tập, không thì coi như chưa học}
- Dot-grid hero {Hero lưới chấm}: build a dot
<pattern>, fill a full-bleed rect, then export it as a CSSbackground-imagedata-URI. {dựng<pattern>chấm, fill rect tràn viền, rồi export thành data-URIbackground-image.} - Blob avatar frame {Khung avatar blob}: generate a blob and use it as a
clipPath(Part 8!) for a photo. {sinh một blob và dùng làmclipPathcho một ảnh.} - Animated texture {Texture động}: animate
patternTransformto slowly drift a diagonal-line background. {animatepatternTransformđể nền đường chéo trôi chậm.}
What’s next {Phần tiếp theo}
You can now generate textures and shapes programmatically. {Giờ con sinh texture và hình theo lập trình được.} Next we put SVG inside the framework most of you ship in. {Tiếp theo ta đặt SVG vào framework đa số các con dùng.} In Part 14 we cover SVG in React/JSX: inlining vs importing, the JSX attribute gotchas (className, strokeWidth), turning icons into typed components with props, currentColor theming, and rendering data-driven SVG the React way. {Ở 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.}