3 คะแนน โดย GN⁺ 2025-04-13 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • SVG ไม่ได้เป็นแค่ฟอร์แมตไอคอนธรรมดาอีกต่อไป แต่สามารถนำ mask, path และ CSS animation มาผสมกันเพื่อสร้างเอฟเฟกต์สายไฟที่ไหลไปตามเส้นและไฮไลต์ TOC ได้
  • แนวคิดหลักของการทำงานคือ แทนที่จะแสดงเส้นที่สร้างด้วย line หรือ path โดยตรง จะใช้มันเป็น พื้นที่มาสก์ เพื่อจำกัดขอบเขตการแสดงผลของบล็อกที่มีแอนิเมชัน
  • Animated Wires ใช้ mask="url(#...)" กับ rect และขยับ translateY ด้วย @keyframes พร้อมขยายสไตล์ภาพด้วย linearGradient และ CSS variables
  • TOC สไตล์ Clerk ของ Fumadocs ต้องเรนเดอร์เส้นโครงบนเซิร์ฟเวอร์เพื่อให้ รองรับ SSR ส่วน thumb ที่แสดงตำแหน่งที่กำลังใช้งานจะเรนเดอร์บนไคลเอนต์โดยอาศัยข้อมูลตำแหน่งจากเบราว์เซอร์
  • แอททริบิวต์ d ของ SVG <path> ไม่ใช่สตริงที่สร้างอัตโนมัติ แต่เป็นรายการคำสั่ง จึงสามารถประกอบ ภาพมาสก์ ที่มีรูปร่างเดียวกับเส้นโครง TOC ที่เรนเดอร์จากเซิร์ฟเวอร์ขึ้นใหม่บนไคลเอนต์ได้

Animated Wires ที่สร้างด้วย SVG mask

  • โค้ดตัวอย่างอ้างอิงไวยากรณ์ JSX หรือ React ไม่ใช่ HTML ปกติ
  • เส้นพื้นฐานสามารถสร้างได้ด้วย line หรือ path ของ SVG
    • ในตัวอย่างมีการวาง line แนวตั้งไว้ภายใน viewBox="0 0 50 50"
  • แทนที่จะวาดเส้นลงบนหน้าจอโดยตรง จะนำเส้นนั้นไปใช้เป็น mask เพื่อจำกัดพื้นที่ที่รูปร่างอื่นจะมองเห็นได้
    • ใช้ mask="url(#line)" กับ rect และวาง line สีขาวไว้ภายใน mask
  • การเคลื่อนไหวสร้างขึ้นโดยใส่ CSS animation ให้กับ rect
    • @keyframes to-down จะเลื่อนจาก translateY(-10px) ไปถึง translateY(50px)
  • สไตล์ภาพสามารถขยายต่อได้ด้วยการผสมเส้นพื้นหลัง เส้นมาสก์ที่หนากว่า linearGradient และ CSS variable --height
    • @keyframes to-down-2 จะเลื่อนจาก calc(var(--height) * -1) ไปถึง 100%
  • เอฟเฟกต์ลักษณะคล้ายกันส่วนใหญ่ใช้วิธี ตัดบล็อกแอนิเมชันด้วยมาสก์
    • งานออกแบบบางแบบอาจสร้างใน Figma หรือโปรแกรมแก้ไข SVG อื่น ๆ ได้
    • หน้าแลนดิ้งเพจของ Unkey เป็นตัวอย่างของวิธีนี้

