Tự tạo file JavaScript hiển thị icon SVG siêu nhẹ cho web/app: Dễ như trở bàn tay

Bạn muốn bỏ các thư viện icon cồng kềnh và tự chủ hoàn toàn về biểu tượng trong dự án web/app? Bài viết này là một hướng dẫn thực chiến kết hợp giải thích và hướng dẫn từng bước.

Tự tạo file JavaScript hiển thị icon SVG siêu nhẹ cho web/app: Dễ như trở bàn tay

Bạn đang phụ thuộc vào các thư viện icon nặng nề như Font Awesome hay Feather Icons? Muốn kiểm soát hoàn toàn bộ icon trong dự án mà vẫn giữ được hiệu năng tối ưu? Bài viết này sẽ hướng dẫn bạn tạo một hệ thống icon SVG tự chủ chỉ với một file JavaScript duy nhất – siêu nhẹ, dễ sử dụng và hoàn toàn tùy biến.

Kết quả: Một bộ icon SVG chỉ vài KB, tải nhanh như chớp, dễ theme theo ý muốn và thân thiện với công cụ đọc màn hình.

Tại sao nên tự tạo hệ thống icon thay vì dùng thư viện có sẵn?

Các thư viện icon phổ biến thường có những hạn chế:

  • Dung lượng lớn: Font Awesome 6 có thể nặng đến 1MB+ chỉ để bạn dùng 10-15 icon
  • Thiếu tính linh hoạt: Khó tùy biến màu sắc, kích thước theo design system riêng
  • Phụ thuộc ngoại vi: CDN có thể chậm hoặc bị chặn trong một số môi trường
  • Không tối ưu: Tải cả bộ icon trong khi chỉ sử dụng một phần nhỏ

Hệ thống icon tự tạo giải quyết toàn bộ vấn đề trên:

  • Chỉ 2-5KB cho 20-30 icon thường dùng
  • Tùy biến hoàn toàn màu sắc bằng CSS
  • Không phụ thuộc bên thứ ba
  • Tải tức thì cùng với trang web

Kiến trúc hệ thống Init Icons

Hệ thống bao gồm 3 thành phần chính:

  1. InitIcons Object: Lưu trữ tất cả SVG dưới dạng chuỗi
  2. InitIconsInit Function: Quét DOM và chèn icon vào vị trí phù hợp
  3. Data Attribute: Sử dụng data-init-icon để đánh dấu vị trí cần hiển thị icon

Code hoàn chỉnh: init-icons.js

Dán đoạn code sau vào file init-icons.js và import vào dự án:

