jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

SVG from Zero to Senior · Part 10 — Production: Optimization, Sprites & Accessibility

Ship SVG like a senior: optimize with SVGO, choose the right delivery (inline vs img vs sprite), build a symbol + use icon system themed with currentColor, make graphics accessible with title/desc/role/aria, and respect perf budgets.

Giờ con vẽ, sơn, animate, filter, mask, và script SVG được. Bài cuối là cái tách người chơi tài tử khỏi senior: ship nó cho tốt. Được tối ưu, đổi theme được, truy cập được, và nhanh. Làm chủ cái này là con hoàn thành hành trình từ gà mờ lên senior.

Xem mức tiết kiệm byte, đổi theme cho sprite icon bằng một click, và đọc checklist truy cập.

Mở demo đầy đủ:

Tối ưu: SVGO

Công cụ thiết kế export SVG phình to — prolog XML, metadata trình biên tập, comment, id="Layer_1", thuộc tính dư, và toạ độ tám chữ số thập phân. SVGO loại bỏ tất cả không mất chất, thường cắt 40–70% byte.

npx svgo icon.svg -o icon.min.svg
npx svgo --folder ./icons --recursive   # whole directory

Nhưng tối ưu có chủ đích, đừng mù quáng:

  • Giữ viewBox — đừng để SVGO bỏ, không thì scale hỏng.
  • Giữ các id con tham chiếu từ CSS/JS/<use>/gradient.
  • Giữ <title>/<desc> cho khả năng truy cập.

SVGO dựa trên plugin, nên con cấu hình chính xác transform nào chạy qua svgo.config.js.

Chọn cách giao đúng

Không có cách “tốt nhất” duy nhất để đặt SVG lên trang — tuỳ việc.

MethodWhenTrade-off
Inline <svg>…</svg>icon con style/animate/scriptkiểm soát đủ, nhưng phình HTML & không cache
<img src="x.svg">ảnh tĩnh, logocache, đơn giản; không CSS/JS vào trong
CSS background-imagetrang trí, lặp lạicache; không trong DOM, không truy cập
Sprite (<use>)hệ iconđịnh nghĩa một lần, dùng khắp nơi, đổi theme được

Quy tắc senior: inline cho icon tương tác/đổi theme, <img> cho art tĩnh cache được, sprite cho bộ icon dùng chung.

Hệ icon: <symbol> + <use> + currentColor

Đây là cách các bộ icon chuyên nghiệp hoạt động. Định nghĩa mỗi icon một lần thành <symbol> (với viewBox riêng), rồi đóng dấu các instance bằng <use>:

<!-- once per page (often injected at the top of <body>) -->
<svg style="display:none" aria-hidden="true">
  <symbol id="i-star" viewBox="0 0 24 24">
    <path fill="currentColor" d="M12 2l2.9 6.3 6.9.7…z" />
  </symbol>
</svg>

<!-- anywhere, any number of times -->
<svg class="icon" aria-hidden="true"><use href="#i-star" /></svg>

Cú đánh quyết định là fill="currentColor". currentColor phân giải thành color CSS của element, nên icon tự kế thừa màu chữ và đổi theme bằng một luật:

.icon { width: 1.25em; height: 1.25em; }
.btn-danger .icon { color: #ef4444; }   /* every icon inside goes red */

Click các ô màu trong demo — một thay đổi color đổi theme cả hàng. Vì thế con gần như không bao giờ nhúng màu cứng vào icon tái dùng.

<use href> hiện đại dùng href thường; xlink:href cũ chỉ cần cho trình duyệt rất cũ.

Khả năng truy cập — phần ai cũng bỏ qua

SVG nằm trong DOM, nên nó có nghĩa vụ về khả năng truy cập. Cây quyết định:

  • Trang trí (cạnh nhãn chữ) → aria-hidden="true", không thông báo.
  • Đồ hoạ độc lập có nghĩarole="img" + một <title> (tên ngắn) và <desc> tuỳ chọn (chi tiết), nối bằng aria-labelledby:
<svg role="img" aria-labelledby="t d" viewBox="0 0 24 24">
  <title id="t">Favorite</title>
  <desc id="d">A filled star indicating this item is saved</desc>
  <path d="…" />
</svg>
  • Tương tác → bọc trong <button> thật với tên truy cập được và focus style nhìn thấy.
  • Trực quan dữ liệu → cho một bản thay thế dạng chữ (tóm tắt hoặc bảng dữ liệu ẩn); các hình của biểu đồ tự nó vô nghĩa với screen reader.

Ngân sách hiệu năng

  • Inline SVG phình HTML và không cache riêng — cho bộ icon lớn dùng chung, ưu tiên sprite hoặc <img>.
  • Filter và blur lớn tốn GPU — tính toán chúng, đừng animate stdDeviation mỗi frame.
  • Hàng nghìn node DOM nặng — quá vài nghìn hình, chuyển sang <canvas>/WebGL.
  • Animate transform/opacity, các property thân thiện compositor.

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

  • Đừng để SVGO bỏ viewBox hay id được tham chiếu. Kiểm tra output, đừng tin mù quáng.
  • currentColor cho icon tái dùng. Fill cứng không đổi theme theo ngữ cảnh được.
  • Đồ hoạ không nhãn vô hình với công nghệ hỗ trợ — hoặc tệ hơn, bị đọc vô nghĩa. Quyết định trang trí vs có nghĩa cho mọi SVG.

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

  1. Tối ưu một bản export thật: chạy npx svgo lên một icon từ công cụ thiết kế và so byte.
  2. Dựng sprite 4 icon: <symbol>``<symbol> với currentColor, rồi đổi theme qua color của cha.
  3. Kiểm tra a11y: lấy một SVG trang trí và một SVG có nghĩa và thêm xử lý aria đúng cho mỗi cái.

Kết thúc hành trình

Nhìn lại nơi con bắt đầu: một tờ giấy kẻ ô phẳng và một viewBox khó hiểu. Giờ con điều khiển cả ngôn ngữ — hình, path, sơn, chữ, transform, animation, filter, mask, scripting, và nghề ship production. Đó thực sự là SVG tầm senior. Đi dựng thứ gì đó sắc nét ở mọi độ phân giải. Sư phụ cúi chào.