TOC สไตล์ Clerk ของ Fumadocs

  • Fumadocs มีการทำ สารบัญ (TOC) สไตล์ Clerk ไว้แล้ว
  • หากต้องการให้รองรับ SSR จะต้องเรนเดอร์เส้นโครง TOC จากฝั่งเซิร์ฟเวอร์โดยไม่พึ่ง JavaScript ฝั่งไคลเอนต์
    • บนเซิร์ฟเวอร์จะไม่สามารถรู้ตำแหน่งที่แน่นอนขององค์ประกอบได้
    • วิธีที่ใช้คือกำหนดตำแหน่งแบบ absolute แล้วเรนเดอร์เส้นโครงเป็นชิ้น ๆ คล้ายหลายคอมโพเนนต์ก่อนนำมาต่อกัน
  • ส่วนหนึ่งของเส้นโครงที่ตรงกับรายการที่กำลังใช้งานหรือ heading ที่มองเห็นอยู่ใน viewport จะแสดงเป็น thumb
    • เนื่องจาก thumb ต้องมีแอนิเมชัน การเปลี่ยนแค่สีของคอมโพเนนต์เส้นโครงจึงไม่เพียงพอ
    • thumb ซึ่งเป็นส่วนที่ใช้โต้ตอบจะถูกเรนเดอร์บนไคลเอนต์
  • ฝั่งไคลเอนต์จะประกอบ mask map จากข้อมูลตำแหน่งที่ได้จากเบราว์เซอร์
    • ใช้ SVG ในการสร้าง mask map นี้
    • แอททริบิวต์ d ของ SVG <path> เป็นรายการคำสั่ง และสามารถเรนเดอร์เส้นที่เชื่อมจุดต่าง ๆ ได้
    • ดูเอกสารที่เกี่ยวข้องได้ที่ MDN Web Docs ของ SVG Paths
  • SVG ที่ได้จะมีรูปร่างเหมือนกับเส้นโครง TOC ต้นฉบับที่เรนเดอร์ไว้ล่วงหน้าบนเซิร์ฟเวอร์
  • เช่นเดียวกับ Animated Wires ระบบจะใส่ SVG ในรูป data URL ลงใน CSS mask-image แล้วใช้มันมาสก์บล็อก div ที่มีแอนิเมชันเพื่อเรนเดอร์ thumb ที่ถูกไฮไลต์
    • div ภายในใช้ค่าประมาณ width: 1, height: thumb.height, transform: translateY(${thumb.top}px), transition: "all 500ms", backgroundColor: "white"
  • ดูการติดตั้งใช้งานใน React.js ได้จาก ซอร์สโค้ด toc-clerk.tsx

2 ความคิดเห็น

 
ndrgrd 2025-04-14