/* init-icons.js - Hệ thống icon SVG tự chủ */
const InitIcons = {
    eye: '<svg width="20" height="20" viewBox="0 0 20 20" aria-hidden="true"><circle fill="none" stroke="currentColor" cx="10" cy="10" r="3.45"></circle><path fill="none" stroke="currentColor" d="m19.5,10c-2.4,3.66-5.26,7-9.5,7h0,0,0c-4.24,0-7.1-3.34-9.49-7C2.89,6.34,5.75,3,9.99,3h0,0,0c4.25,0,7.11,3.34,9.5,7Z"></path></svg>',
    eyeoff: '<svg width="20" height="20" viewBox="0 0 20 20" aria-hidden="true"><path fill="none" stroke="currentColor" d="m7.56,7.56c.62-.62,1.49-1.01,2.44-1.01,1.91,0,3.45,1.54,3.45,3.45,0,.95-.39,1.82-1.01,2.44"></path><path fill="none" stroke="currentColor" d="m19.5,10c-2.4,3.66-5.26,7-9.5,7h0,0,0c-4.24,0-7.1-3.34-9.49-7C2.89,6.34,5.75,3,9.99,3h0,0,0c4.25,0,7.11,3.34,9.5,7Z"></path><line fill="none" stroke="currentColor" x1="2.5" y1="2.5" x2="17.5" y2="17.5"></line></svg>',
    star: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><polygon fill="none" stroke="currentColor" stroke-width="1.01" points="10 2 12.63 7.27 18.5 8.12 14.25 12.22 15.25 18 10 15.27 4.75 18 5.75 12.22 1.5 8.12 7.37 7.27"></polygon></svg>',
    user: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><circle fill="none" stroke="currentColor" stroke-width="1.1" cx="9.9" cy="6.4" r="4.4"></circle><path fill="none" stroke="currentColor" stroke-width="1.1" d="M1.5,19 C2.3,14.5 5.8,11.2 10,11.2 C14.2,11.2 17.7,14.6 18.5,19.2"></path></svg>',
    check: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><polyline fill="none" stroke="currentColor" stroke-width="1.1" points="4,10 8,15 17,4"></polyline></svg>',
    clock: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><circle fill="none" stroke="currentColor" stroke-width="1.1" cx="10" cy="10" r="9"></circle><rect width="1" height="7" x="9" y="4"></rect><path fill="none" stroke="currentColor" stroke-width="1.1" d="M13.018,14.197 L9.445,10.625"></path></svg>',
    calendar: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><path d="M 2,3 2,17 18,17 18,3 2,3 Z M 17,16 3,16 3,8 17,8 17,16 Z M 17,7 3,7 3,4 17,4 17,7 Z"></path><rect width="1" height="3" x="6" y="2"></rect><rect width="1" height="3" x="13" y="2"></rect></svg>',
    camera: '<svg width="20" height="20" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true"><circle fill="none" stroke="currentColor" stroke-width="1.1" cx="10" cy="10.8" r="3.8"></circle><path fill="none" stroke="currentColor" d="M1,4.5 C0.7,4.5 0.5,4.7 0.5,5 L0.5,17 C0.5,17.3 0.7,17.5 1,17.5 L19,17.5 C19.3,17.5 19.5,17.3 19.5,17 L19.5,5 C19.5,4.7 19.3,4.5 19,4.5 L13.5,4.5 L13.5,2.9 C13.5,2.6 13.3,2.5 13,2.5 L7,2.5 C6.7,2.5 6.5,2.6 6.5,2.9 L6.5,4.5 L1,4.5 L1,4.5 Z"></path></svg>'
};

/* SVG cho badge demo */
const InitBadgeSVG = '<svg viewBox="0 0 24 24" width="18" height="18" fill="currentColor" class="init-badge-icon"><path d="M12 2l3.09 6.26L22 9.27l-5 4.87L18.18 22 12 18.56 5.82 22 7 14.14l-5-4.87 6.91-1.01L12 2z"/></svg>';

/* Hàm chính: quét và chèn icon */
function InitIconsInit(root = document) {
    root.querySelectorAll("[data-init-icon]:not(.init-icon-rendered)").forEach(element => {
        const iconName = element.getAttribute("data-init-icon");
        
        if (InitIcons[iconName]) {
            element.innerHTML = InitIcons[iconName];
            element.setAttribute("aria-hidden", "true");
            element.classList.add("init-icon-rendered");
        }
    });
}

/* Hàm mở rộng: tạo badge với icon */
function InitBadgesInit(root = document) {
    root.querySelectorAll(".init-badge-level:not(.init-badge-enhanced)").forEach(element => {
        element.classList.add("init-badge-enhanced");
        
        const number = element.textContent.trim();
        element.textContent = "";
        
        // Thêm icon
        const iconWrapper = document.createElement("span");
        iconWrapper.innerHTML = InitBadgeSVG;
        element.appendChild(iconWrapper.firstElementChild);
        
        // Thêm số
        const numberSpan = document.createElement("span");
        numberSpan.className = "init-badge-number";
        numberSpan.textContent = number;
        element.appendChild(numberSpan);
    });
}

/* Tự động khởi tạo khi DOM sẵn sàng */
document.addEventListener("DOMContentLoaded", () => {
    InitIconsInit();
    InitBadgesInit();
});

Cách sử dụng trong HTML

Sau khi import file JavaScript, việc hiển thị icon trở nên cực kỳ đơn giản:

