Layout model

Layout in the Milda Language uses the propose/choosemodel: the parent proposes available space, the child reports the size it wants, the parent positions it. It's the model SwiftUI, Compose, and Flutter already are - which makes the web, not native, the target that needs translation.

#Propose/choose, in plain language

Every layout negotiation is the same three-step conversation. A container tells each child how much room is on offer; the child answers with the size it wants - its content size, all of it, a share, a fixed amount; the container then places the children. That's the entire model. CSS flexbox can be expressed inpropose/choose, but not the reverse - so the abstract model is the native one, and the web generator translates. Grow/shrink factors, min-width gotchas, and the rest of flexbox's mechanics are realization details the language never exposes.

#Containers

  • stack - the universal container, flowing children along row, column, or layers (the z axis - how overlays stack).
  • grid - 2D tracks, deliberately basic: equal or weighted columns/rows only.
  • flow- wrap when out of space. Not a third primitive: it's a convenience macro for stack + the wrap facet (FlowRow / flex-wrap).

#Container facets

  • gap - spacing between children, token-valued.
  • inset - padding, block/inline or per-edge.
  • distribute - main-axis distribution: start | center | end | between | around | evenly.
  • align - cross-axis alignment: start | center | end | stretch | baseline.
  • wrap - nowrap | wrap | wrap-reverse.

#Child sizing: per-axis intents

A child declares a sizing intent per axis - width and height independently (width fill, height fit is common). This replaces the grow/shrink/basis triple with five words:

  • fit - size to content (the default). Web flex: none; SwiftUI ideal size; Compose wrapContent.
  • fill - take all proposed space. Web flex: 1 (plus the min: 0 the generator knows to add); SwiftUI maxWidth: .infinity; Compose fillMax.
  • weight(n) - a proportional share of the leftover space.
  • fixed(token) - an explicit dimension, token-valued.
  • ratio(w:h) - aspect-locked.

Optional min/max clamps attach per axis on top of any intent.

#Position: escaping the flow

  • flow - in the normal parent-directed flow (the default).
  • overlay - out of flow, into a layers stack; how badges sit on avatars and popovers float.
  • pinned(edge) - stuck to an edge: sticky headers, safe-area pinning. Safe areas are native-first (notch, home indicator, system bars); the web approximates via env(safe-area-inset) in the generator.
  • bleed(edge)- stays in flow but cancels the parent's inset on the named edges, extending the child to the parent's edge (the full-bleed image inside a padded card).

Both pinned and bleed name logical edges (block-start, inline-end…) so layouts survive right-to-left locales; physical edges exist only at the realization layer.

#Conditional layout

A part can carry a default layout plus prop-conditioned overrides - layout when orientation=horizontal { … } - the principled home for a prop-driven structure switch (a data list rendering as a column vs a two-track grid). Facet values that vary by prop or viewport use context aliasing instead (see Facets & tokens).

#What deliberately stays out

The model is intentionally smaller than CSS. Things every platform does differently enough that abstracting them would be a lie are left to per-target realization:

  • Advanced grid tracks - fr, minmax, auto-fit are web-leaning concepts with no faithful native equivalent.
  • Baseline alignment - exists everywhere, but composes differently with multi-line text and mixed sizes on each platform.
  • Scroll-container negotiation - nested-scroll cross-axis sizing diverges between platforms.

Text truncation and wrapping are not in this list - they are style, not layout, and live on the text facet (text.clamp, text.wrap).

Why so small
A layout concept earns its place only if it means the same thing on every target. Everything on this page passes that bar; the residue is honestly labeled as realization work instead of being papered over with a leaky abstraction.

Next, put all four layers to work: Authoring walkthrough.