This topic overviews our thinking on layout engines.
It should convey at a high level our intent and vision, and explain why we are pursuing (or not pursuing) specific features in the layout engine.
I'll keep this topic up to date with our thinking.
Goals / tradeoffs
Digital products must render across a wide variety of device sizes.
But designing for multiple sizes in print-lineage graphic design tools is a tedious, error prone, manual process.
As such, an automated layout engine is a core differentiating feature of Subform.
The goals of the layout engine are:
Better responsive designs: The engine should allow designers to quickly explore the consequences of design decisions across different sizes. It should reduce "iteration time" caused by, e.g., handing off a preliminary design to devs, waiting for a prototype, and seeing responsive consequences days or weeks later.
Reduced time pixel-pushing: The engine should enable designers to build necessary comps faster than print-lineage tools. Time spent pushing pixels should be reduced in favor of high-value design activities (clarifying requirements, user testing, etc.).
Streamlined communication: The engine should unambiguously capture responsive design intent, and convey that intent to developers and other stakeholders. Subform's layout engine should be able to reduce designer/developer back-and-forth re: "what is supposed to happen at size X?" (Imagine if design tools only worked in black and white, and all color decisions needed to be communicated in redlines or over Slack.)
These goals form a framework by which a layout engine can be evaluated.
We should also evaluate possible solutions with an eye towards their downsides:
Unfamiliar: Some designers have never used automatic layout systems and may have a hard time learning one without extensive tutorials/documentation. Can the engine be learned in a reasonable amount of time/effort?
Different: Some designers are used to other layout systems (e.g., HTML+CSS). Shared terminology may interfere with understanding if the semantics are different. (E.g., "padding" or "borders" may behave differently in Subform than in CSS). Inherent capability differences may also lead to implementation troubles (Can you design a layout in Subform that cannot be built easily on web or iOS? Should you be able to?)
Limited designs: Tools influence work in a Sapir Whorf sort of way. Will Subform push everyone into designing simple rectangular things? (Or is this already the case, regardless of Subform, given the Cartesian bias of typical implementation media and, for that matter, written human languages?)
With these goals and downsides in mind, lets look at a few principles to guide our thinking.
Designers should be able to fully internalize the layout semantics
It's crucial that we understand our tools so that we can work quickly and confidently.
Part of that responsibility is on us to put in a few hours of deliberate study and practice.
But the rest falls on the tool designer (yours truly) to build something comprehensible.
My goal is to minimize "I didn't know you could do that" and "wait, what is going on here?"
Subform's layout semantics should be similar to the target medium
The design intent captured by Subform should be translatable by developers into the final implementation media (web, iOS, Android, etc.)
This is why, for example, the layout engine is built on hierarchical relationships along the horizontal and vertical directions rather than, say, polar coordinates or parametric differential equations --- because the web, iOS, and Android all use hierarchical, horizontal/vertical layout systems.
However, Subform will not have a 1:1 correspondence to any other layout system --- it is not an IDE for HTML/CSS, iOS, or Android.
As such, the limitations of some media shouldn't restrict Subform's expressiveness.
There is value in allowing designers to express "unbuildable" ideas.
If Subform captures that intent clearly, developers are in a better position to consider implementing it.
(Of course, if they can't, they should communicate with their designers: "Please stop with the multiple borders --- we can't do that in CSS.")
Features should be required to design and communicate a product idea
Each feature of Subform should be justified by the need to design/communicate a particular product idea.
E.g., percentage values are justified because designers need a mechanism to design/communicate the idea that a child's size is proportional to their parent's.
Conversely, if a feature does not meet a specific need --- or if that need can be met by other features --- then it should not be included in Subform.
The need to hide/show specific elements at different artboard sizes, for example, does not imply that Subform needs "breakpoints", as one can design and communicate this using multiple artboards containing shared components.
Full fidelity is a trap
There are some matters of fidelity --- pixel-perfect positioning, millisecond animation timing, full network/data behavior, etc. --- which cannot be captured by a design tool without effectively becoming an IDE and transforming the designer into a developer.
Designers must acknowledge this fact and understand the level of fidelity beyond which they must work closely with developers on actual prototypes in the target medium.
All design tools exist to serve the final product.
The artifacts created by design tools shouldn't be confused with (or be an unnecessary facsimile of) the product.
Forgetting this is akin to working obsessively on slides at the expense of the presentation.
As such, Subform will not attempt to reach "full fidelity" for any medium.
Any tool that promises such fidelity (either explicitly or implicitly via certain features) encourages designers to stay within the familiar (their tool) to the detriment of their responsibility to maintain design integrity across the actual production workflow.
Can "layout" be fully separated from "styles"?
If they are fully separate, then semantics are smaller, which enables both better understanding as well as performance benefits (e.g., repainting styles can be done faster if it is known that styles cannot affect layout).
However, there are arguments to let some styles affect layout.
E.g., borders: https://talk.subformapp.com/t/option-to-set-border-positioning/551
What other conceivable style properties could/should affect layout?
What are the mechanisms for reusing / composing "layout" properties?
Should layout properties be sharable?
If so, should that reuse occur via existing mechanisms (e.g., classes) or a new one (variables?)?
Given that an element can have multiple classes, how should layout properties combine?
Should it be "last class wins" (as it is now, for style properties), or should they merge piecewise, allowing, say, a height defined on one class and width defined on another?
What element size constraints are necessary?
The layout engine will likely support min/max width and height, which override the general width/height (e.g., "max-width" overrides "width").
Are there other size constraints that we should consider.
Say, "aspect ratio"?
What are the necessary "casual directions" of layout?
I feel that Subform needs three:
- top-down (child is 50% as wide as the parent)
- bottom-up (parent is as wide as the sum of all of its children)
- sibling (elements expand or position themselves to share space within their parent)
Having three directions complicates the semantics, but I feel that this complexity is inherent in responsive design --- removing one would unreasonably limit the expressiveness of the engine.
How do we avoid undefined configurations?
With three casual directions, it's possible to run into undefined situations.
For example, what happens when a child with 50% width (top-down causality) is underneath a parent with an "auto" width (bottom-up causality).
Together these constraints don't make sense, they're "undefined".
Note that ill-defined constraints can occur even within an element.
For example, "width" and "aspect ratio" fully constrain "height", so an element that has all three values set is overdetermined and its layout undefined.
Should we allow people to get into such situations?
Or is it possible to keep them out of trouble?
Possible solution: UI control validation
Can we prevent undefined configurations by having the UI reject input values?
E.g., a parent's width input box would refuse an "auto" value when one of the children has a percentage width/height.
I don't think this solution will work, for two reasons:
we may want to define layout to via composition (of components, classes, etc.), and so there may not always be a single UI input that can reject invalid inputs --- we'd also need UI to reject the addition or removal of classes, check interpolated variable values (if we support variables), etc.
in addition to property setting, topological changes can also lead to undefined situations, so we'd also need to design a "reject" UI for operations like tree dragging (to prevent an element w/ 50% width from being dragged into an auto-width parent), for placing new component instances, hotkeys that affect element topology, etc.
Said another way, Subform UI offers many expressive and powerful operations, and ensuring that all of them can "reject" undefined layouts would complicate both the technical implementation as well as the conceptual overhead when using them.
Furthermore, even if we could reliably prevent undefined layouts via UI checks, we still need to explain to the user why they cannot input a value or drag an element, as such operations are usually allowed.
Possible solution: limit constraints to an orthogonal set (just width and height, or just width and aspect ratio).
This may work for overdetermined constraints for a single element, but it's not obvious that it can solve issues within relationships between elements.
Even if it could, limiting the constraint set limits Subform's ability to capture design intent.
If the designer wants to sometimes constrain an "aspect ratio" and other times constrain "height", it is better to let them use the constraint that best captures their intent.
Possible solution: prioritize constraints relative to each other.
Priorities are clear in some situations (max-width should take precedence over width), but not all (When width, height, and aspect ratio conflict, which one is ignored?)
If there's no "obvious" priority order, then any order will be arbitrary, and requiring that designers memorize an arbitrary order would be hostile.
There's an analog here with arithmetic: The "order of operations" is a band-aid on the shortcomings of infix notation --- a better solution is fixed-arity prefix (Polish) or parenthesized notation that eliminates ambiguity without imposing a cognitive tax.
Possible solution: allow, but draw attention to undefined layouts
If Subform cannot prevent undefined situations, then it should ensure that users notice, understand, and resolve them.
For example, A warning icon on undefined elements in the tree could be coupled with a popover that explains the situation: "Box 32 has a percentage width, but its parent has an auto width --- set an explicit width on the parent or non-percentage width on Box 32 to resolve."
How should Subform tolerate undefined situations?
Should the undefined elements be rendered somehow, or should they be hidden?
Should artboards containing undefined layouts be drawn or grayed-out?
If Subform is too lenient, it risks sending trouble downstream (e.g., developers are given an exported style guide w/ undefined layouts).
But if Subform is too strict (forcing people to complete a "resolve all ambiguity" 110-step wizard, refusing to save files with undefined layouts, etc), it will aggravate designers and they will curse my name.
Analogous situations: Dynamically checked vs. statically checked programming language type systems; using text editors on code rather than AST-aware, every-transformation-is-valid editors
What about breakpoints?
Breakpoints (CSS rules that apply only under certain viewport conditions) are a CSS feature.
But what is the need that breakpoints address?
To conserve bandwidth by allowing the same HTML markup to encode several different visual designs? If so, that's a platform implementation need, not a design one.
To allow a team to assert a consistent identity across something that varies greatly between manifestations? E.g., that the app "homescreen" on a smart watch is the same "homescreen" on a large tablet. If so, what does this consistent identity accomplish? When do the designs diverge enough to be considered two separate entities, "the watch homescreen" and "the tablet homescreen"?
To allow anonymous or "local" reuse? E.g., for some elements that only appear on the "homescreen", is it preferrable to reuse them across watch and tablet by keeping them under "the same" artboard rather than reifying those elements as reusable components?
Regardless of the underlying need, if breakpoints are implemented like they are in CSS, we should consider the implications:
Breakpoints conceal intent: Artboards cannot be taken "at face value", since any change in size could yield a radically different apperance.
Communication w/ developers: Are developers expected to understand the semantics of Subform's breakpoint system so they can translate it into the final medium? Or would it be easier for developers if Subform "expanded" an artboard across all of the different breakpoints, showing concrete examples for each? If the latter, what is the advantage of breakpoints vs. letting the designer specify the examples as distinct artboards?
My take is that CSS-like breakpoints have more tradeoffs then benefits.
They remind me of implementation inheritance in OO-languages: great for simple examples, shitshow in practice.
Breakpoints would complicate both Subform's UI and the underlying semantics.
This complication would bleed into designer/developer communications, without adding capabilities beyond Subform's existing mechanisms for reuse (style classes, components, etc.)
I'm curious to hear about needs that are better solved by breakpoints than by, say, duplicating and customizing individual artboards.