สิ่งเจ๋ง ๆ ที่สร้างได้ด้วย SVG
(fuma-nama.vercel.app)- 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 ความคิดเห็น
ดูเท่อยู่หรอก แต่ถ้าเน้นให้ชัดแค่รายการปัจจุบันรายการเดียวน่าจะสะดุดตากว่า
ความคิดเห็นบน 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
&refใน SVG วิธีคือวางรูปทรง เส้นทาง ฯลฯ ไว้ใต้
defsแล้วกำหนดidจากนั้นค่อยนำกลับมาใช้ในตัว SVG หลัก และหน้าที่ลิงก์ไปก็ดูเหมือนใช้วิธีนั้นภายใน SVG แต่ละอันไม่ได้แชร์สี่เหลี่ยมระหว่างภาพหลายภาพ เพราะแต่ละภาพถูกใส่เข้ามาเป็น DOM แยกกัน
น่าสงสัยว่าทำไมนักออกแบบ SVG รุ่นแรกถึงมองว่าต้องนำกลไกเอนทิตีมาทำใหม่แบบเฉพาะกิจ
อาจเกี่ยวกับการที่สามารถ override คุณสมบัติการเรนเดอร์ ณ จุดที่ใช้งานได้ และในเวลานั้น SVG ก็อยู่ในกระแสการเปลี่ยนผ่านของ W3C ไปสู่ XHTML/XML ดังนั้นสมมติฐานที่ว่าเบราว์เซอร์จะเพิกเฉยต่อ entity definition หรือ prologue/DOCTYPE ของเอกสารก็น่าจะยังไม่ได้ถูกยึดเป็นหลัก
!doctypeหรือ!elementที่บ่งชี้ว่าเป็น DTD ไม่เจอถ้าหมายถึงแค่
defsกับuseของ SVG นั่นไม่ใช่ DTDhttps://developer.mozilla.org/en-US/docs/Web/SVG/Reference/E...
เช่น Billion laughs attack
https://en.wikipedia.org/wiki/Billion_laughs_attack
“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 ง่าย ๆ เท่านั้นที่จะแสดงผลได้ถูกต้องทุกที่
แต่แรกแล้วการเปรียบเทียบ SVG กับ Flash ก็ดูเหมือนเอาแอปเปิลไปเทียบกับส้ม
ฟอร์แมต SVG ไม่จำเป็นต้องทำทุกอย่างที่ Flash เคยทำเองโดยตรง และสามารถพึ่งพาเทคโนโลยีอื่นในเบราว์เซอร์ได้
เช่น Unity, Unreal, Godot สามารถ compile สำหรับเบราว์เซอร์ได้ค่อนข้างง่าย
ปัญหาคือแอปแบบนี้มักจะค่อนข้างเทอะทะ และมักไปอยู่ในช่วงหลายสิบ MB มากกว่าจะเป็นเลขหลักเดียว MB
SVG แอนิเมชันที่ซับซ้อนลองเล่นแล้วสนุก แต่พอลงลึกใน SMIL แล้ว Safari อาจทำให้มือถือค้างเพียงเพราะขาดเลข 0 ข้างหน้าทศนิยมไปตัวเดียว หรือเกิดเรื่องประหลาดสารพัด
ถ้าคุณกำลังสร้าง SVG แบบไดนามิกอย่างสร้างสรรค์ด้วย JavaScript และกำลังหางานอยู่ ส่ง DM มาได้
สงสัยว่ามีส่วนขยาย SVG ที่อนุญาต ความเข้ม ของเส้นหรือไม่
มี plotter ที่ยกปากกาและวางปากกาได้ และขับเคลื่อนด้วยไฟล์ SVG
อยากให้สามารถกดปากกาลงระหว่างลากเส้นได้ เหมือนที่มักทำในลายมือ
อ้างอิงคือ Axidraw ของ Evil Mad Scientist Labs ซึ่งเป็นอุปกรณ์ที่ยอดเยี่ยมและคนทำก็น่าทึ่ง
ตัวอย่างเช่น ผมใช้เครื่องตัดเลเซอร์/plotter อเนกประสงค์ โดยใช้ opacity เป็นกำลังเลเซอร์, ความหนาเส้นเป็นความเร็วในการเคลื่อนที่, ช่องสีเขียวเป็นจำนวนรอบซ้ำ, ช่องสีน้ำเงินเป็นความสูงแกน Z, ช่องสีแดงเป็นการวางปากกาลงหรือปิดเลเซอร์ เป็นต้น
งานประเภทนี้ทำอยู่ที่นี่
https://github.com/WillAdams/gcodepreview
ก่อนจะลองทำไอคอนหรือโลโก้เอง ผมเคยคิดเสมอว่าการมี transform ใน SVG เป็นเรื่องแปลก
การจัด curve ให้พอดีทำได้ยาก
พอทำโลโก้อันที่สองเสร็จแล้วมันดูแบนเกินไป เลยอยากเอียง 10° และพอคิดว่าจะต้องเขียนเส้นกับ curve ทั้งหมดนั้นใหม่ การหมุนก็ดูเป็นตัวเลือกที่ดีกว่ามาก
โชคดีที่พอวางข้างข้อความแล้วมันดูแปลก จึงได้ปรับมุมอีกหลายครั้งเพื่อให้ kerning ดูเข้าที่
เพิ่งทำเกมเล็ก ๆ เล่น ๆ เมื่อไม่นานมานี้ และใช้ ไทล์ SVG ที่แอนิเมตด้วย CSS เป็นหลักในการเรนเดอร์: https://pipeline-panic.vercel.app/
https://boardgamegeek.com/boardgame/333/waterworks