SVG from Zero to Senior · Part 12 — Progress Rings & Gauges
Build the loaders, percentage rings, and speedometers in every dashboard with one formula: stroke-dashoffset = circumference × (1 − percent). Plus the -90° start rotation, round caps, gradient rings, and a 270° gauge. With a live builder.
Có những component trông cao siêu nhưng dựa trên một công thức thanh lịch duy nhất. Vòng tiến trình tròn — cái loader phần trăm trong mọi dashboard, app thể dục, và trang thanh toán — chính là vậy. Một khi thấy được mánh con sẽ dựng chúng trong lúc ngủ.
Kéo phần trăm, độ rộng, và màu; rồi khám phá đồng hồ 270° bên dưới.
Mở demo đầy đủ:
Một công thức
Nhớ stroke-dasharray và stroke-dashoffset ở Phần 3 và 6 chứ? Đây là ứng dụng đỉnh của chúng.
Lấy một vòng tròn có stroke. Chiều dài đường viền là chu vi:
C = 2 × π × r
Giờ làm pattern nét đứt thành một nét dài đúng bằng cả vòng (stroke-dasharray: C). Nét đó phủ cả vòng. Rồi đẩy nó đi bằng stroke-dashoffset:
dashoffset = C × (1 − percent)
- cả nét bị đẩy ra → vòng rỗng.
- nét nằm trọn trên vòng → đầy.
<svg viewBox="0 0 200 200">
<g transform="rotate(-90 100 100)"> <!-- start at 12 o'clock -->
<circle cx="100" cy="100" r="80" fill="none" stroke="#232323" stroke-width="12"/>
<circle cx="100" cy="100" r="80" fill="none" stroke="#c8ff00" stroke-width="12"
stroke-linecap="round"
stroke-dasharray="502.6" /* C = 2π·80 */
stroke-dashoffset="160.8" /> /* C × (1 − 0.68) */
</g>
</svg>
const C = 2 * Math.PI * r;
fill.style.strokeDasharray = C;
fill.style.strokeDashoffset = C * (1 - percent); // percent in 0..1
Đó là toàn bộ component. Phần còn lại là đánh bóng.
Hai chi tiết làm nó trông đúng
- Bắt đầu ở 12 giờ. Stroke của vòng tròn bắt đầu ở 3 giờ. Bọc trong
rotate(-90 cx cy)để tiến trình bắt đầu từ trên. - Đầu bo tròn.
stroke-linecap: roundcho đầu nét mềm, hiện đại.
Animate nó mượt
Vì stroke-dashoffset là một số animate được, một transition CSS một dòng làm vòng trượt tới giá trị mới:
.ring-fill {
transition: stroke-dashoffset 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
Cập nhật offset trong JS và nó tự animate — không cần keyframe. Cho spinner xác định→không xác định, xoay cả SVG bằng @keyframes spin trong khi giữ khoảng hở dash cố định.
Vòng gradient & lựa chọn conic
Muốn màu fill đổi dọc cung? Một linearGradient trên stroke cho vẻ hai tông; cho cầu vồng quanh vòng thật con xoay gradient hoặc chuyển sang mask conic-gradient của CSS. Cho tiến trình thuần, cách stroke SVG thắng về độ sắc và kiểm soát animation.
Đồng hồ 270° (tốc kế)
Đồng hồ cùng ý tưởng, nhưng track chỉ phủ một phần vòng tròn. Dùng dasharray [độ-dài-cung, khoảng-hở-lớn] để chỉ cung hiện, xoay nhóm để khoảng hở nằm dưới, và fill là độ-dài-cung × giá-trị:
const C = 2 * Math.PI * r;
const arc = C * 0.75; // 270° = three-quarters
track.style.strokeDasharray = `${arc} ${C}`; // show 270°, hide the rest
fill.style.strokeDasharray = `${arc * value} ${C}`;
// rotate the group by 135° so the open quarter is centred at the bottom
Cùng toán chu vi, thêm một phép xoay — và con có tốc kế, đồng hồ pin, hay mặt số điểm.
Lời cảnh báo của sư phụ
- Khớp bán kính trong công thức và markup. Sai bán kính là lỗi số 1 “vòng không bao giờ đầy”.
- Tính stroke width khi định cỡ. Stroke cưỡi lên bán kính, nên stroke 12px trên
r=80sơn từ 74→86; thurnếu nó cắt viewBox. - Xoay, đừng vẽ lại, để đổi góc bắt đầu. Vẽ arc path riêng là thừa khi
rotate()làm được.
Luyện tập, không thì coi như chưa học
- Vòng 68%: dựng vòng, tính C trong JS, và animate từ 0 → 68% khi tải.
- Vòng đếm ngược: lái
stroke-dashoffsettừ một timer để vòng cạn dần trong 10 giây. - Đồng hồ pin: một gauge 180° đổi fill sang đỏ khi dưới 20%.
Phần tiếp theo
Giờ con dựng được đồng hồ tròn chính xác. Tiếp theo ta nghịch ngợm và sinh tạo. Ở Phần 13 ta làm pattern sinh tạo và nền SVG — ô <pattern> lặp, máy sinh blob hữu cơ, và các nền hero nhẹ ship dưới dạng data-URI tí hon thay cho ảnh nặng.