ดูเท่อยู่หรอก แต่ถ้าเน้นให้ชัดแค่รายการปัจจุบันรายการเดียวน่าจะสะดุดตากว่า

 
GN⁺ 2025-04-13
ความคิดเห็นบน Hacker News
  • ถึงจะเป็นเนื้อหาเมื่อ 8 ปีก่อน แต่พรีเซนเทชันชื่อดังของ Sarah Drasner เรื่อง “SVG Can Do That?” ก็ยังเปิดโลกให้หลายคนอยู่ดี
    หลังจากนั้น CSS โตขึ้นมากแล้ว ส่วนตัว SVG เองไม่แน่ใจว่าถึงขนาดนั้นไหม แต่ไม่ว่าอย่างไรก็แนะนำอย่างยิ่ง
    สไลด์: https://slides.com/sdrasner/svg-can-do-that
    วิดีโอ: https://youtu.be/ADXX4fmWHbo?si=6YPZkopyEDc8PSte

    • หนังสือเล่มนั้นก็ดีมากเช่นกัน แต่ไม่แน่ใจว่าเครื่องมือที่แนะนำในนั้นยังใช้ได้ดีอยู่หรือไม่
  • หนึ่งในสิ่งสนุก ๆ ที่ทำได้กับไฟล์ SVG คือการใช้ เอนทิตีของ inline DTD เพื่อกำหนดค่าคงที่ที่จะแชร์กันในหลายตำแหน่งของไฟล์
    ดูตัวอย่างที่ยอดเยี่ยมได้จาก SVG บนหน้า “Squares in Squares” ของ David Ellsworth
    ในเบราว์เซอร์หลัก ๆ ไม่มีปัญหา แต่เครื่องมือบางตัวอย่าง Inkscape ไม่แม้แต่จะ parse DTD หรือขยายเอนทิตีให้
    [0] https://kingbird.myphotos.cc/packing/squares_in_squares.html

    • “เอนทิตี” ที่พูดถึงตรงนี้ จริง ๆ แล้วเป็นชื่อของ กลไก SGML/XML สำหรับกำหนดและนำเนื้อหาไวยากรณ์ใด ๆ กลับมาใช้ซ้ำผ่าน entity reference อย่าง &ref
      ใน SVG วิธีคือวางรูปทรง เส้นทาง ฯลฯ ไว้ใต้ defs แล้วกำหนด id จากนั้นค่อยนำกลับมาใช้ในตัว SVG หลัก และหน้าที่ลิงก์ไปก็ดูเหมือนใช้วิธีนั้นภายใน SVG แต่ละอัน
      ไม่ได้แชร์สี่เหลี่ยมระหว่างภาพหลายภาพ เพราะแต่ละภาพถูกใส่เข้ามาเป็น DOM แยกกัน
      น่าสงสัยว่าทำไมนักออกแบบ SVG รุ่นแรกถึงมองว่าต้องนำกลไกเอนทิตีมาทำใหม่แบบเฉพาะกิจ
      อาจเกี่ยวกับการที่สามารถ override คุณสมบัติการเรนเดอร์ ณ จุดที่ใช้งานได้ และในเวลานั้น SVG ก็อยู่ในกระแสการเปลี่ยนผ่านของ W3C ไปสู่ XHTML/XML ดังนั้นสมมติฐานที่ว่าเบราว์เซอร์จะเพิกเฉยต่อ entity definition หรือ prologue/DOCTYPE ของเอกสารก็น่าจะยังไม่ได้ถูกยึดเป็นหลัก
    • อาจจะมีอะไรที่ผมพลาดไป แต่ในหน้านั้นหา !doctype หรือ !element ที่บ่งชี้ว่าเป็น DTD ไม่เจอ
      ถ้าหมายถึงแค่ defs กับ use ของ SVG นั่นไม่ใช่ DTD
    • ยังสามารถดึงส่วนอื่นของ SVG ที่มีอยู่แล้วออกมาแล้ว โคลนไปใช้ที่อื่นในหน้าได้
      https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/E...
    • ในเบราว์เซอร์อาจทำงานได้ แต่เครื่องมือ SVG จำนวนมากจะเพิกเฉยต่อ DTD เพราะ ความเสี่ยงจากการโจมตีแบบปฏิเสธการให้บริการ
      เช่น Billion laughs attack
      https://en.wikipedia.org/wiki/Billion_laughs_attack
    • หน้านั้นใช้เวลาราว ๆ 5 วินาทีเต็มในการเรนเดอร์บน iPhone SE รุ่นปี 2022
  • A Deep Dive Into SVG Path Commands” ของ Nanda Syahrasyad ดีมากสำหรับการทำความเข้าใจว่า path ของ SVG ประกอบขึ้นอย่างไร
    ถึงจะเป็นบทความเกือบ 2 ปีก่อน แต่ก็เปิดโลกให้เห็นว่า SVG ทำอะไรได้บ้างและทำอย่างไรอย่างแม่นยำ
    [0] https://www.nan.fyi/svg-paths

  • เคยทำโปรเจกต์ที่ทำอะไรสนุก ๆ แบบนี้ด้วย SVG
    สร้างด้วย React ใส่องค์ประกอบแอนิเมชันลงในภาพประกอบแบบ static หลายภาพ และสีถูก ควบคุมจาก CMS
    ฝั่ง frontend เรียก API เพื่อรับภาพ SVG ที่มีสีถูกต้อง แล้วจัดการแอนิเมชันด้วยการซ่อนและแสดงองค์ประกอบ SVG
    ดูตัวอย่างได้ที่นี่: https://web.archive.org/web/20221020133516im_/https://uncrow...

  • คิดถึง Macromedia Flash มากจริง ๆ
    ไม่มีเทคโนโลยีไหนเหมือน Flash กับฟอร์แมต SWF ที่แค่มี Flash Player ก็เล่นเกมอินดี้และดูภาพยนตร์แอนิเมชันได้มากมายโดยไม่ต้องดาวน์โหลดแยก
    อุปสรรคในการเริ่มต้นก็ต่ำมาก
    SVG มีศักยภาพที่จะทำทุกอย่างที่ SWF เคยทำได้ แต่ไม่มี editor แบบ Flash หรือวิธีเขียนโค้ดแบบอิงฉาก/ออบเจ็กต์อย่าง ActionScript
    แต่ละเบราว์เซอร์ก็มีพฤติกรรมเฉพาะตัวด้วย จึงรับประกันได้แค่ว่า SVG ง่าย ๆ เท่านั้นที่จะแสดงผลได้ถูกต้องทุกที่

    • ตอนนี้ก็ยังมีอยู่ในชื่อ Adobe Animate และ export เป็น HTML ได้
      แต่แรกแล้วการเปรียบเทียบ SVG กับ Flash ก็ดูเหมือนเอาแอปเปิลไปเทียบกับส้ม
      ฟอร์แมต SVG ไม่จำเป็นต้องทำทุกอย่างที่ Flash เคยทำเองโดยตรง และสามารถพึ่งพาเทคโนโลยีอื่นในเบราว์เซอร์ได้
    • คิดว่า WebAssembly น่าจะเป็นคู่เปรียบเทียบได้
      เช่น Unity, Unreal, Godot สามารถ compile สำหรับเบราว์เซอร์ได้ค่อนข้างง่าย
      ปัญหาคือแอปแบบนี้มักจะค่อนข้างเทอะทะ และมักไปอยู่ในช่วงหลายสิบ MB มากกว่าจะเป็นเลขหลักเดียว MB
    • ดูเหมือนมี โอกาสสตาร์ทอัพ ในการสร้างสิ่งนี้ขึ้นมาใหม่
  • SVG แอนิเมชันที่ซับซ้อนลองเล่นแล้วสนุก แต่พอลงลึกใน SMIL แล้ว Safari อาจทำให้มือถือค้างเพียงเพราะขาดเลข 0 ข้างหน้าทศนิยมไปตัวเดียว หรือเกิดเรื่องประหลาดสารพัด

  • ถ้าคุณกำลังสร้าง SVG แบบไดนามิกอย่างสร้างสรรค์ด้วย JavaScript และกำลังหางานอยู่ ส่ง DM มาได้

  • สงสัยว่ามีส่วนขยาย SVG ที่อนุญาต ความเข้ม ของเส้นหรือไม่
    มี plotter ที่ยกปากกาและวางปากกาได้ และขับเคลื่อนด้วยไฟล์ SVG
    อยากให้สามารถกดปากกาลงระหว่างลากเส้นได้ เหมือนที่มักทำในลายมือ
    อ้างอิงคือ Axidraw ของ Evil Mad Scientist Labs ซึ่งเป็นอุปกรณ์ที่ยอดเยี่ยมและคนทำก็น่าทึ่ง

    • การเก็บ คำสั่งกำหนดเอง ไว้ในไฟล์ SVG ปกติแล้วให้ reader ตีความนั้นทำได้ค่อนข้างง่าย
      ตัวอย่างเช่น ผมใช้เครื่องตัดเลเซอร์/plotter อเนกประสงค์ โดยใช้ opacity เป็นกำลังเลเซอร์, ความหนาเส้นเป็นความเร็วในการเคลื่อนที่, ช่องสีเขียวเป็นจำนวนรอบซ้ำ, ช่องสีน้ำเงินเป็นความสูงแกน Z, ช่องสีแดงเป็นการวางปากกาลงหรือปิดเลเซอร์ เป็นต้น
    • เรื่องแบบนั้นน่าจะให้ G-code จัดการจะดีกว่า
      งานประเภทนี้ทำอยู่ที่นี่
      https://github.com/WillAdams/gcodepreview
  • ก่อนจะลองทำไอคอนหรือโลโก้เอง ผมเคยคิดเสมอว่าการมี transform ใน SVG เป็นเรื่องแปลก
    การจัด curve ให้พอดีทำได้ยาก
    พอทำโลโก้อันที่สองเสร็จแล้วมันดูแบนเกินไป เลยอยากเอียง 10° และพอคิดว่าจะต้องเขียนเส้นกับ curve ทั้งหมดนั้นใหม่ การหมุนก็ดูเป็นตัวเลือกที่ดีกว่ามาก
    โชคดีที่พอวางข้างข้อความแล้วมันดูแปลก จึงได้ปรับมุมอีกหลายครั้งเพื่อให้ kerning ดูเข้าที่

  • เพิ่งทำเกมเล็ก ๆ เล่น ๆ เมื่อไม่นานมานี้ และใช้ ไทล์ SVG ที่แอนิเมตด้วย CSS เป็นหลักในการเรนเดอร์: https://pipeline-panic.vercel.app/