- HTML-in-Canvas คือโครงการของ WICG ที่เสนอ API มาตรฐานใหม่สำหรับวาดองค์ประกอบ/เนื้อหา HTML โดยตรงภายใน
<canvas>บนเว็บ - โครงการนี้เกิดขึ้นเพื่อแก้ปัญหาการจัดวางข้อความที่ซับซ้อน, ความสามารถในการเข้าถึง, การรองรับสากล, และปัญหาด้านคุณภาพ/ประสิทธิภาพ และทำให้สามารถนำการตกแต่งด้วย HTML มาใช้ได้โดยตรงใน กรณีการใช้ Canvas ที่หลากหลาย เช่น แผนภูมิ, UI, และเมนูเกม
- ผ่านเมธอดใหม่อย่าง
drawElement,texElement2D,setHitTestRegionsสามารถเรนเดอร์และทำเป็นเทกเจอร์ขององค์ประกอบ HTML ใน Canvas 2D หรือ WebGL context ได้โดยตรง - พื้นที่โต้ตอบ การปรับปรุง accessibility การวาง UI แบบ 2D ในฉาก 3D และเลย์เอาต์บนพื้นฐาน CSS/HTML สะท้อนความต้องการใช้งานจริงของนักพัฒนาเว็บแอป
- ขณะนี้สามารถเปิดใช้งานได้ใน Chrome Canary (ตั้งแต่ 138.0.7175.0 ขึ้นไป) ด้วย flag ทดลอง และยินดีรับฟีดแบ็กและรายงานบั๊กที่สำคัญ
ภาพรวมและความสำคัญ
- เสนอ API ใหม่ที่วาดองค์ประกอบ
<canvas>ด้วย HTML โดยตรงได้ - เดิมระบบยังขาดวิธีที่ง่ายต่อการเรนเดอร์เนื้อหา HTML ที่อิงข้อความและเลย์เอาต์ซับซ้อนลงบน
<canvas>ทำให้เกิดข้อจำกัดด้าน accessibility, ความเป็นสากล, performance และคุณภาพ - HTML-in-Canvas เป็นแนวทางเติมเต็มโดยรองรับการเรนเดอร์ HTML ใน canvas 2D และ WebGL ซึ่งช่วยเพิ่มความเหมาะสมในการนำไปใช้ในโดเมนต่างๆ เช่น เครื่องมือแผนภูมิ, กล่อง rich text, UI เกม
กรณีการใช้งาน
- การแสดง เนื้อหาแบบข้อความและเลย์เอาต์ที่มีสไตล์ ภายใน canvas
- ตัวอย่าง: คำอธิบายแผนภูมิ, แกน, กล่องแก้ไขข้อความแบบ rich, เมนูในเกม เป็นต้น
- การเสริม accessibility
- แก้ปัญหาความไม่ตรงกันระหว่างเนื้อหาทดแทนของ canvas แบบเดิมกับเนื้อหาที่เรนเดอร์จริง
- กับ API ใหม่ช่วยให้ซิงโครไนซ์ข้อมูล accessibility ได้
- การผสาน HTML กับ WebGL shader
- รองรับความต้องการเชื่อมต่อ HTML กับ WebGL shader ทั่วไป นอกเหนือจากเอฟเฟกต์ CSS filter
- การเรนเดอร์ HTML ใน context 3D
- สามารถแทรก rich 2D content ในพื้นที่ 3D ของเกม/เว็บไซต์ได้
API ที่เสนอและฟีเจอร์หลัก
- เปิดใช้งานเลย์เอาต์องค์ประกอบ HTML ย่อยของ canvas โดยใช้คุณสมบัติ
<canvas layoutsubtree>(โดยค่าเริ่มต้นจะเรนเดอร์เฉพาะมิติทางสายตา และไม่เผยแพร่ให้กับ algorithm ของ UA เช่นการนำทางหน้าเว็บ) - CanvasRenderingContext2D.drawElement(element, x, y, options)
- เรนเดอร์องค์ประกอบ HTML ลูกของ canvas ไปยังตำแหน่งที่กำหนด
- ควบคุมการป้องกันการรั่วไหลของข้อมูลส่วนบุคคลด้วย
options.allowReadback(วางแผนนำไปสู่การใช้นโยบาย tainting ในอนาคต) - รองรับการปรับขนาดตามต้องการด้วยพารามิเตอร์ dwidth/dheight
- WebGLRenderingContext.texElement2D(...)
- วาดองค์ประกอบ HTML ที่ระบุลงเป็น WebGL texture โดยตรง เพื่อใช้ในฉาก 3D
- setHitTestRegions
- ผูกองค์ประกอบที่วาดในพื้นที่เฉพาะกับอีเวนต์ของ canvas (hit test) เพื่อรีไดเรกต์เหตุการณ์ mouse/touch อัตโนมัติ
- fireOnEveryPaint option(ResizeObserver)
- ตรวจจับจังหวะรีเรนเดอร์ของ canvas อัตโนมัติเมื่อ HTML มีการเปลี่ยนแปลง/จัดวางใหม่ และกระตุ้นการวาดซ้ำ
การทำงานและข้อจำกัด
- เมื่อเรียก drawElement แล้ว จะสะท้อน
canvas transform matrix(CTM)และ clip รูปเฉพาะภายใน border box ขององค์ประกอบ - ภาพที่วาดบน canvas เป็น แบบคงที่ (เมื่อองค์ประกอบเปลี่ยนหลัง render แล้วต้องเรียก drawElement อีกครั้ง)
- ไม่รองรับกับ offscreen canvas หรือ canvas ที่ไม่อยู่ใน DOM (ข้อจำกัดด้านเทคนิค)
- องค์ประกอบแบบ interactive (เช่น ปุ่ม, ฟอร์ม ฯลฯ) วาดได้ แต่จะไม่ทำงานโต้ตอบโดยอัตโนมัติ
- ไม่รองรับ cross-origin iframe, SVG foreignObject และอื่นๆ
- ประเด็น accessibility, security, privacy (PII) ยังอยู่ระหว่างการหารืออย่างต่อเนื่อง
ตัวอย่างสาธิต
- ตัวอย่าง complex-text: วาดข้อความ HTML ที่มีสไตล์ กล่อง และเลย์เอาต์ที่ซับซ้อนลงบน canvas โดยตรงด้วย drawElement
- ตัวอย่าง webGL: ใช้ texElement2D สร้าง WebGL texture จากเนื้อหา HTML แล้วแมปไปยัง 3D cube
- ตัวอย่าง text-input: แสดงพื้นที่ที่สามารถโต้ตอบได้ เช่น input form โดยใช้ setHitTestRegions และ fireOnEveryPaint
การทดลองสำหรับนักพัฒนาและข้อควรระวัง
- เปิดใช้งานได้ใน Chrome Canary ด้วย flag
--enable-blink-features=CanvasDrawElement - เนื้อหาใน canvas ไม่ถูก taint จึง จำเป็นอย่างยิ่งต้องระวังการรั่วไหลของข้อมูลส่วนบุคคล
- API และพฤติกรรมยังเปลี่ยนแปลงอยู่ และยังขาดกรณีทดสอบ HTML ขนาดใหญ่
- ยินดีรับฟีดแบ็ก: แนะนำให้ส่งประเด็นเรื่องความเข้ากันได้, กรณีเรนเดอร์ล้มเหลว, ปัญหา accessibility ผ่าน GitHub Issue
การประยุกต์ใช้และแนวโน้ม
- ในพื้นที่อย่างแผนภูมิ, data visualization, in-canvas UI, HUD/เมนูในเกม 3D และอีกมากมาย API นี้สามารถยกระดับ การสื่อสารและความสามารถในการผลิตของเว็บ ได้
- ปัญหาการแปลง HTML→Canvas ซึ่งก่อนหน้านี้ซับซ้อน (สไตล์, เลย์เอาต์, รองรับหลายภาษา, accessibility) จะถูกจัดการได้แบบตรงไปตรงมาในระดับ API มาตรฐาน
- คาดหวังให้เป็นเทคโนโลยีใหม่ที่ทรงพลังสำหรับนักพัฒนาเว็บที่ทำกราฟิก เกม และแอปพลิเคชัน
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
มีความกังวลด้าน accessibility และการใช้งานในทางที่ไม่เหมาะสมค่อนข้างมากในประเด็นนี้ แต่ผมคิดว่าเราควรมองอีกด้านหนึ่งด้วย เมื่อเร็ว ๆ นี้ได้เห็นเธรดน่าสนใจบน X ที่กล่าวว่า เนื่องจากการเรนเดอร์ฟอนต์และการเข้าถึงเมตริกซ์ไม่ได้ใน JS ทำให้ “90% ของสิ่งดี ๆ ที่อาจเกิดขึ้นบนเว็บ” ไม่ได้เกิด หลายคนตอบว่า เว็บถูกออกแบบมาเพื่อแสดงข้อความ แต่ขาดความสามารถในการจัดการข้อความเชิงละเอียด และมีความเสียดายที่ tldraw ต้องดิ้นรนหาวิธีวัดข้อความเอง (เธรดบน X: https://x.com/_chenglou/status/1951481453046538493) เพราะเว็บคือแพลตฟอร์มทำแอปพลิเคชัน ทำให้ทุกคนได้ประโยชน์หากทำให้ทุกอย่างทั้งง่ายและทรงพลังมากขึ้น ในมุมมองผม API ของเว็บควรย้ายลงไประดับที่ต่ำกว่า และการมี canvas-specific font/text metrics API คงช่วยได้มาก ในขณะเดียวกันเอนจิ้น layout ข้อความของเว็บมีประสิทธิภาพสูงมากมาก หากฟีเจอร์เหล่านี้ถูกใช้ภายใน canvas ได้จริง คงเกิดความสามารถใหม่ที่ยอดเยี่ยม กรณีที่ผมยกบ่อย ๆ คือ “rich-text editing ที่รองรับการแบ่งหน้า” ซึ่ง contenteditable อย่างเดียวทำได้ไม่ถึงระดับโปรดักต์ ทำให้ Google Docs สร้าง layout engine ของตัวเอง หากข้อเสนอนี้สำเร็จ เราจะได้ทั้งความสามารถของ contenteditable และการควบคุม layout สำหรับหน้า/การพิมพ์ไปพร้อมกัน หวังว่าฟีเจอร์นี้จะได้เข้ามาในเบราว์เซอร์
ผมสงสัยกับข้ออ้างว่า “ส่วนใหญ่ของสิ่งดี ๆ ที่เกิดได้บนเว็บไม่สามารถเกิดเพราะไม่ได้เข้าถึงการเรนเดอร์ฟอนต์และเมตริกซ์” อยู่บ้าง อยากเห็นตัวอย่างที่เป็นนวัตกรรมชิ้นใหญ่จริง ๆ ว่าเป็นอะไร ตอนนี้ข้อมูลฟอนต์และเมตริกซ์ยังถูกเข้าถึงได้จาก JS ค่อนข้างมากอยู่แล้ว และแทบทุกอย่างที่ต้องการสามารถทำ workaround ได้โดยไม่ทำให้ประสิทธิภาพพังหนัก และที่สำคัญ HTML-in-Canvas เองก็ไม่ได้เปลี่ยนแปลงแกนกลางในจุดนี้โดยตรง
ผมเองก็ใช้ Harfbuzz และ layout engine ของตัวเองบน WASM ใน Nutrient เหมือน Google Docs เดโม: https://document-authoring-demo.nutrient.io/ ถ้า API แบบนี้เป็นของแพลตฟอร์มทางการแล้ว การพัฒนาจะง่ายขึ้นมาก ด้วย WASM ก็ไม่ใช่ทางตันจริง ๆ ได้ยินว่าจะมีงานซิงก์ที่ ElectricSQL อยู่ เลยขอทักทาย Oleksii ให้ด้วย
คำว่า “หวังว่าเบราว์เซอร์จะรับฟีเจอร์นี้” ของคุณทำให้ผมนึกว่า ทำไมถึงอยากดัน layout/UI engine ที่ไม่ประสิทธิภาพที่สุดในโลกให้ลามเข้าสู่ canvas เพราะแบบนั้นอาจทำให้ปัญหาความขาด API ที่ดีอยู่เดิมยังยิ่งคงอยู่ Figma เลือกเส้นทาง “สร้างเบราว์เซอร์อีกตัวหนึ่งอยู่ในเว็บ” เพื่อหลีกข้อจำกัดของ DOM (อ้างอิง: https://www.figma.com/blog/building-a-professional-design-tool-on-the-web/) ถ้า contenteditable ทำเป็นโปรดักต์เลเวลไม่ได้และ Google Docs ต้องทำ layout engine เอง ข้อเสนอนี้ก็ดูไม่ช่วยเรื่อง layout ของ rich text แบบจริงจังนัก
ผมคิดว่าคุณสมบัตินี้มีคุณค่ามาก แต่ตัวโครงสร้างที่ฝัง HTML ไว้ใน canvas ซึ่งอยู่ใน HTML เอง มันแปลกและไม่ค่อยเข้ากัน ในสายตาผม canvas ควรเป็น first-class format อิสระในเบราว์เซอร์ เพื่อให้ใช้งานได้อย่างยืดหยุ่น แบบนี้ทั้งการฝัง canvas ลงหน้า HTML และฝัง HTML ลงหน้า canvas จะดูเป็นธรรมชาติมากขึ้น แน่นอนว่าเป็นแค่ความเห็นส่วนตัวเท่านั้น
สิ่งที่คุณพูดไม่แปลกเลย อย่างน้อยตอนนี้เราฝังค่า HTML ใน SVG หรือฝังกลับเข้ากันใน HTML ได้อยู่แล้ว ถ้า canvas เป็นองค์ประกอบระดับบนสุดของหน้า แล้ว title ของหน้าจะเก็บไว้ที่ไหน? ก็ต้องใช้ `` แน่นอน ยกตัวอย่างเช่น
ถ้าทำให้ canvas รับคอนเทนต์ภายในแท็กได้โดยตรง ก็แก้ปัญหานี้แบบง่ายมาก
เว็บไซต์ที่โฟกัสที่ canvas อย่างเดียวมีความไม่สะดวกมาก ไม่สามารถใช้บริการของระบบได้ครบ (autocomplete, accessibility ฯลฯ) และยังมีเรื่อง privacy เช่น ระบบตรวจคำผิดอัตโนมัติจาก OS ใช้ได้ยาก และระบบ accessibility ของระบบปฏิบัติการก็ไม่ช่วย ดังนั้นแต่ละแอปต้องทำ accessibility ของ UI เองต่างกัน
ถ้าจะยึดโครงสร้างที่คุณพูดถึง มันก็เหมือนการ “คิดค้น Flash ขึ้นมาใหม่” เลย แต่อันนี้ก็เคยยากมากเมื่อฝัง Flash ในเว็บ
บางครั้งก็มีความต้องการใส่ canvas ลงในหน้า HTML แล้วปรับ layout/styling สำหรับข้อความภายใน canvas แต่ไม่จำเป็นต้องปรับทั้งแนวทาง layout ของทั้งหน้า
เคยมีคนคัดค้านการเข้าถึง DOM ผ่าน WASM จึงมองว่าเส้นทางแบบนี้อาจเป็นพัฒนาการที่หลีกเลี่ยงไม่ได้
ตอนนี้เรามาไกลมากแล้วจนถึงจุดที่สามารถคอมไพล์ browser ทั้งตัวเป็น WASM แล้ว แล้วรัน browser นั้นอยู่ในแท็ก canvas ของ browser หลักได้
ในเอกสาร https://github.com/WICG/html-in-canvas/blob/main/security-privacy-questionnaire.md มี TODO ระบุว่าควรเพิ่มเรื่องความเสี่ยง “fingerprinting”
ด้วย
foreignObjectของ SVG เราอาจได้ผลลัพธ์คล้ายกับ HTML-in-Canvas อยู่แล้ว ตัวอย่างเช่นโปรเจกต์อย่าง https://github.com/zumerlab/snapdom ที่คัดลอก DOM พร้อม inline style ไปใส่ในforeignObjectของ SVG แล้วเรนเดอร์ลง canvasforeignObjectลง canvas ง่ายขึ้น นอกจากนี้ยังรองรับการอัปเดต canvas อัตโนมัติเมื่อคอนเทนต์เปลี่ยน และการโต้ตอบ (interactivity) ฟีเจอร์ใหม่ ๆ เพิ่มเติมไม่แน่ใจว่าอาจเป็นความเข้าใจผิดของผม แต่น่าจะ render HTML บน canvas ได้ดีด้วย JS ล้วนอยู่แล้ว canvas ใช้สำหรับวาดสิ่งที่ทำด้วย HTML ไม่ได้ และไม่ได้มาทดแทน DOM โดยตรง
เราอาจไม่ช้าก็เร็วต้อง render canvas ใน HTML-in-Canvas ใหม่อีกครั้ง
ทำให้คิดถึง meme “Pimp My Ride” เลย รู้สึกเหมือน “น้อง พี่ว่าเหย้าโปรด HTML เลยแทรก HTML เข้า canvas แล้วก็แทรก canvas กลับเข้า HTML ให้"
คิดดูแล้วการเพิ่ม flag นี้ที่ body น่าสนใจไหม
แบบนี้หน้าทั้งหน้าเว็บก็เป็น drawing surface แบบเดียวกับ canvas และจะ render DOM elements ตามปกติได้ ถ้าเปิดกระบวนการ rasterize DOM ออกมาได้ก็น่าจะดีกว่า สถาปัตยกรรมจะทำให้ DOM rendering กับ canvas rendering เป็นเลเยอร์ที่เท่าเทียมกัน ตัวอย่างเช่น แสดงเส้นบนหน้าเว็บอาจกระตุ้นหรือเลี่ยงการทำ DOM reflow ได้ตามควบคุม
ผมจินตนาการถึงจังหวะที่ screen reader ทั้งหมดจะกรี๊ดพร้อมกันได้เลย
ถ้าทำแบบนี้ canvas อาจปรับขนาดอัตโนมัติได้ด้วย และถ้าเกิดได้จริงก็คือยุคใหม่ของการรวม HTML อาจล้ำหน้า iframe ได้
แม้มันจะดูแปลก แต่ผมก็ค่อนข้างเห็นด้วยกับข้อเสนอนี้ บางครั้งเวลาต้องวาดอะไร เรามักต้องนำ HTML element ที่มีอยู่มาใช้ซ้ำบ่อย เดิมเคย render หน้าเว็บเป็น bitmap แบบ offscreen แล้วคัดลอกเข้า canvas หรือพยายามจัดการด้วย z-index และ position absolute แต่ canvas มักทับมุมมองเสมอ (ช่วงหลังค่อนข้างดีขึ้นแล้ว) วิธีนี้อาจไม่ใช่คำตอบสมบูรณ์แบบ แต่ดีกว่าวิธีแก้กันแบบเดิมชัดเจน คล้ายกับ html2canvas คือ ถ้าจำเป็นจริง ๆ ตัวนี้เป็นวิธีที่คุ้มค่าใช้