Why Not Flexbox?

Summary: The concepts in flexbox can be hard to learn and behave surprisingly. Subform’s layout engine has fewer concepts, applied uniformly.

Why doesn’t Subform use flexbox? When we first launched on Kickstarter, we did! However, in working with our backers, we quickly realized that flexbox was too difficult to learn.

Flexbox introduces new concepts (flex, justify-content, align-items, etc.) on top of existing CSS concepts (margins, padding, absolute positioning, etc.), all of which interact with in surprising and literally invisible ways. These concepts were completely new to designers coming from Photoshop or Sketch, and proved to be a huge barrier to actually exploring design ideas.

So we decided to implement our own layout engine, one that specifically supports the visual design process.

The Subform layout engine

Compared to Flexbox, the Subform layout engine has fewer concepts, applied uniformly.

Here’s the tl;dr:

  • All elements have a horizontal and vertical axis, each of which consists of space before, size, and space after.

  • Elements either control their own position (“self-directed”, akin to CSS absolute positioning) or are positioned by their parent (parent-directed).

  • Parents can position their parent-directed children in a vertical stack, horizontal stack, or grid.

  • The same units—pixels, percentages (of the parent size), and stretch (akin to flex, proportionally dividing up available space)—are used everywhere, with minimum and maximum constraints as part of the unit.

We made some specific design choices to keep the layout engine understandable, based on what we saw people struggling with in flexbox, as well as what we’d always wanted from CSS:

Default between. We added a “default between” setting, so you never have to write gross things like: .foo {margin-bottom: 20px;}, .foo:last-child {margin-bottom: 0;}:

Uniform stretch units. By allowing stretch units to be used everywhere (instead of just on an element’s size in the flex direction), we eliminate the flexbox trivia of justify-content, align-items, etc.

These values are just special cases of more general spacing rules. E.g., justify-content: space-between can be implemented in a Subform stack by setting the default space between elements to be 1s. We have these special cases as presets, but they are shortcuts rather than wholly new concepts — all they do is set the appropriate values:

The quick align preset buttons just fill in the appropriate values on the main axis automatically.

This approach is far more expressive than Flexbox, since it’s straightforward to express something like “distribute extra space between all elements, except between these two, where it should be 20px”.

Overriding default space between elements
20px between middle two elements, with extra space distributed evenly everywhere else.

The layout engine is symmetric. A stack child’s cross axis and both axes of a self-directed child act the same as a main axis with only one element. E.g., an element can be centered in any of these axes by setting space before = space after = 1s—no need to think about justify-content: center, align-items: center, or margin: 0 auto.

A single stack, with different settings on the cross axis for each element.
A single stack, with different settings on the cross axis for each element.

Fewer gotchas. No flex shrink, can use percentages in cross axis, no invisible interaction of margins/padding/borders, no margin collapsing, etc.

Don’t take my word for it!

The best way to learn the layout system is to just play around with it: try Subform here. Or, if you’d rather play with it in code than in a visual cool, check out the examples in our Github repo.

Further reading

If you’re interested in the design thinking and process that led us to our layout engine, see my 2017 Deconstruct talk.

In particular, check out Daniel Jackson’s conceptual design framework, which was immensely helpful in defining our problem and exploring possible solutions.

If you are thinking about writing a layout engine, or have any questions about Subform’s, feel free to write me (kevin@generalreactives.com)!