แนะนำบน HN: Dropflow เอนจินเลย์เอาต์ CSS สำหรับ Node หรือ <canvas>
(github.com/chearon)- Dropflow เป็นเอนจินเลย์เอาต์ CSS ที่สร้างขึ้นเพื่อสำรวจ มาตรฐาน CSS พื้นฐาน ได้แก่ inline, block, float, positioning และในอนาคตคือ table โดยไม่ได้มุ่งเป้าไปที่ flexbox และ grid
- สามารถใช้กับ Node และ node-canvas เพื่อ สร้าง PDF/รูปภาพ บนแบ็กเอนด์ และในเบราว์เซอร์สามารถเรนเดอร์ rich text ที่มีการตัดบรรทัดลงบน canvas ได้
- เลย์เอาต์ข้อความรองรับ ข้อความสองทิศทางและ RTL, การ fallback ฟอนต์ระดับกราฟีม, เครื่องหมายกำกับเสียงแบบมีสี, การลงทะเบียนฟอนต์ OpenType/TrueType และ shaping ที่อิง HarfBuzz
- ขอบเขตการรองรับ CSS มีมากกว่า 30 พร็อพเพอร์ตี โดย
float,clear,display: inline-block,position: relative,overflow,z-index,zoomเป็นต้นใช้งานได้ และtable,absolute,fixed,transformเป็นต้นยังอยู่ในขั้นวางแผน - ประสิทธิภาพสูงสุดได้จาก hyperscript API ที่ข้ามการ parse HTML/CSS และ object style ที่นำกลับมาใช้ซ้ำได้ โดยบน MacBook Pro ปี 2019 สามารถแปลง The Little Prince ที่มีมากกว่า 500 ย่อหน้าจาก HTML เป็นรูปภาพได้ในเวลาต่ำกว่า 160ms
ขอบเขตเลย์เอาต์ CSS ที่ Dropflow ครอบคลุม
- Dropflow เป็น เอนจินเลย์เอาต์ CSS ที่สร้างขึ้นเพื่อสำรวจขอบเขตของ foundational CSS standards
- เป้าหมายคือ inline, block, float, positioning และในอนาคตคือ tables
- flexbox และ grid ไม่ใช่เป้าหมาย
- มีการใช้งาน เลย์เอาต์ข้อความ คุณภาพสูง และสามารถแสดงภาษาต่าง ๆ ทั่วโลกได้
- มีการนำเสนอการใช้งานสองแบบ
- ใช้ Node และ node-canvas เพื่อสร้าง PDF หรือรูปภาพบนแบ็กเอนด์
- เรนเดอร์ rich text ที่ตัดบรรทัดได้ลงบน canvas ในเบราว์เซอร์
ฟีเจอร์หลัก
- รองรับพร็อพเพอร์ตี CSS มากกว่า 30 รายการ รวมถึงพร็อพเพอร์ตีที่ซับซ้อนอย่าง
float - ฟีเจอร์เกี่ยวกับข้อความครอบคลุมกว้าง
- ข้อความสองทิศทาง และข้อความ RTL
- ฟอนต์ fallback ระดับกราฟีม
- เครื่องหมายกำกับเสียงแบบมีสี
- การจัดการตัดบรรทัดที่เหมาะสม เช่น นำ padding เริ่มต้นไปไว้บรรทัดถัดไป
- shaping ที่ปรับแต่งประสิทธิภาพแล้ว
- นอกจาก HTML/CSS แล้ว ยังรองรับ hyperscript
h()API ที่ส่ง style เป็น object ได้ด้วย - สามารถลงทะเบียนบัฟเฟอร์ OpenType/TrueType ได้ และจำเป็นต้องลงทะเบียน
<img>รองรับ JPEG, BMP, PNG, GIF แต่การรองรับอาจแตกต่างกันตามแบ็กเอนด์- style ที่สืบทอดและผ่าน cascade แล้วจะไม่ถูกคำนวณซ้ำสองครั้ง
- มี type ครบถ้วน มีการทดสอบจำนวนมาก และตั้งเป้าให้ทำงานเร็ว
สถานะการรองรับ CSS
- รายการที่ทำงานได้ใน Inline formatting ได้แก่
color,direction,font-family,font-size,font-stretch,font-style,font-weight,line-height,text-align,vertical-align,white-space,word-break,overflow-wrap,word-wrap,word-spacingเป็นต้น - ใน Inline formatting,
font-variant,letter-spacing,tab-size,text-decoration,unicode-bidiอยู่ในสถานะ วางแผนไว้ - ใน Block formatting,
clearและfloatทำงานได้horizontal-tb,vertical-lr,vertical-rlของwriting-modeอยู่ในสถานะใช้งานได้บางส่วน- ใช้งานใน BFC แล้ว แต่ยังไม่ได้ใช้งานใน IFC
- ใน Boxes and positioning มีพร็อพเพอร์ตีกล่องและการจัดวางหลายรายการที่ทำงานได้
background-clip,background-color,border-color,border-style,border-widthtop,right,bottom,leftbox-sizingdisplay: block,inline,inline-block,flow-root,noneheight,margin,padding,overflow,width,z-index,zoomposition: relative
- ใน Boxes and positioning,
display: table,min/max-height,min/max-width,position: absolute,position: fixed,transformอยู่ในสถานะ วางแผนไว้
ลำดับการใช้งานพื้นฐาน
- Dropflow ทำงานบนพื้นฐาน DOM ที่มี style ที่สืบทอดและคำนวณแล้ว เช่นเดียวกับเบราว์เซอร์
- ลำดับทั่วไปมีดังนี้
- ลงทะเบียนฟอนต์ด้วย
FontFaceก่อนทำเลย์เอาต์ - สร้าง object style ด้วย
flow.style() - สร้าง DOM ด้วย
flow.h() - เตรียม tree สำหรับเรนเดอร์ด้วย
flow.dom() - ทำเลย์เอาต์และ paint ทั้ง canvas ด้วย
renderToCanvas()
- ลงทะเบียนฟอนต์ด้วย
- มี HTML API ให้ด้วย แต่แนะนำเฉพาะเมื่อประสิทธิภาพไม่สำคัญหรือเพื่อการเรียนรู้
- การ parse ทำให้ใช้เวลาเพิ่ม และเพิ่มขนาด bundle อย่างมาก
- ระบุไว้ว่าการ parse HTML นั้นเร็วได้เพราะ @fb55
- ปัจจุบันรองรับเฉพาะแอตทริบิวต์ HTML
styleส่วนclassยังไม่ทำงาน
ลักษณะด้านประสิทธิภาพ
- ประสิทธิภาพเป็นเป้าหมายสูงสุด และสำคัญรองจากความถูกต้อง
- มีตัวเลขประสิทธิภาพจากตัวอย่างดังนี้
- แปลง 8 ย่อหน้าที่มี inline span หลายรายการและฟอนต์ต่างกันจาก HTML เป็นรูปภาพ ใช้เวลา 9ms บน MacBook Pro ปี 2019 และ 13ms บน MacBook Pro ปี 2012
- แปลง The Little Prince ที่มีมากกว่า 500 ย่อหน้าจาก HTML เป็นรูปภาพ ใช้เวลา ต่ำกว่า 160ms บน MacBook Pro ปี 2019 และ ต่ำกว่า 250ms บน MacBook Pro ปี 2012
- สร้างคำยาว 10 ตัวอักษรและทำเฉพาะเลย์เอาต์ ใช้เวลา ต่ำกว่า 25µs บน MacBook Pro ปี 2019 และ ต่ำกว่า 50µs บน MacBook Pro ปี 2012
- ประสิทธิภาพที่เร็วที่สุดได้เมื่อสร้าง DOM โดยตรงด้วย hyperscript API และข้ามขั้นตอน parse HTML/CSS ทั่วไป
- หากนำ object style กลับมาใช้ซ้ำจะได้ประโยชน์มากขึ้น
- การ reflow ที่ความกว้างอื่นเร็วกว่าการสร้าง layout tree ใหม่
โครงสร้าง API
- ขั้นพื้นฐานมีสองอย่าง
- ลงทะเบียนฟอนต์
- สร้าง DOM ด้วย Hyperscript API หรือ Parse API
- ในการใช้งานแบบง่าย สามารถเรนเดอร์ DOM ลง canvas ได้โดยตรง
renderToCanvas(el, canvas)ใช้ width และ height ของ canvas เป็นขนาด viewport แล้วเรนเดอร์เลย์เอาต์ทั้งหมด
- หากใช้ API ระดับล่างกว่า จะสามารถเก็บเลย์เอาต์ไว้ได้
- โหลด resource ที่พึ่งพา
- สร้าง layout ของ DOM
- reflow layout
- paint ไปยังเป้าหมาย เช่น HTML5 canvas
- วิธีนี้ใช้สำหรับ reflow เป็นขนาดอื่น, ไม่ paint เลย์เอาต์ที่มองไม่เห็น หรือรับค่า intrinsics ได้
การจัดการฟอนต์
- ขั้นแรกของโปรแกรม Dropflow คือการลงทะเบียนฟอนต์ที่จะถูกเลือกด้วยพร็อพเพอร์ตี CSS font
- เนื่องจาก Dropflow ไม่ค้นหาฟอนต์ระบบ จึงต้องสร้างและเพิ่ม
FontFaceอย่างน้อยหนึ่งครั้ง - API ลงทะเบียนฟอนต์ใช้งาน subset ของ CSS Font Loading API และเพิ่มเมธอดนอกมาตรฐาน
loadSync - ฝั่งเซิร์ฟเวอร์สามารถโหลด URL
file:///แบบ synchronous ด้วยreadFileSyncได้ ArrayBufferจะถูกโหลดทันทีใน constructor เช่นเดียวกับในเบราว์เซอร์registerNotoFontsลงทะเบียน font family Noto Sans ทั้งหมด- ฟอนต์จัดจำหน่ายโดย FontSource และโฮสต์โดย jsDelivr
- เป็น import ขนาดใหญ่ เพราะมีฟอนต์ Noto Sans มากกว่า 200 รายการ และสตริง
unicodeRangeของฟอนต์ CJK มีขนาดใหญ่ - ระบุไว้ว่าสำหรับการใช้งาน production ในเบราว์เซอร์ การลงทะเบียนฟอนต์แยกเป็นรายตัวจะดีกว่า
- สำหรับ Latin มีการลงทะเบียนฟอนต์ italic และสำหรับทุกสคริปต์มีการลงทะเบียน normal 400 และ bold 700
- ภาษาจีน เกาหลี และญี่ปุ่นแชร์ Unicode code point ร่วมกัน แต่ตัวอักษรอาจเรนเดอร์ต่างกัน ดังนั้นหากเป็นไปได้ควรใช้ฟอนต์เฉพาะภาษานั้น ๆ
เลย์เอาต์, reflow, paint
layout(el)สร้าง layout ที่มี box tree, fragmentation tree และ glyph- box tree โดยรวมสอดคล้องกับ DOM tree แต่เพราะมีเนื้อหาข้อความแบบ anonymous จึงอาจมีกล่องมากขึ้น หรืออาจน้อยลงเพราะ
display: none
- box tree โดยรวมสอดคล้องกับ DOM tree แต่เพราะมีเนื้อหาข้อความแบบ anonymous จึงอาจมีกล่องมากขึ้น หรืออาจน้อยลงเพราะ
reflow(layout, width = 640, height = 480)จัดวางกล่อง แบ่งข้อความเป็นบรรทัด และทำให้พร้อม paint- margin collapsing ของ block box
- ส่งข้อความให้ HarfBuzz
- ทำ font fallback ซ้ำ
- reshaping ตามการตัดบรรทัดและ break point
- จัดวาง float และจัดการ
clear - จัดวาง shaped text span และ background ตาม
directionและทิศทางข้อความ - คำนวณ intrinsics ของเนื้อหา
float,inline-block,absolute - จัดการ
positionหลัง normal flow
- เป้าหมายสำหรับ paint ปัจจุบันรองรับ Canvas และ SVG
paintToCanvaspaint ไปยัง browser canvas, node-canvas หรือ context อื่นที่สอดคล้องกับมาตรฐานใกล้เคียงกันpaintToSvgสร้างสตริง SVG และรวมกฎ@font-faceที่อ้างอิง URL ที่ส่งให้FontFacepaintToSvgElementsไม่เพิ่ม<svg>และกฎ@font-faceเพื่อใช้เมื่อวาดใน SVG ที่มีอยู่แล้วpaintToHtmlสร้าง flat list ขององค์ประกอบที่จัดตำแหน่งแบบ absolute แม้ไม่แนะนำให้ใช้ แต่อาจมีประโยชน์ระหว่างพัฒนา
DOM API และ environment hooks
HTMLElementรากที่ได้จาก Hyperscript และ Parse API มีเมธอดค้นหาองค์ประกอบด้วย tag name,id,classคล้ายกลุ่มquerySelectorของ browserquery(selector)คืนค่าHTMLElementหนึ่งตัวหรือnullqueryAll(selector)คืนค่าHTMLElement[]
HTMLElementอาจมีกล่อง render ที่เชื่อมอยู่- โดยทั่วไปมีหนึ่งกล่อง แต่ถ้ามี inline และ block content ปนกันอาจมีหลายกล่อง
BlockContainerถูกสร้างสำหรับ absolute positioned element, floated element, inline-block, block-level elementReplacedBoxถูกสร้างสำหรับรูปภาพ
- Dropflow ออกแบบมาให้ปรับเข้ากับสภาพแวดล้อมหลากหลายได้
- ในเบราว์เซอร์ โหลดฟอนต์และรูปภาพด้วย
fetchและลงทะเบียนบัฟเฟอร์ฟอนต์กับdocument.fonts - ใน Nodejs สามารถโหลดฟอนต์แบบ synchronous ด้วย
fs.readFileSync - หากมี canvas backend และ
node-canvasจะเรียกregisterFontของnode-canvas node-canvasไม่รองรับ font buffer จึงต้องใช้ URLfile://
- ในเบราว์เซอร์ โหลดฟอนต์และรูปภาพด้วย
- หากต้องการใช้
@napi-rs/canvasหรือskia-canvasต้องมีโค้ดไม่กี่บรรทัดเพื่อเชื่อมflow.environment.registerFontเข้ากับ API ลงทะเบียนฟอนต์นั้น - environment มี hook 6 รายการ
wasmLocatorregisterFontresolveUrlresolveUrlSynccreateDecodedImagedestroyDecodedImage
Text shaping ที่อิง HarfBuzz
- Glyph layout ดำเนินการโดย HarfBuzz ที่คอมไพล์เป็น WebAssembly
- ตั้งเป้าเรื่อง ความถูกต้อง ซึ่งเป็นสิ่งที่ทำได้ยากด้วยวิธีจับตำแหน่ง text span ผ่าน API
measureText - ตัวอย่างเช่น หากใน Google Sheets ระบายสีเฉพาะ
"V"ใน"AV"เป็นสีอื่น kerning จะหายไป ทำให้ตัวอักษรอยู่ห่างกันกว่าปกติ- เพราะมีการเรียก
measureTextและfillTextสองครั้งแยกตามตัวอักษร ทำให้ contextual glyph advance หายไป
- เพราะมีการเรียก
- Dropflow ใช้ HarfBuzz ที่ shaping boundary ที่หยาบกว่า ไม่ใช่ตรงจุดที่สีเปลี่ยน เพื่อรองรับฟอนต์ได้ถูกต้องยิ่งขึ้น
- HarfBuzz ที่คอมไพล์เป็น WebAssembly สามารถให้ตัวชี้วัดประสิทธิภาพใกล้เคียงกับ
measureTextของCanvasRenderingContext2D- ระบุไว้ว่าแม้ไม่เร็วเท่า
measureTextแต่ก็ไม่ได้ช้ากว่ามาก - ระบุว่าทั้งสองอย่างไม่ใช่คอขวดหลักของสแตกเลย์เอาต์ข้อความ
- ระบุไว้ว่าแม้ไม่เร็วเท่า
- เลย์เอาต์ข้อความที่อิง
measureTextต้องมี word cache จึงจะทำงานเร็ว และระบุว่าแอป GSuite ใช้วิธีนี้- word cache ไม่สามารถรองรับฟอนต์ที่มีเอฟเฟกต์ข้ามช่องว่างได้
- หากจะรองรับฟอนต์ดังกล่าว ต้อง binary search ที่ break index ของย่อหน้า ซึ่งระบุว่าช้ากว่าการส่งทั้งย่อหน้าให้ HarfBuzz มาก
- เครื่องหมายกำกับเสียงแบบมีสีทำด้วย
measureTextไม่ได้
โปรเจกต์ที่พึ่งพา
- Dropflow ไม่มี dependency ใน
package.jsonแต่ใช้ผลงานจากหลายโปรเจกต์ - dependency ฝั่ง JavaScript ถูกเช็กอินไว้ในโปรเจกต์ และถูกแก้ไขในระดับต่าง ๆ เพื่อคงโฟกัสและหลีกเลี่ยงปัญหา dependency-of-dependency
- โปรเจกต์หลักมีดังนี้
- harfbuzz: ให้ font shaping และ font API ที่จำเป็น
- Tehreer/SheenBidi: คำนวณ bidi boundary
- foliojs/linebreak: ให้ Unicode break index
- peggyjs/peggy: สร้าง CSS parser
- fb55/htmlparser2: HTML parsing
- google/emoji-segmenter: emoji segmenting
- foliojs/grapheme-breaker: ให้ Unicode grapheme boundary และถูกแก้ไขอย่างมากสำหรับ Unicode 15
- foliojs/unicode-trie: ใช้สำหรับ Unicode data ที่รวดเร็ว และถูกแก้ไขอย่างมากเพื่อตัดส่วนที่ไม่ใช้ออก
3 ความคิดเห็น
ชื่อเดิมคือ "Show HN: Dropflow, a CSS layout engine for node or <canvas>" นั่นเอง ตอนนี้กลายเป็น "GN⁺: HN แนะนำ: เอนจินเลย์เอาต์ CSS สำหรับ Node หรือ <canvas>, Dropflow</canvas>" ไปแล้วครับ
มีแท็กอยู่ในชื่อเรื่อง เลยทำให้ส่วนชื่อบนหน้ารายละเอียดเพี้ยนไปสินะ.. ฮ่าๆ ควร escape หน่อย..
ความคิดเห็นบน Hacker News
ทุกวันนี้วิธีมาตรฐานในการสร้าง PDF สวย ๆ บนแบ็กเอนด์คือการเปิด เฮดเลสเบราว์เซอร์ แล้วใช้ Browser API แปลง HTML/CSS เป็น PDF แต่ต้นทุนในการรันอินสแตนซ์ของเบราว์เซอร์บนเซิร์ฟเวอร์และสเกลให้รองรับงานปริมาณมากนั้นค่อนข้างสูง
เครื่องมือนี้เป็นตัวเปลี่ยนเกม เพราะตอนนี้สามารถออกแบบและสร้าง PDF ด้วย HTML/CSS ได้โดยไม่ต้องมีโอเวอร์เฮดของเบราว์เซอร์
เพียงแต่ PDF ที่ผมสร้างนั้นแน่นอนว่าไม่ได้สวยงามเท่าไร นั่นอาจเป็นความแตกต่างก็ได้
ทุกคนต้องเป็นไปตาม ADA จึงเปลี่ยนไปใช้ Canvas renderer ได้ยาก เพราะแบบนั้นการเข้าถึงได้จะหายไป
ดูดีมากจริง ๆ ที่งานก่อนหน้านี้ผมพัฒนาแพลตฟอร์มการเรียนรู้ออนไลน์แบบ immersive โดยใช้ Oculus Quest 2 ฝึกภาษาต่างประเทศให้บุคลากรกระทรวงกลาโหม และใช้ WebXR, Three.js เป็นต้น
Unity3D ครั้งเดียวก็เกินพอแล้ว และผมก็ไม่อยากผ่านการตรวจของแอปสโตร์ด้วย เรามีกลุ่มอุปกรณ์ของตัวเองเลยไม่มีปัญหา
หนึ่งในความท้าทายใหญ่ที่สุดคือการสร้างเวิร์กโฟลว์สำหรับคอนเทนต์บทเรียน และแทบต้องทำคนเดียวทั้งหมด อาจารย์ภาษาตัวจริงจะสร้าง PDF ด้วย PowerPoint แล้วอัปโหลด PDF เข้า content database ผ่านเอดิเตอร์เฉพาะที่ผมทำขึ้น เพื่อเอาไปวางในสภาพแวดล้อมการฝึก จากนั้นใช้ PDFJS เรนเดอร์ลงองค์ประกอบ Canvas แล้วใช้เป็นเท็กซ์เจอร์ของสี่เหลี่ยม 3D
ถ้ามีเครื่องมือแบบนี้ ผู้คนก็คงไม่ต้องอ้อมไปทำสื่อด้วย PowerPoint วิธี PowerPoint ช่วยให้เวิร์กโฟลว์เร็วขึ้นมากเมื่อเทียบกับความพยายามก่อนหน้าที่ให้ทำภาพด้วย Photoshop แต่ถ้าสร้าง ตัวแก้ไขป้าย ไว้ในแอปได้ ก็น่าจะดีกว่า เพราะจะตัดวงจร “เดาว่าจะดูเป็นอย่างไรในสภาพแวดล้อม → ส่งออกเป็น PDF → อัปโหลดเข้า DB → ตรวจดูของจริง” ออกไปได้
ถึงอย่างไรก็คงไม่ได้มีความหมายมากนัก เพราะไม่มีทีม business development หรือการตลาดที่เข้าใจแต่การขายบริการ ไม่ใช่ผลิตภัณฑ์
ผมกำลังมองหาของแบบนี้สำหรับโปรเจกต์ของผม https://htwins.net/scale2 และงานอื่น ๆ ที่ใช้ SVG หรือ Canvas อยู่
ถ้ากำลังปวดหัวกับ Flexbox ก็มีเครื่องมือที่ช่วยทำให้ขั้นตอนง่ายขึ้น เพื่อไม่ต้องกังวลกับหลายพร็อพเพอร์ตีเวลาสร้างเลย์เอาต์แบบ responsive: https://flexboxcss.com
ยอดเยี่ยม เครื่องมือแบบนี้สำคัญมากเพราะทำให้ กล่องวิเศษ ที่ชื่อว่า browser rendering engine เข้าใจได้มากขึ้น
หากเราสร้างสเปกที่เครื่องอ่านได้อย่างสมบูรณ์สำหรับการเรนเดอร์ HTML และ CSS ได้ ก็น่าจะสร้าง renderer ออกมาได้ พฤติกรรมเฉพาะของแต่ละเบราว์เซอร์อาจวางเป็นส่วนขยายทับขึ้นไปได้ อยากให้สิ่งอย่าง https://github.com/tawesoft/html5spec กลายเป็นรูปแบบที่ใช้กับเอนจินจริงได้
ค่อนข้างใกล้กับสิ่งที่ช่วงนี้กำลังสงสัยอยู่ ผมกำลังคิดว่าจะใช้ CSS และ SVG เป็น ชั้น abstraction เหนือไลบรารีกราฟิกและ UI ได้หรือไม่
เพิ่งเคยได้ยิน node-canvas แต่ดูเหมือนจะเติมเต็มส่วนการวาดให้ได้ เครื่องมือนี้ดูจะรับหน้าที่ส่วนเลย์เอาต์ ซึ่งเป็นทั้งหมดที่ผมต้องการจากไลบรารี UI ได้
ก็สงสัยเหมือนกันว่าการ implement CSS นั้นยากแค่ไหน ได้ยินมาว่าค่อนข้างซับซ้อน
การ implement CSS นั้นยาก แต่กำแพงที่ใหญ่ที่สุดคือความรู้ไม่ได้ถูกเปิดเผยให้เห็นชัดเจน
ส่วนที่ยากที่สุดคือ เลย์เอาต์ข้อความ การจัดการ glyph และการวนย้อนทางเพื่อ RTL ทำให้ปวดหัว และการตัดบรรทัดก็ซับซ้อนจริง ๆ ยิ่งยากขึ้นเพราะความรู้ที่ต้องใช้ไม่ได้ถูกรวบรวมไว้ในที่เดียว
หลังจากทำ block layout เสร็จในช่วงแรกแล้ว ผมต้องใช้เวลาหลายปีทำงานแค่สัปดาห์ละไม่กี่ชั่วโมง เพื่อเรียนรู้รายละเอียดของ text shaping และ itemization รวมถึงสิ่งที่ควรทำและไม่ควรทำ หลายส่วนเรียนรู้จากการอ่านซอร์สโค้ดของ Pango [1] และที่เหลือก็ปะติดปะต่อจากการค้นหา Google
นอกเหนือจากนั้น สเปกของ W3C ครอบคลุมแทบทุกอย่าง มาตรฐาน CSS2 [2] เป็นหนึ่งในเอกสารที่สวยงามที่สุดเท่าที่ผมเคยอ่านมา มันสอดคล้องภายใน กระชับ และเป็นผลลัพธ์จากการไตร่ตรองและลองผิดลองถูกมาหลายปี CSS3 ก็ยอดเยี่ยมเช่นกัน แต่ CSS2 คือรากฐานของทุกอย่าง
[1] https://gitlab.gnome.org/GNOME/pango/
[2] https://www.w3.org/TR/CSS22/
เป็นการมีส่วนช่วยต่อโลกอย่างยิ่ง ดูเหมือนกรณีคลาสสิกที่ทุกคนคิดว่า “ใครสักคนควรทำ $X” แต่ไม่มีใครลงมือทำ
ในฐานะคนที่ชอบใช้ CSS สำหรับเลย์เอาต์ ช่วงนี้ผมพึ่งพา Flexbox และ Grid เป็นหลัก เข้าใจได้เต็มที่ว่ายังไม่รองรับ แต่อยากรู้ว่ามีแผนจะรองรับในสักวันไหม ถ้ามี คนอื่น ๆ จะช่วยได้อย่างไร?
สุดยอดจริง ๆ คนส่วนใหญ่คงไม่รู้ว่าการแปลง HTML เป็น PNG ด้วยโปรแกรมนั้นยากแค่ไหน
คุณจะเจอปัญหาเล็ก ๆ นับไม่ถ้วนจาก ความแตกต่างระหว่าง Node กับเบราว์เซอร์ หรือ ความแตกต่างระหว่าง HTML กับ Canvas
ดูมีประโยชน์ นึกภาพไม่ออกเลยว่าต้องใช้แรงงานมากแค่ไหนในการทำให้เข้าใจ CSS ก่อน แล้วสร้าง layout engine ขึ้นมาบนนั้น