Centering a Div Tag with Physics, Instead of CSS

Friday, February 07, 2014

Summary: I combined a Javascript CSS parser and a Javascript physics engine to layout DOM elements with physics.

After reading yet another guide to layout with CSS, and yet another flame-war over CSS’s flaws, I just wanted to ditch CSS entirely. Tex has had a box and glue model, that has functioned well, for decades in print, but the tooling looks unusable for rendering webpage layouts requiring dynamic flexing and reflowing. So, why can’t I just connect two DOM nodes with a spring and have it flex as the the document resizes? (And, this is 2014. Where is my flying car?)

Using the real physical laws of motion, that people expect out of real world objects, actually makes some sense when you think of a document as in motion. CSS grids, using frameworks such as Twitter Bootstrap, have different layout configurations for ranges of different window sizes, based on CSS media queries. But, you can also see it as a page squeezing and stretching based on the user’s window size, with the DOM nodes connected by springs, colliding as the window is squeezed and stretching apart as the window is stretched. So, I built a Physics-based Page Layout system (Live demo).

Conceptual Springs
I am, currently, using a modified physics engine, originally built by by jonobr1, but there are numerous other engines to choose from. If I get the urge, I may swap it out for one that does continuous collision detection. This would help layouts squeeze correctly in response to other nodes, but would require a better abstraction around the current physics engine.

All the DOM nodes mentioned in a selector, or a declaration, are lazily assigned a particle group, containing one particle for each side (top, right, bottom, left) of a box. If the node is only mentioned inside a declaration, the particles are fixed in position, relative to the DOM node. This allows nodes to be used as anchors, without taking them out of the normal document flow. If the node is mentioned in a selector, the node is taken out of the document flow (absolute positioning) and given internal springs connecting each edge particle in a diamond pattern (top to right, right to bottom, bottom to left, left to top). This allows the particles, and thus the node, to flex in response to external springs. It would be interesting to conditionally disable those internal springs to provide partially-rigid boxes. But, that is not currently in the code base.

Originally, I kept the physics animation, of the springs flexing, as the system sought equilibrium. This behavior was fun to watch, but it resulted in terrible performance for document layout. So, now, it runs a fixed number of steps in time (500) without updating the DOM, and repeating as necessary to reach equilibrium. It might be nice to be able to conditionally re-enable the animation, as a way to assist debugging complex layouts, but that is not yet a priority.

After building this system, I think I now have a better understanding of the complexities around document layout. The current implementation is not much more than a proof-of-concept. To make it usable would require adding rigid connections, one-dimensional springs, minimum and maximum spring lengths, layers, cross-layer connections, shorthand declaration syntax, better performance, and more. So, for right now, it is just a neat proof-of-concept.