24 ms·
Show HN: Dropflow, a CSS layout engine for node or <canvas>
For the last 5 years I've been working on a layout engine that targets CSS2 and some more modern properties.
Live demo: https://chearon.github.io/dropflow/ https://chearon.github.io/dropflow/
It matches browsers in all cases I can find where they agree, and it's fast. It supports `position`, `inline-block`, `z-index`, and complex properties like `float` and `vertical-align`. It doesn't support high-level layout like flexbox or grid yet, but you can get intrinsics to easily divide space yourself and paint multiple layout trees. It has a great text layout implementation, and supporting non-Latin scripts is a top priority.
I've wanted this to exist as far back as 2013, and the desire kept coming up: for a way to get detailed intrinsics, for high quality rich text layout to canvas and SVG, and for server-side rich text. We currently use it in CellEngine for our new canvas-based spreadsheet library to layout text in hundreds of thousands of cells, and will be using it soon to render PDFs with thousands of pages in a few seconds.
- andrewmcwatters 3y agoThe layout algorithm for CSS 2.1 is not well defined. How did you interpret the algorithm? I may be missing it from a quick glance, but it’s not obvious from your code.
- big_paps 3y agoWell this looks like something useful. Can't imaging how much work is needed to first understand css and then to build a layout engine around it.
- troupo 3y agoThere's also Facebook's Yoga: https://github.com/facebook/yoga https://github.com/facebook/yoga
- Rohansi 3y agoYoga is great but only really supports flexbox. For most cases that can be enough but inline content (as shown in the Dropflow demo) is difficult with only flexbox layouts available.
- lovegrenoble 3y agoFor anyone struggling with flexbox, you can use this tool to streamline the process of creating responsive layouts, removing the need to focus on multiple properties: https://flexboxcss.com https://flexboxcss.com
- airstrike 3y agothank you for this!
- undershirt 3y agothank you
- techscruggs 3y agoThis is the first site I've run in to that uses neumorphic design. Love the aesthetic -- just never seen in it the wild before.
- fareesh 3y agoCRED had it in their app for a while, their library is open source https://github.com/CRED-CLUB/synth-android https://github.com/CRED-CLUB/synth-android
- bobajeff 3y agoThis sounds close to what I've been wondering about lately. I was wondering if css and svg could be used as abstraction over graphics and UI libraries. This is my first time hearing of node-canvas looks like it fills the drawing part of the solution. While this may do the layout portion (which is all I need from a UI library). I wonder how hard it was to implement css. I've heard it can be pretty complex.
- chearon 3y ago> wondering if css and svg could be used as abstraction over graphics and UI libraries There's another project called Sciter that uses CSS to target native graphics libraries: https://sciter.com https://sciter.com > I wonder how hard it was to implement css. I've heard it can be pretty complex. It was hard, but the biggest barrier is the obscurity of the knowledge. Text layout is the hardest, because working with glyphs and iterating them in reverse for RTL is brain-breaking. And line wrapping gets really complicated. It's also the most obscure because nobody has written down everything you need to know in one place. After I finished block layout early on, I had to stop for a couple of years (only working a few hours a week though) and learn all of the ins, outs, dos, and don'ts around shaping and itemizing text. A lot of that I learned by reading Pango's [1] source code, and a lot I pieced together from Google searches. But other than that, the W3C specifications cover almost everything. The CSS2 standard [2] is one of the most beautiful things I've ever read. It's internally consistent, concise, and obviously the result of years of deliberation, trial and error. (CSS3 is great, but CSS2 is the bedrock for everything). [1] https://gitlab.gnome.org/GNOME/pango/ https://gitlab.gnome.org/GNOME/pango/ [2] https://www.w3.org/TR/CSS22/ https://www.w3.org/TR/CSS22/
- jsunderland323 3y agoI’m curious if you’ve implemented a rich text editor with this. I think Google Docs uses canvas. I hate the browser APIs for rich text and wonder if this could be more a viable candidate than using contenteditable for future projects
- chearon 3y ago
- ape4 3y agoIts too bad browsers don't support this. // Do CSS layout in the regular document const doc = new CssLayout(document); doc.layout(...); // Do CSS layout on your own canvas const mycanvas = new CssLayout(document.getElementById('mycanvas')); mycanvas.layout(...);
- deleted 3y ago[deleted]
- Sesse__ 3y agoThe security implications would be interesting, unless you tainted the canvas (which makes it instantly less useful).
- awesomekling 3y agoSuper cool! Nice job, chearon :)
- chearon 3y agoWow thanks! Seeing Ladybird progress kept me motivated!
- 1oooqooq 3y agowhy not ship a desktop application at this point with support for a special schema? i can understand the abuse for server side rendering, but at this poit you pretty much have a bad browser engine. running inside a 2d hack in a browser engine. sigh.
- Bjartr 3y agoWhy re-invent the wheel with a special schema when CSS2 is a solid standard and widely understood? Is there no room in the world for rendering implementations between nothing at all and full-spec web browser with all the bells and whistles?
- 1oooqooq 3y agoI'm actually advocating against re-inventing the wheel (insider another wheel, no less) you can still follow css spec if you want. just get a better environment than a canvas.
- robbiejs 3y agoThis is a big achievement, congrats! A lot of time must have been put into this I am sure. And you are also making a spreadsheet product AND a PDF (preview?) product? How do you combine it?
- chearon 3y agoWith this and node-canvas, you have everything you need to generate PDFs. I'll add an example to the examples/ directory for that. The spreadsheet library and PDFs I talked about in OP were examples of how we use this in our application, but are closed-source.
- XCSme 3y agoCould I use this together with Pixi.JS ?
- jasonjmcghee 3y agoAre you planning to add support for the missing standard tags like img and table (both very useful for pdf rendering)?
- chearon 3y agoYes, definitely. In the meantime, you can still use this to get the intrinsic sizes of cells to create rows and columns, and you can use an empty inline-block and paint the image where it's laid out. I'll put something in the examples/ directory soon.
- AndriyKunitsyn 3y agoI wonder if there’s something opposite — an abstraction for the Web to provide some layout rules that are more sane than CSS.
- usrusr 3y agoFeels a bit like history repeating (well, rhyming) with the time back when Java was "the language of web applets" and then Sun created the Hotjava browser and confusion reached the point where minds simply blank out. Few technological novelties have been forgotten more decidedly than Hotjava. Despite marking an intersection of two technological fields (browsers and the JVM) that have shown extreme staying power through the last quarter century. But the idea of using html for text styling has stuck, Swing UI do text styling with html (and rudimentary css!) to this day. Html would not be a lingua franca if its use was limited to the equivalent of native speakers (browsers).
- eigenvalue 3y agoI worry that this sort of technology is going to lead to webapps that aren't really what we've grown to think of as "the web" but which will instead be closer to a VNC window where you just see pixels and can't interact with anything or see how stuff works in devtools.
- jdiff 3y agoAccessibility features would need to be added to canvases before that reality's possible, so we've got a ways to go yet before we need to worry too much about that.
- guhcampos 3y agoIs it bad though? This is of course a rethoric question, I don't know myself if I think it's good or bad, yet. What I'm thinking is: there's been soo much discussion around "we have corrupted the Web", "Web standards were never made to build apps on", etc. with sometimes good and sometimes really bad arguments. If we can build viewports in canvas that behave more like just a desktop environment where apps can be built, maybe that could be good? It could mean a split between the informational web and the "apps on the browser" paradigm, and in a ideal scenario this could make things simpler and more organized for everyone? Or it could just mean more work, more standards, more rupture and more siloing. Honestly don't know.
- littlestymaar 3y ago
- lewisjoe 3y agoThis is an amazing piece of work. Thanks for making this open-source. The default way of generating beautiful PDFs in the backend these days is, running a headless browser and using browser APIs to turn HTML/CSS into PDFs. And apparently, it's a bit costly running instances of browser in the server and scale it properly for huge workloads. This is literally a game changer. Now it's possible to design PDFs using HTML/css and generate them without the browser overhead!
- bawolff 3y agoAs an aside its amazing how far the web has come, where the best way to make pretty pdf documents is to literally run a web browser on the server. This would have been so unthinkable back in the 90s & 2000s
- vanderZwan 3y agoI'm fairly certain that using a headless browser on the server is mainly about sandboxing all the security concerns that PDFs have, not aesthetics, but yes.
- bawolff 3y agoSecurity of the pdf format is not relavent here. The headless browser outputs a PDF. It is not taking a user controlled pdf as input.
- vanderZwan 3y agoAh of course, my apologies. I misread the original post.
- menacingly 3y agoit's actually because layout-via-code for arbitrary documents is a humblingly complex problem, so leveraging existing layout engines is preferred. This impressive effort looks far better than what I'd achieve, but when this approach has been tried before, it is eventually discovered that few organizations have the resources to maintain a rendering engine long-term.
- pietroppeter 3y agoI would be very much interested in articles on how to write a CSS layout engine from scratch
- bawolff 3y agoNot exactly what you are looking for, but if you haven't seen it, firefox has some really interesting blog posts about how their css engine works, e.g. https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-engine-quantum-css-aka-stylo/ https://hacks.mozilla.org/2017/08/inside-a-super-fast-css-en... that i personally found really enlightening
- pietroppeter 3y agoThis is great, thanks for sharing!
- nicoburns 3y agoI've been considering writing such a thing. Although I've only implemented Flexbox and CSS Grid so far. The CSS specifications for those algorithms are worth reading if you're interested in this kind of thing. They're a challenging read, but not an impossible one.
- pietroppeter 3y agoFair advice, thanks
- joelanman 3y agothis wouldn't be accessible would it? For example to screen readers, so just wondering what the use case is over accessible tech
- mattmar96 3y agoOh wonderful. Thank you! I was looking for something like this for my project https://htwins.net/scale2 https://htwins.net/scale2 and others which use svg or canvas
- webprofusion 3y agoNeat project!
- internetter 3y agoWoah, I'd love a writeup on how you made this
- eob 3y agoThis is incredible --- @chearon thank you for open sourcing this! I think most folks probably don't realize how difficult it is to go from HTML -> PNG programmatically. You get hit with a thousand papercuts related to either Node<>Browser differences or HTML<>Canvas differences.
- niutech 3y agoHave you tried dom-to-image (https://github.com/tsayen/dom-to-image https://github.com/tsayen/dom-to-image) or html2canvas?
- shepherdjerred 3y agoI've used satori [0] on the backend with TypeScript/Deno to render React JSX + tailwind CSS as an SVG (which is then rendered to a PNG). Of course you could use another flavor of JSX (or even plain HTML) or omit tailwind, but it's really cool that you can use the same stack as a typical frontend and render it as an image. Satori is meant for rendering Open Graph images (e.g. the little images that come up when you post a link on Twitter/Slack/Facebook), but I found that it works well for rendering arbitrary images. Satori has no native dependencies, so it kinda "just works" on the backend. It supports a subset of modern CSS, including flexbox. My use case is posting match reports for League of Legends into a Discord text channel, e.g. person X just played a match, here are their stats. It's quite nice because there are almost zero server-side native dependencies (the one exception is the library to convert svg -> png requires some native libraries). Here's what a match report looks like: [1] Here's an example of what the JSX looks like: [2] I also built a small project [3] that renders the JSX in a browser to make developing the images just as easy as developing a normal website. If others are interested in this, I would by happy to write a blog post about the process. [0]: https://github.com/vercel/satori https://github.com/vercel/satori [1]: https://github.com/shepherdjerred/glitter/blob/main/assets/postmatch.png https://github.com/shepherdjerred/glitter/blob/main/assets/p... [2]: https://github.com/shepherdjerred/glitter/blob/main/packages/backend/src/league/image/html/report.tsx https://github.com/shepherdjerred/glitter/blob/main/packages... [3]: https://github.com/shepherdjerred/glitter/tree/main/packages/preview https://github.com/shepherdjerred/glitter/tree/main/packages...
- deleted 3y ago[deleted]
- LinguaBrowse 3y agoThanks for sharing this. I’ll be checking its potential as a base element for something like NativeScript or Node.js. Text is about the most complex UI element that a UI framework offers, and if you’ve got Flow Layout working, that’s very encouraging! Will be interested how far along things like gestures (particularly text highlighting) and IME integration are. In any case, kudos for opensourcing this!
- mwit2023 3y agowill give it a try for opengraph images, thank you!
- Vt71fcAqt7 3y agoThis looks great. As you mention PDF, do you plan to support the various @page properties that add pagination? For example like pagedjs[0] but native? Major usecases are books and invoices [0] https://pagedjs.org/about/ https://pagedjs.org/about/
- chearon 3y agoYes, this is pretty high up on my list. I've already done a little bit of work on pagination/fragmentation, but it will take me some time.
- wg0 3y agoThis is pure craftsmanship. A heavy undertaking TBH, kind of reinventing browser flow on top of browser primitives.
- rrgok 3y agoPerhaps I'm missing something, but why can't we render HTML directly onto the canvas in the browser? The parser is there, the layout engine is already implemented, and the calculation of box layout is already done. It should be doable without going in circles. If only the browser had a flag indicating which "surface" to render on. I was looking at Glide Grid the other day, and it renders so fast, even with 1 million rows; it's somehow responsive. There should be an easier way to render HTML to canvas without resorting to low-level primitives. Why is canvas faster than the "regular" DOM renderer?
- eeiaeaa 3y agoGlide grid renders to canvas also.
- rrgok 3y agoPerhaps I worded it wrong: I meant to bring Glide Grid as an example how fast we can render millions of items to canvas.
- spankalee 3y agoIt doesn't actually render millions of items though. It renders the visible viewport, something you can also do with pretty standard DOM virtualization techniques.
- duckfruit 3y agoBut if all you want to do is render HTML then why use <canvas>? I'm only speculating, but it doesn't seem surprising that regular DOM rendering logic - which has to handle approximately a bazillion different rules and special cases - is slower than a custom renderer written for a specific subset of HTML.
- hwillis 3y agoIf you want to do any kind of text or diegetic UI in webgl, you are begging for DOM rendering to canvas (which is then sent to a texture)
- lloydatkinson 3y agoIt doesn’t support flex box? I really can’t tell what the purpose of this library is then.
- recursive 3y agoThe purpose is for documents that don't use flexbox.
- lloydatkinson 3y agoAlright so that’s about as useful as saying “I built a word processor without left, right, middle align or tables”.
- recursive 3y agoMaybe? I mean those exist. Not sure what you're getting at. If you don't like it don't use it.
- benatkin 3y agoI agree, I think there has to be something compilable to WebAssembly. A web search shows something that's written in Rust: https://github.com/DioxusLabs/taffy?tab=readme-ov-file#taffy https://github.com/DioxusLabs/taffy?tab=readme-ov-file#taffy
- deleted 3y ago[deleted]
- dohello1 3y ago[flagged]
- peer2pay 3y agoI have nostalgia for a lot of things in webdev, hacking together floating layouts is not one of them. /s But congrats on the work! I can definitely see this being useful for text formatting and layouting PDFs. Neat!
- dohello1 3y ago[flagged]
- justhw 3y agoThis looks great. I've been using html2canvas but it doesn't support the 'filter' property yet. This will be an awesome alternative.
- moron4hire 3y agoThis sounds great. In a past role, my job was to develop an immersive, online learning platform. We used Oculus Quest 2s to do foreign language training for DoD personnel. WebXR, Three.js, etc, because I had had enough Unity3D for one lifetime and we didn't want to submit to app store reviews. We had a fleet of our own devices, so it was fine. One of the biggest challenges with the project was creating a workflow for didactic content. By myself. I had an employee who I supervised working for me, but most of the work was of such high technical level that it was way over their head and we couldn't afford to hire anyone else. I eventually landed on having our actual language instructors use PowerPoint to create PDFs, use a bespoke editor I created to upload the PDF into a content database and position them in the training environments, and then used PDFJS to render them to canvas elements to then texture on a 3D quad. Something like this would have made it possible for me to avoid having people go out of band into PowerPoint to make those materials. The PowerPoint route did dramatically improve our workflow speed over a previous attempt to get people to author images in Photoshop. But if I could have built the "sign" editor into the app, it would have improved it even more by eliminating the "guess what will look good in the environment, export to PDF, upload to the database (oh, BTW, not a lot of people know how to keep files well organized), then find out how it really looks" cycle. Oh well. We didn't have a business development team or market department that knew anything about selling products instead of services, so I guess the point is moot anyway.
- vthommeret 3y agoDoes anyone have a similar solution for drawing graphs / charts in a Node environment without a browser dependency? Last time I explored this I couldn't find any good solutions.
- tills13 3y agoYou could use https://github.com/vercel/satori https://github.com/vercel/satori which supports Node 16+.
- vthommeret 3y agoThanks. I've tried using Satori but I'm curious if you've used it to draw graphs specifically. E.g. Satori expects JSX / doesn't support HTML strings from d3-node with dangerouslySetInnerHTML.
- AaronFriel 3y agoUnfortunately not for nested inline nodes, like spans of text with formatting. For a lot of uses, that will be OK - but for rendering say, markdown text, Satori won't work. The upstream layout engine handles flexbox layout, and it's unclear if Facebook needs inline layout or if Vercel would pick it up and close the gap: https://github.com/facebook/yoga https://github.com/facebook/yoga Then again, for the main purpose Satori is advertised for - generating URL unfurl previews - Dropflow looks like it might be the answer.
- AaronFriel 3y agoDoes this depend on a browser? It looks like it doesn't - which is pretty impressive!
- pier25 3y agoDo you need to create images? It's trivial to create svg in the server. It's like rendering html.
- foreigner 3y agoWhat is the API to produce SVG?
- webprofusion 3y agoBrilliant! It's super important that stuff like this exists, demystifying the magic boxes of browser rendering engines. It would be great if we could create a full machine readable spec for html and CSS rendering, so that renderers can be generated. Browser quirks could then be extensions to that. Like https://github.com/tawesoft/html5spec https://github.com/tawesoft/html5spec but used for real engines.
- internetter 3y agoSomehow this reminded me that Ladybird is a browser being written by scratch and this has been really useful to actually make sure that there are no bugs in the spec.
- fgutmann 3y agoGreat achievement, congratulations! This reminds me of flying saucer, a CSS render written in pure Java. Successfully used it in multiple projects for rendering PDFs in the past. It has some great features to handle paged media. For example, it can repeat table headers on a new page, if there is a page-break within the table. Unfortunately, it seems that it doesn't get much active development anymore. https://github.com/flyingsaucerproject/flyingsaucer https://github.com/flyingsaucerproject/flyingsaucer
- atoav 3y agoTruly a service to the world. I think this is a classic example of "somebody ought to do $X" and nobody ever having done it. Thanks. As someone who loves working with CSS for layout, I am mostly relying on Flexbox and Grids these days — it is totally understandable that these are not supported yet — but do you plan to do so at some point? If so, how can others help?
- niutech 3y agoFor flexbox check out Facebook Yoga (https://github.com/facebook/yoga https://github.com/facebook/yoga) or Webkit.js (https://github.com/trevorlinton/webkit.js https://github.com/trevorlinton/webkit.js).
- crankdude 3y ago[flagged]
- YorickPeterse 3y agoHow suitable would this be for a text editor of sorts, and what latency would one expect? Using the demo it's difficult to gauge the latency by just eyeballing it.
- niutech 3y agoThere is also HTML/CSS layout engine litehtml (https://github.com/litehtml/litehtml https://github.com/litehtml/litehtml) and even a full-blown web engine in JS: WebKit.js (https://github.com/trevorlinton/webkit.js https://github.com/trevorlinton/webkit.js)
- andrewmcwatters 3y ago> webkit.js What in the world?
- dormento 3y agoEmscripten sausage. Or a kind of a web turducken.
- andrewmcwatters 3y agoYeah, I'm just impressed someone did it. Emscripten doesn't come free, you have to do a bit of work yourself.