- Dropflow adalah mesin layout CSS yang dibuat untuk mengeksplorasi standar CSS dasar seperti inline, block, float, positioning, dan ke depannya table; flexbox dan grid bukan targetnya
- Dapat digunakan untuk membuat PDF dan gambar di backend dengan Node dan node-canvas, serta di browser untuk merender rich text dengan line wrapping ke canvas
- Layout teks mendukung teks bidirectional dan RTL, fallback font per grafem, diakritik berwarna, registrasi font OpenType/TrueType, serta shaping berbasis HarfBuzz
- Cakupan dukungan CSS mencakup lebih dari 30 properti;
float,clear,display: inline-block,position: relative,overflow,z-index,zoom, dan lainnya sudah berfungsi, sementaratable,absolute,fixed,transform, dan lainnya masih dalam tahap rencana - Performa terbaik diperoleh dari hyperscript API yang melewati parsing HTML/CSS dan objek style yang dapat digunakan ulang; pada MacBook Pro 2019, The Little Prince dengan lebih dari 500 paragraf dapat dikonversi dari HTML menjadi gambar dalam kurang dari 160 ms
Cakupan layout CSS yang ditangani Dropflow
- Dropflow adalah mesin layout CSS yang dibuat untuk mengeksplorasi cakupan foundational CSS standards
- Targetnya adalah inline, block, float, positioning, dan ke depannya tables
- Flexbox dan grid bukan targetnya
- Memiliki implementasi layout teks berkualitas tinggi dan dapat menampilkan berbagai bahasa di dunia
- Ada dua penggunaan yang disebutkan
- Membuat PDF atau gambar di backend menggunakan Node dan node-canvas
- Merender rich text yang dibungkus barisnya ke canvas di browser
Fitur utama
- Mendukung lebih dari 30 properti CSS, termasuk properti kompleks seperti
float - Fitur terkait teksnya luas
- Teks bidirectional dan teks RTL
- Fallback font per grafem
- Diakritik berwarna
- Penanganan line break yang diinginkan, misalnya membawa padding awal ke baris berikutnya
- Shaping yang dioptimalkan
- Selain HTML/CSS, cara input juga mendukung hyperscript
h()API yang meneruskan style sebagai objek - Buffer OpenType/TrueType dapat diregistrasikan, dan registrasi wajib dilakukan
<img>mendukung JPEG, BMP, PNG, GIF, tetapi dukungan dapat berbeda tergantung backend- Style yang diwariskan dan dikaskadekan tidak dihitung dua kali
- Tipenya lengkap, memiliki banyak pengujian, dan menargetkan operasi yang cepat
Status dukungan CSS
- Item yang berfungsi dalam inline formatting mencakup
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, dan lainnya - Dalam inline formatting,
font-variant,letter-spacing,tab-size,text-decoration,unicode-bidiberstatus direncanakan - Dalam block formatting,
cleardanfloatsudah berfungsihorizontal-tb,vertical-lr,vertical-rlpadawriting-modeberada dalam status implementasi parsial- Sudah diimplementasikan pada BFC, tetapi belum pada IFC
- Dalam boxes and positioning, berbagai properti box dan penempatan sudah berfungsi
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
- Dalam boxes and positioning,
display: table,min/max-height,min/max-width,position: absolute,position: fixed,transformberstatus direncanakan
Alur penggunaan dasar
- Dropflow bekerja berdasarkan DOM dengan style yang diwariskan dan dihitung, seperti cara kerja browser
- Alur umumnya adalah sebagai berikut
- Mendaftarkan font dengan
FontFacesebelum layout - Membuat objek style dengan
flow.style() - Membuat DOM dengan
flow.h() - Menyiapkan tree yang akan dirender dengan
flow.dom() - Melakukan layout dan paint ke seluruh canvas dengan
renderToCanvas()
- Mendaftarkan font dengan
- HTML API juga disediakan, tetapi hanya direkomendasikan ketika performa tidak penting atau untuk tujuan belajar
- Parsing menambah waktu dan sangat memperbesar ukuran bundle
- Tertulis bahwa parsing HTML cepat berkat @fb55
- Saat ini hanya atribut HTML
styleyang didukung, sementaraclassbelum berfungsi
Karakteristik performa
- Performa adalah sasaran utama dan menjadi hal terpenting setelah akurasi
- Angka performa berbasis contoh disajikan
- Mengonversi 8 paragraf dengan beberapa inline span dan font berbeda dari HTML menjadi gambar membutuhkan 9 ms di MacBook Pro 2019 dan 13 ms di MacBook Pro 2012
- Mengonversi The Little Prince dengan lebih dari 500 paragraf dari HTML menjadi gambar membutuhkan kurang dari 160 ms di MacBook Pro 2019 dan kurang dari 250 ms di MacBook Pro 2012
- Membuat kata 10 huruf dan hanya menjalankan layout membutuhkan kurang dari 25 µs di MacBook Pro 2019 dan kurang dari 50 µs di MacBook Pro 2012
- Performa tercepat diperoleh saat membuat DOM langsung dengan hyperscript API dan melewati tahap parsing HTML/CSS yang umum
- Menggunakan ulang objek style memberi manfaat lebih besar
- Reflow pada lebar berbeda lebih cepat daripada membuat ulang layout tree
Susunan API
- Tahap dasarnya ada dua
- Registrasi font
- Membuat DOM dengan Hyperscript API atau Parse API
- Dalam penggunaan sederhana, DOM dapat langsung dirender ke canvas
renderToCanvas(el, canvas)menggunakan width dan height canvas sebagai ukuran viewport untuk merender seluruh layout
- Dengan API level lebih rendah, layout dapat dipertahankan
- Memuat resource dependen
- Membuat layout DOM
- Reflow layout
- Paint ke target seperti canvas HTML5
- Cara ini dapat digunakan untuk reflow ke ukuran berbeda, tidak melakukan paint pada layout yang tidak terlihat, atau mendapatkan intrinsics
Penanganan font
- Tahap pertama program Dropflow adalah mendaftarkan font yang akan dipilih oleh properti CSS font
- Karena Dropflow tidak mencari font sistem, setidaknya satu
FontFaceharus dibuat dan ditambahkan - API registrasi font mengimplementasikan subset CSS Font Loading API dan menambahkan metode nonstandar
loadSync - Di sisi server, URL
file:///dapat dimuat secara sinkron denganreadFileSync ArrayBufferdimuat langsung di constructor seperti di browserregisterNotoFontsmendaftarkan semua keluarga font Noto Sans- Font didistribusikan oleh FontSource dan dihosting oleh jsDelivr
- Ini adalah import besar karena ada lebih dari 200 font Noto Sans dan string
unicodeRangeuntuk font CJK besar - Untuk penggunaan produksi di browser, disebutkan bahwa lebih baik mendaftarkan font secara individual
- Untuk Latin, font italic diregistrasikan, dan untuk semua skrip diregistrasikan normal 400 serta bold 700
- Bahasa Mandarin, Korea, dan Jepang berbagi code point Unicode yang sama, tetapi karakter dapat dirender berbeda, jadi jika memungkinkan lebih baik menggunakan font khusus bahasa tersebut
Layout, reflow, paint
layout(el)membuat layout yang mencakup box tree, fragmentation tree, dan glyph- Box tree umumnya berkorespondensi dengan DOM tree, tetapi bisa memiliki lebih banyak box karena konten teks anonim atau lebih sedikit karena
display: none
- Box tree umumnya berkorespondensi dengan DOM tree, tetapi bisa memiliki lebih banyak box karena konten teks anonim atau lebih sedikit karena
reflow(layout, width = 640, height = 480)menempatkan box, membagi teks menjadi baris, dan membuatnya siap untuk di-paint- Margin collapsing pada block box
- Meneruskan teks ke HarfBuzz
- Pengulangan fallback font
- Reshaping berdasarkan line break dan break point
- Penempatan float dan penanganan
clear - Penempatan shaped text span dan background berdasarkan
directiondan arah teks - Perhitungan intrinsics untuk konten
float,inline-block,absolute - Penanganan
positionsetelah normal flow
- Target paint saat ini mendukung Canvas dan SVG
paintToCanvasmelakukan paint ke canvas browser, node-canvas, atau context serupa yang mematuhi standarpaintToSvgmembuat string SVG dan menyertakan aturan@font-faceyang merujuk URL yang diteruskan keFontFacepaintToSvgElementstidak menambahkan aturan<svg>dan@font-faceagar dapat digunakan ketika menggambar di dalam SVG yang sudah adapaintToHtmlmembuat flat list elemen berposisi absolut; penggunaannya tidak direkomendasikan, tetapi dapat berguna saat pengembangan
DOM API dan hook lingkungan
- Root
HTMLElementyang diperoleh dari Hyperscript dan Parse API menyediakan metode untuk mencari elemen berdasarkan tag name,id, danclass, seperti keluargaquerySelectorpada browserquery(selector)mengembalikan satuHTMLElementataunullqueryAll(selector)mengembalikanHTMLElement[]
HTMLElementdapat memiliki render box yang terhubung- Biasanya satu, tetapi bisa lebih dari satu jika konten inline dan block bercampur
BlockContainerdibuat untuk absolute positioned element, floated element, inline-block, dan block-level elementReplacedBoxdibuat untuk gambar
- Dropflow dirancang agar dapat disesuaikan dengan berbagai lingkungan
- Di browser, font dan gambar dimuat dengan
fetch, lalu buffer font didaftarkan kedocument.fonts - Di Nodejs, font dapat dimuat secara sinkron dengan
fs.readFileSync - Jika ada backend canvas dan
node-canvas,registerFontmiliknode-canvasdipanggil - Karena
node-canvastidak mendukung buffer font, URLfile://harus digunakan
- Di browser, font dan gambar dimuat dengan
- Untuk memakai
@napi-rs/canvasatauskia-canvas, diperlukan beberapa baris kode yang menghubungkanflow.environment.registerFontke API registrasi font terkait - Lingkungan memiliki 6 hook
wasmLocatorregisterFontresolveUrlresolveUrlSynccreateDecodedImagedestroyDecodedImage
Shaping teks berbasis HarfBuzz
- Layout glyph dilakukan oleh HarfBuzz yang dikompilasi ke WebAssembly
- Tujuannya adalah akurasi yang sulit diperoleh dengan cara menentukan posisi span teks menggunakan API
measureText - Sebagai contoh, jika hanya
"V"pada"AV"di Google Sheets diberi warna berbeda, kerning hilang sehingga huruf menjadi lebih berjauhan dari semestinya- Ini terjadi karena dua panggilan
measureTextdanfillTextdilakukan per huruf, sehingga contextual glyph advance hilang
- Ini terjadi karena dua panggilan
- Dropflow menggunakan HarfBuzz pada shaping boundary yang lebih kasar, bukan di titik perubahan warna, untuk mendukung font dengan lebih akurat
- HarfBuzz yang dikompilasi ke WebAssembly dapat menghasilkan metrik performa yang mirip dengan
measureTextpadaCanvasRenderingContext2D- Disebutkan bahwa ini tidak secepat
measureText, tetapi tidak jauh lebih lambat - Keduanya disebut bukan bottleneck dominan dalam stack layout teks
- Disebutkan bahwa ini tidak secepat
- Layout teks berbasis
measureTextmemerlukan word cache agar dapat berjalan cepat, dan disebutkan bahwa aplikasi GSuite menggunakan cara ini- Word cache tidak dapat mendukung font yang memiliki efek melintasi spasi
- Untuk mendukung font semacam itu, diperlukan binary search pada break index paragraf, dan disebutkan bahwa ini jauh lebih lambat daripada meneruskan seluruh paragraf ke HarfBuzz
- Diakritik berwarna tidak mungkin dilakukan dengan
measureText
Proyek dependensi
- Dropflow tidak memiliki dependensi
package.json, tetapi memanfaatkan pekerjaan dari berbagai proyek - Dependensi JavaScript di-check-in ke proyek dan dimodifikasi dalam berbagai tingkat untuk menjaga fokus serta menghindari masalah dependency-of-dependency
- Proyek utama adalah sebagai berikut
- harfbuzz: menyediakan font shaping dan API font penting
- Tehreer/SheenBidi: menghitung bidi boundary
- foliojs/linebreak: menyediakan Unicode break index
- peggyjs/peggy: membuat CSS parser
- fb55/htmlparser2: parsing HTML
- google/emoji-segmenter: segmentasi emoji
- foliojs/grapheme-breaker: menyediakan Unicode grapheme boundary, dimodifikasi besar-besaran untuk Unicode 15
- foliojs/unicode-trie: digunakan untuk data Unicode cepat, dimodifikasi besar-besaran untuk menghapus bagian yang tidak digunakan
3 komentar
Judul aslinya ternyata "Show HN: Dropflow, a CSS layout engine for node or <canvas>". Sekarang masuk sebagai "GN⁺: HN memperkenalkan: mesin tata letak CSS untuk Node atau <canvas>, Dropflow</canvas>".
Karena ada tag di judul, bagian judul di halaman detail jadi rusak ya.. haha, perlu di-escape..
Komentar Hacker News
Saat ini cara standar untuk membuat PDF yang bagus di backend adalah menjalankan browser headless lalu mengubah HTML/CSS menjadi PDF lewat API browser, tetapi biaya menjalankan instance browser di server dan menskalakannya untuk beban kerja besar cukup tinggi
Ini alat yang mengubah permainan, jadi sekarang HTML/CSS bisa dipakai untuk mendesain dan menghasilkan PDF tanpa overhead browser
Tapi PDF yang saya hasilkan memang jelas tidak terlalu indah, jadi mungkin itu bedanya
Semuanya harus patuh ADA, jadi sulit beralih ke renderer Canvas. Kalau begitu aksesibilitasnya hilang
Kelihatannya sangat bagus. Di pekerjaan sebelumnya saya mengembangkan platform pembelajaran online imersif, dan kami melatih personel Departemen Pertahanan dalam bahasa asing memakai Oculus Quest 2, WebXR, Three.js, dan lainnya
Sekali memakai Unity3D saja sudah cukup, dan saya juga tidak ingin melalui proses review app store. Karena kami punya armada perangkat sendiri, itu tidak masalah
Salah satu tantangan terbesar adalah membangun workflow konten materi ajar, dan saya hampir harus mengerjakannya sendirian. Para pengajar bahasa sungguhan membuat PDF dari PowerPoint, lalu dengan editor khusus yang saya buat saya unggah PDF itu ke basis data konten dan men-deploy-nya ke lingkungan pelatihan, kemudian merendernya ke elemen Canvas dengan PDFJS untuk dipakai sebagai tekstur pada persegi panjang 3D
Kalau alat seperti ini ada, orang tidak perlu memutar lewat PowerPoint untuk membuat materi. Pendekatan PowerPoint memang sangat meningkatkan kecepatan workflow dibanding upaya sebelumnya yang membuat orang membuat gambar di Photoshop, tetapi akan lebih baik lagi kalau kami bisa membuat editor papan tanda di dalam aplikasi agar menghilangkan siklus “menebak bagaimana tampilannya di lingkungan → ekspor ke PDF → unggah ke DB → cek tampilan aslinya”
Toh tidak terlalu berarti juga karena kami tidak punya tim business development atau marketing yang hanya paham menjual layanan, bukan produk
Saya sudah mencari sesuatu seperti ini untuk proyek saya https://htwins.net/scale2 dan pekerjaan lain yang memakai SVG atau Canvas
Jika Anda kesulitan dengan Flexbox, ada alat yang bisa menyederhanakan proses saat membuat layout responsif agar Anda tidak perlu memikirkan banyak properti: https://flexboxcss.com
Luar biasa. Alat seperti ini sangat penting karena membuat kotak ajaib bernama mesin render browser menjadi sesuatu yang bisa dipahami
Kalau kita bisa membuat spesifikasi lengkap yang bisa dibaca mesin untuk rendering HTML dan CSS, seharusnya renderer bisa dihasilkan darinya. Perilaku aneh khusus tiap browser bisa dijadikan ekstensi di atasnya. Akan bagus kalau sesuatu seperti https://github.com/tawesoft/html5spec bisa menjadi bentuk yang dipakai mesin nyata
Ini cukup dekat dengan hal yang belakangan saya pikirkan. Saya sedang bertanya-tanya apakah CSS dan SVG bisa dipakai sebagai lapisan abstraksi di atas library grafis dan UI
Saya baru pertama kali mendengar node-canvas, dan sepertinya itu mengisi bagian menggambarnya. Alat ini tampaknya bisa menangani bagian layout, yang merupakan semua yang saya butuhkan dari library UI
Saya juga penasaran seberapa sulit implementasi CSS-nya. Katanya cukup rumit
Implementasi CSS memang sulit, tetapi hambatan terbesarnya adalah pengetahuannya tidak tersaji dengan jelas
Bagian tersulit adalah layout teks. Menangani glyph dan melakukan iterasi terbalik untuk RTL itu membuat pusing, dan line breaking juga jadi sangat rumit. Lebih sulit lagi karena pengetahuan yang dibutuhkan tidak terkumpul di satu tempat
Setelah menyelesaikan layout blok di awal, selama beberapa tahun saya hanya mengerjakannya beberapa jam per minggu sambil mempelajari detail text shaping dan itemization, apa yang harus dilakukan dan apa yang harus dihindari. Banyak hal saya pelajari dengan membaca source code Pango [1], dan sisanya saya rangkai dari pencarian Google
Selain itu, spesifikasi W3C mencakup hampir semuanya. Standar CSS2 [2] adalah salah satu dokumen terindah yang pernah saya baca. Konsisten secara internal, ringkas, dan merupakan hasil dari bertahun-tahun pemikiran serta trial and error. CSS3 juga hebat, tetapi CSS2 adalah fondasi dari semuanya
[1] https://gitlab.gnome.org/GNOME/pango/
[2] https://www.w3.org/TR/CSS22/
Ini kontribusi besar bagi dunia. Terlihat seperti contoh klasik dari hal yang dipikirkan semua orang dengan “seseorang harus membuat $X”, tetapi tidak ada yang melakukannya
Sebagai orang yang suka memakai CSS untuk layout, akhir-akhir ini saya kebanyakan bergantung pada Flexbox dan Grid. Saya sangat paham kalau itu belum didukung, tetapi saya penasaran apakah ada rencana untuk mendukungnya suatu hari nanti. Kalau ada, bagaimana orang lain bisa membantu?
Benar-benar hebat. Kebanyakan orang mungkin tidak menyadari betapa sulitnya mengubah HTML menjadi PNG secara terprogram
Karena perbedaan antara Node dan browser, atau perbedaan antara HTML dan Canvas, Anda akan menabrak begitu banyak masalah kecil
Terlihat berguna. Sulit membayangkan seberapa banyak pekerjaan yang dibutuhkan untuk memahami CSS lebih dulu lalu membangun mesin layout di atasnya