<!-- Icon đơn giản -->
<span class="icon" data-init-icon="star"></span> Yêu thích

<!-- Icon trong button -->
<button class="btn-demo" type="button">
    <span class="icon" data-init-icon="eye"></span>
    Xem chi tiết
</button>

<!-- Badge với icon (tự động) -->
<span class="init-badge-level">12</span>
Demo:12

Styling và theming với CSS

Icon tự động kế thừa màu sắc từ thuộc tính color của phần tử cha nhờ currentColor:

/* CSS cơ bản cho icon */
.icon {
    display: inline-flex;
    width: 1em;
    height: 1em;
    line-height: 1;
    vertical-align: -2px;
}

.icon svg {
    width: 100%;
    height: 100%;
}

/* Theming - thay đổi màu dễ dàng */
.btn-primary {
    color: #3b82f6;
}

.btn-primary:hover {
    color: #1d4ed8;
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
    .icon {
        color: #e5e7eb;
    }
}

/* Kích thước khác nhau */
.icon-sm { font-size: 0.875rem; }
.icon-lg { font-size: 1.25rem; }
.icon-xl { font-size: 1.5rem; }

Tối ưu SVG để giảm dung lượng

Để có hiệu năng tốt nhất, hãy tối ưu SVG trước khi thêm vào InitIcons:

  • Tham khảo: Nén SVG để tối ưu hóa dung lượng mã SVG
  • Sử dụng currentColor: fill="currentColor" hoặc stroke="currentColor"
  • Loại bỏ thuộc tính thừa: id, class, style không cần thiết
  • Giữ viewBox chuẩn: Thường là “0 0 20 20” hoặc “0 0 24 24”
  • Minify SVG: Xóa khoảng trắng, xuống dòng không cần thiết

Sử dụng với SPA và DOM động

Khi làm việc với React, Vue hoặc các framework SPA, bạn có thể khởi tạo icon cho phần DOM mới:

// Chỉ khởi tạo icon trong container cụ thể
const newPanel = document.querySelector('#dynamic-content');
InitIconsInit(newPanel);

// Hoặc sau khi component mount
useEffect(() => {
    InitIconsInit(containerRef.current);
}, []);

// Trong Vue
mounted() {
    InitIconsInit(this.$refs.container);
}

Mở rộng hệ thống

Hệ thống có thể dễ dàng mở rộng:

  • Thêm icon mới: Chỉ cần bổ sung vào object InitIcons
  • Tạo theme riêng: Nhóm icon theo chức năng (social, ui, business)
  • Lazy loading: Tách icon ít dùng ra file riêng
  • Build tool: Tự động tạo InitIcons từ thư mục SVG

So sánh hiệu năng

Phương pháp Dung lượng Tốc độ tải Tùy biến
Font Awesome 6 900KB+ Chậm Hạn chế
Feather Icons 45KB+ Trung bình Khá tốt
Init Icons 3-8KB Tức thì Hoàn toàn

Checklist trước khi deploy

  • Tất cả icon sử dụng currentColor để dễ theming
  • Đã test hiển thị trên nhiều kích thước màn hình
  • Icon trang trí có aria-hidden="true"
  • CSS đã tối ưu cho cả light và dark mode
  • Test với screen reader để đảm bảo accessibility
  • Đo đạc bundle size trước và sau khi áp dụng

Kết luận

Hệ thống Init Icons mang lại sự tự chủ hoàn toàn về icon trong dự án web. Với chỉ vài KB dung lượng, bạn có được một bộ icon tải nhanh, dễ tùy biến và không phụ thuộc vào bên thứ ba. Đây là giải pháp lý tưởng cho những ai muốn tối ưu hiệu năng mà vẫn giữ được tính linh hoạt trong thiết kế.

Bước tiếp theo: thử nghiệm với dự án nhỏ, đo lường hiệu quả, sau đó mở rộng dần cho toàn bộ ứng dụng. Bạn sẽ ngạc nhiên về sự khác biệt mà một hệ thống icon tự tạo có thể mang lại!

Bình luận


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...