Layout Model¶
Layout pipeline in practice¶
At runtime, the layout is resolved in this order:
- resolve computed style
- resolve style lengths into numeric node fields
- measure nodes (
measure/measureForLayout) - place nodes (
render) - build paint commands (
appendRenderCommands) - route input using the same used geometry model
That render/input symmetry is important for positioned and clipped nodes.
Display Modes¶
display: block¶
ContainerNode block flow supports mixed block and inline-formatting children:
- block children are stacked vertically
- inline/text children form line boxes and wrap when width is constrained
gapis applied between rows/lines in DSGL terms
display: inline¶
Inline container mode lays children left-to-right with wrapping.
- wrapping happens against the available content width
- line height uses measured child outer height plus resolved line-height constraints
- dedicated tests cover no-overlap behaviour for mixed nested children
display: flex¶
Current flex behaviour is single-line row/column distribution:
- axis from
flex-direction - size distribution with
flex-grow/flex-shrink/flex-basis - main-axis alignment from
justify-content - cross-axis alignment from
align-items - no public
flex-wrapstyle property in the current model
display: grid¶
Current grid behaviour is numeric track-based:
grid-columnssets column countgrid-rowsis optional; auto placement can expand rowsgrid-auto-flowcontrols row-first vs column-first placement- item spans from
grid-column-span/grid-row-span - per-cell alignment uses
justify-items+align-items
This is intentionally narrower than browser CSS grid.
display: none¶
Node is excluded from layout/render traversal and state like hover/active/focus/open is reset for that node.
Overlay stack container (DSL helper)¶
overlay { ... } uses a ContainerNode with stackLayout=true.
- children share the same content area
- child
aligncontrols placement inside that area - this is a DSGL container mode, not a CSS
positionfeature
Example:
overlay({
key = "hud.layer"
style = {
width = 100.percent
height = 100.percent
}
}) {
div({
key = "badge"
style = {
align = StyleAlign.END
margin(8.px)
padding = 4.px
}
}) {
text("Pinned")
}
}
Sizing and Units¶
DSGL resolves style lengths via CssLength with units:
px,rem,em,vw,vh,%
Percent bases are explicit in runtime:
- width-like values resolve against containing block width
- height-like values resolve against containing block height
emresolves against current element computed font sizeremresolves against root computed font size
Constraints:
min-*/max-*clamp measured content sizes- width/height values are clamped to non-negative values
- negative lengths are rejected for width/height/border/gap/font-size-style paths
Positioning Modes¶
static¶
- default mode
- ignores offsets (
left/top/right/bottom) for used geometry - stays in normal flow
z-indexdoes not reorder static siblings
relative¶
- stays in normal flow
- applies visual/input offset after normal slot placement
- precedence rules:
leftoverright,topoverbottom
absolute¶
- removed from normal flow
- containing block: nearest positioned ancestor (
relative/absolute/fixed) or root - offset precedence is the same (
leftoverright,topoverbottom)
fixed¶
- removed from normal flow
- anchored to root viewport, not nearest positioned ancestor
- participates in root ordering (promotion model)
- escapes ancestor overflow clipping, but still clipped to root viewport
sticky¶
- remains in normal flow (slot preserved)
- visual offset activates per axis only when that axis has an inset (
top/bottom,left/right) - inset precedence: top over bottom, left over right
- reference scroll container is nearest scroll-container ancestor per axis (fallback to root)
- movement is clamped by direct parent containing block
Overflow and Scroll behaviour¶
Overflow is axis-based (overflow-x, overflow-y).
visible: no scroll container behaviour on that axishidden: clipped axis, no scrollbarscroll: always scrollbar on that axisauto: scrollbar when content exceeds viewport
Runtime properties covered by tests:
- clipping applies to both paint and pointer input (no click-through outside visible viewport)
- nested clips intersect
- mixed-axis cases (
visible+ non-visible on the other axis) still clip using resolved viewport behaviour - scrollbar gutter reduces effective viewport size when present
Example:
.panel {
width: 260px;
height: 140px;
overflow-x: visible;
overflow-y: auto;
}
Z-order and Stacking¶
DSGL ordering uses one model for paint and hit-testing (hit order is reverse paint order).
Important rules from the current model:
- positioned nodes participate in positioned ordering buckets
- static nodes keep DOM-order behaviour
- positioned child with non-default
z-indexcan act as child-context participant - fixed descendants can be promoted to root ordering while preserving logical parent ownership
This is DSGL stacking behaviour, not full browser stacking-context parity.
Known Limits (Current M4 Scope)¶
- No documented browser-equivalent
flex-wrap,align-content, or advanced grid template syntax. - Grid tracks are numeric and equal-width style in current container algorithm.
- Some CSS-like names exist with DSGL semantics only; do not assume browser parity unless tests/code confirm it.
display/position/overflow behaviour is implementation-grounded and may differ from web engines in edge cases.