3 điểm bởi GN⁺ 2025-04-13 | 2 bình luận | Chia sẻ qua WhatsApp
  • SVG không chỉ là một định dạng icon đơn giản; có thể kết hợp mask, path và animation CSS để tạo hiệu ứng dây dẫn chạy dọc theo một đường và phần highlight TOC
  • Cách triển khai cốt lõi là không hiển thị trực tiếp đường được tạo bằng line hoặc path, mà dùng nó như một vùng mask để giới hạn phạm vi hiển thị của khối animation
  • Với Animated Wires, áp dụng mask="url(#...)" cho rect rồi dùng @keyframes để di chuyển translateY, đồng thời mở rộng phong cách hiển thị bằng linearGradient và biến CSS
  • TOC kiểu Clerk của Fumadocs, vì tính tương thích SSR, sẽ render đường viền trên server, còn thumb biểu thị vị trí đang hoạt động thì render ở client bằng thông tin vị trí trong trình duyệt
  • Thuộc tính d của SVG <path> không phải là chuỗi được tạo tự động mà là một danh sách lệnh, vì vậy có thể tái tạo ở client một ảnh mask có cùng hình dạng với đường viền TOC đã được render trên server

Animated Wires tạo bằng SVG mask

  • Mã ví dụ dựa trên cú pháp JSX hoặc React, không phải HTML thông thường
  • Có thể tạo đường cơ bản bằng line hoặc path của SVG
    • Trong ví dụ, một line dọc được đặt trong viewBox="0 0 50 50"
  • Thay vì vẽ đường trực tiếp lên màn hình, dùng nó làm mask để giới hạn vùng hiển thị của hình khác
    • Áp dụng mask="url(#line)" cho rect, và đặt một line màu trắng bên trong mask
  • Chuyển động được tạo bằng cách áp dụng CSS animation cho rect
    • @keyframes to-down di chuyển từ translateY(-10px) đến translateY(50px)
  • Có thể mở rộng phong cách hiển thị bằng cách kết hợp đường nền, đường mask dày hơn, linearGradient và biến CSS --height
    • @keyframes to-down-2 di chuyển từ calc(var(--height) * -1) đến 100%
  • Phần lớn các hiệu ứng tương tự đều dùng cách cắt khối animation bằng mask
    • Một số thiết kế có thể tạo bằng Figma hoặc công cụ chỉnh sửa SVG khác
    • Trang landing của Unkey là một ví dụ cho cách làm này

TOC kiểu Clerk của Fumadocs

  • Fumadocs có triển khai mục lục (TOC) kiểu Clerk
  • Để tương thích với SSR, cần render đường viền TOC trên server mà không cần JavaScript phía client
    • Trên server không thể biết chính xác vị trí của các phần tử
    • Cách triển khai dùng vị trí absolute, render đường viền như nhiều component riêng rồi nối chúng lại
  • Một phần của đường viền tương ứng với mục đang hoạt động hoặc heading đang hiển thị trong viewport được biểu thị bằng thumb
    • Vì thumb cần có animation, chỉ đổi màu component đường viền là không đủ
    • Thumb, là đối tượng tương tác, được render ở client
  • Dựa trên thông tin vị trí lấy từ trình duyệt, phía client sẽ dựng một bản đồ mask
    • SVG được dùng để tạo bản đồ mask này
    • Thuộc tính d của SVG <path> là danh sách lệnh và có thể render các đường nối giữa các điểm
    • Tài liệu liên quan có thể xem tại SVG Paths trên MDN Web Docs
  • SVG được tạo theo cách này sẽ có cùng hình dạng với đường viền TOC gốc đã được render sẵn trên server
  • Tương tự Animated Wires, SVG được đưa vào CSS mask-image dưới dạng data URL, rồi dùng để mask một khối div có animation nhằm render thumb được highlight
    • div bên trong dùng các giá trị như width: 1, height: thumb.height, transform: translateY(${thumb.top}px), transition: "all 500ms", backgroundColor: "white"
  • Có thể xem phần triển khai React.js trong mã nguồn toc-clerk.tsx

2 bình luận

 
ndrgrd 2025-04-14

Trông thì đẹp thật, nhưng chỉ cần nhấn mạnh rõ ràng riêng mục hiện tại thôi thì sẽ dễ nhìn hơn.

 
GN⁺ 2025-04-13
Các ý kiến trên Hacker News
  • Dù là tài liệu từ 8 năm trước, bài thuyết trình nổi tiếng “SVG Can Do That?” của Sarah Drasner vẫn khiến nhiều người mở mang tầm mắt
    Kể từ đó CSS đã trưởng thành vượt bậc, còn bản thân SVG thì tôi không chắc có đến mức đó không, nhưng dù sao cũng rất khuyến nghị
    Slide: https://slides.com/sdrasner/svg-can-do-that
    Video: https://youtu.be/ADXX4fmWHbo?si=6YPZkopyEDc8PSte

    • Cuốn sách đó cũng rất hay, nhưng tôi không chắc các công cụ được khuyến nghị trong đó đến nay còn phù hợp không
  • Một việc thú vị có thể làm với file SVG là dùng entity trong DTD inline để định nghĩa các hằng số dùng chung ở nhiều vị trí trong file
    Có thể thấy một ví dụ tuyệt vời trong SVG trên trang “Squares in Squares” của David Ellsworth
    Trên các trình duyệt lớn thì không vấn đề gì, nhưng một số công cụ như Inkscape thậm chí không parse DTD và cũng không mở rộng entity
    [0] https://kingbird.myphotos.cc/packing/squares_in_squares.html

    • “Entity” được nói tới ở đây thực ra là tên của cơ chế SGML/XML dùng các tham chiếu entity như &ref để định nghĩa và tái sử dụng nội dung cú pháp tùy ý
      Trong SVG, cách làm là đặt hình, path, v.v. dưới defs, gán id, rồi dùng lại trong phần thân SVG; trang được liên kết có vẻ cũng dùng cách đó trong từng SVG
      Không phải là chia sẻ các hình vuông giữa nhiều hình, vì mỗi hình được đưa vào dưới dạng một DOM riêng
      Tôi tò mò vì sao các nhà thiết kế SVG ban đầu lại thấy cần tạm thời tái triển khai cơ chế entity
      Có thể liên quan đến việc có thể ghi đè thuộc tính render tại điểm sử dụng, và khi đó SVG đang nằm trong làn sóng chuyển đổi XHTML/XML của W3C, nên có lẽ tiền đề rằng trình duyệt sẽ bỏ qua định nghĩa entity hay prologue/DOCTYPE của tài liệu cũng chưa được thiết lập
    • Có thể tôi đã bỏ sót gì đó, nhưng tôi không tìm thấy !doctype hay !element nào trên trang đó để thể hiện DTD
      Nếu chỉ đang nói đến defsuse của SVG thì đó không phải là DTD
    • Cũng có thể trích xuất một phần khác của SVG hiện có để nhân bản và dùng ở nơi khác trên trang
      https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/E...
    • Trên trình duyệt có thể hoạt động, nhưng nhiều công cụ SVG bỏ qua DTD vì nguy cơ tấn công từ chối dịch vụ
      Ví dụ như Billion laughs attack
      https://en.wikipedia.org/wiki/Billion_laughs_attack
    • Trang đó mất trọn khoảng 5 giây để render trên iPhone SE đời 2022
  • A Deep Dive Into SVG Path Commands” của Nanda Syahrasyad thật sự rất hay để hiểu các đường dẫn SVG được cấu thành như thế nào
    Dù là bài viết gần 2 năm trước, nó đã giúp tôi mở mang về SVG có thể làm gì và chính xác làm bằng cách nào
    [0] https://www.nan.fyi/svg-paths

  • Tôi từng làm một dự án dùng SVG cho những thứ thú vị như thế này
    Dự án được làm bằng React, đưa các yếu tố hoạt họa vào nhiều minh họa tĩnh, và màu sắc được điều khiển từ CMS
    Frontend gọi API để nhận ảnh SVG với màu đúng, còn hoạt ảnh được xử lý bằng cách ẩn và hiện các phần tử SVG
    Có thể xem ví dụ ở đây: https://web.archive.org/web/20221020133516im_/https://uncrow...

  • Thật sự nhớ Macromedia Flash
    Không có công nghệ nào giống như Flash và định dạng SWF, chỉ cần có Flash Player là có thể thưởng thức vô số game indie và phim hoạt hình mà không cần tải riêng
    Rào cản gia nhập cũng rất thấp
    SVG cũng có tiềm năng làm tất cả những gì SWF từng làm, nhưng không có editor như Flash hay cách lập trình dựa trên cảnh/đối tượng như ActionScript
    Mỗi trình duyệt cũng có điểm kỳ quặc riêng, nên chỉ các SVG đơn giản mới được đảm bảo hiển thị đúng ở mọi nơi

    • Hiện vẫn còn tồn tại dưới tên Adobe Animate và có thể xuất ra HTML
      Ngay từ đầu, so sánh SVG với Flash có vẻ giống như so sánh táo với cam
      Định dạng SVG không cần tự mình làm trực tiếp mọi thứ Flash từng làm, mà có thể dựa vào các công nghệ khác trong trình duyệt
    • Tôi nghĩ WebAssembly có thể là đối tượng so sánh
      Ví dụ Unity, Unreal, Godot có thể compile cho trình duyệt khá dễ dàng
      Vấn đề là các ứng dụng kiểu này khá phình to, thường dễ rơi vào phạm vi hàng chục MB chứ không phải chỉ vài MB một chữ số
    • Có vẻ có cơ hội startup để tái tạo thứ này
  • SVG có hoạt ảnh phức tạp thì chạy thử khá vui, nhưng nếu đi sâu vào SMIL, Safari có thể làm điện thoại đơ chỉ vì thiếu một số 0 trước dấu thập phân trong số dấu phẩy động, hoặc phát sinh đủ chuyện kỳ quặc

  • Nếu bạn đang tạo SVG động một cách sáng tạo bằng JavaScript và đang tìm việc, có thể gửi DM cho tôi

  • Tôi tự hỏi liệu có phần mở rộng SVG nào cho phép điều chỉnh mật độ của nét vẽ không
    Tôi có một máy plotter có thể nhấc và hạ bút, được điều khiển bằng file SVG
    Sẽ rất tốt nếu có thể hạ bút trong khi đang vẽ một nét, như thường làm trong chữ viết tay
    Nhân tiện, đó là Axidraw của Evil Mad Scientist Labs; thiết bị rất tuyệt và những người làm ra nó cũng rất đáng mến

    • Việc lưu chỉ thị tùy chỉnh trong một file SVG thông thường và diễn giải chúng ở trình đọc khá dễ
      Ví dụ tôi dùng một máy cắt laser/plotter đa dụng, trong đó độ mờ là công suất laser, độ dày nét là tốc độ di chuyển, kênh xanh lá là số lần lặp, kênh xanh dương là độ cao trục Z, kênh đỏ là hạ bút hoặc tắt laser, v.v.
    • Có lẽ những thứ như vậy nên xử lý bằng G-code thì tốt hơn
      Tôi đã làm loại công việc này ở đây
      https://github.com/WillAdams/gcodepreview
  • Trước khi tự làm icon hay logo, tôi luôn thấy việc SVG có biến đổi (transform) là kỳ lạ
    Rất khó căn các đường cong cho đúng
    Sau khi hoàn thành logo thứ hai, nó trông quá phẳng nên tôi muốn nghiêng 10°, và khi nghĩ đến việc phải viết lại tất cả các đường thẳng và đường cong đó, xoay nó trông là lựa chọn tốt hơn nhiều
    May là khi đặt cạnh văn bản thì trông kỳ, nên tôi lại phải đổi góc thêm vài lần để kerning nhìn có vẻ đúng

  • Gần đây tôi làm một game nhỏ cho vui, và phần render chủ yếu dùng các tile SVG hoạt ảnh bằng CSS: https://pipeline-panic.vercel.app/