your payout of $12,400.00 is on the way.
layout: app shells, padding lives only on leaves
Six shell patterns, each shown wrong (the container pads) and right (only leaf nodes pad). Containers arrange with flex, grid and gap. Press i for the inspector to see which node owns padding: amber is a leaf pad, red is a negative-margin hack.
holy grail
header, nav, main, aside and footer in one grid.
wrong · the frame pads
body copy
padding on the frame fights every full-bleed element: the title bar needs a negative margin to reach the edges.
right · the leaves pad
body copy
each region pads its own content. a full-bleed title bar is just a child with no padding.
the grid container never pads. every region owns its padding, so any region can go edge to edge without undoing someone else's spacing.
<header class="lay-topbar"> <!-- container: arrange only --><span class="lay-brand">acme</span> <!-- leaf: pads itself --><Button size="sm">new</Button> <!-- leaf: the Button pads itself --></header>.lay-topbar { display:flex; align-items:center;justify-content:space-between;border-bottom:1px solid var(--rule); } /* no padding here */.lay-brand { padding:0.75rem; }
collapsible sidebar and icon rail
collapse is one attribute on the rail; icons stay centered because the items, not the rail, own the width.
wrong · the rail pads
content
when the width flips, labels snap and icons drift: the rail's padding is part of every width calculation.
right · the items pad
content
collapse changes one width. items keep their own padding, so the icon column never moves.
collapse = a class or attribute flip. if padding lives on the container, one flip re-flows everything inside it.
<nav class="lay-rail" data-rail> <!-- container --><a class="lay-railitem" data-pad>…</a> <!-- leaf --></nav>.lay-rail { width:11rem; display:flex;flex-direction:column; gap:0.25rem; }.lay-rail[data-collapsed] { width:3.5rem; } /* the whole collapse */.lay-rail[data-collapsed] .lay-raillabel { display:none; }.lay-railitem { height:2.5rem; align-items:center;gap:0.75rem; padding-inline:1.25rem; }
master-detail
a scrolling list beside a reading pane. separators are the list's job, not each item's.
wrong · the list pads
every item drags its own border around with negative margins, and the sticky header has to out-pad the pane.
right · the items pad
your payout of $12,400.00 is on the way.
divide-y draws all separators once. the sticky header needs no counter-margins.
repeating separators belong to the list (divide-y), never to the item. an item that draws its own border will fight scroll, hover and selection states.
<div class="lay-maillist"> <!-- container: draws dividers --><a class="lay-mailitem"><b class="lay-mailfrom">stripe</b> <!-- leaf --><span class="lay-mailsubj">payout sent</span></a></div>.lay-maillist > * + * { border-top:1px solid var(--rule); }.lay-mailfrom { padding:0.75rem 1rem 0; }.lay-mailsubj { padding:0 1rem 0.75rem; }
three-pane
channel list, thread, and context pane.
wrong · every pane pads
today: shipping the resize handle.
each pane pads, so every edge element (heads, composer) needs a negative-margin escape hatch.
right · the leaves pad
today: shipping the resize handle.
heads sit flush against their pane edges because the pane pads nothing.
<section class="lay-thread"> <!-- container: gap only --><div class="lay-panehead"># design</div><div class="lay-composer"><Input placeholder="message" className="m-3 flex-1" /> <!-- lone leaf insets itself --></div></section>.lay-thread { display:flex; flex-direction:column; gap:0.5rem; }.lay-panehead { border-bottom:1px solid var(--rule);padding:0.5rem 0.75rem; }
dashboard widget grid
auto-fill tracks; the widgets, not the grid, carry their insides. drag the slider to resize the container.
wrong · the grid pads
the grid's padding shifts every breakpoint; widgets can never bleed their sparklines to the card edge.
right · the widgets pad
a widget is a container: it arranges (gap), its leaves pad, and the sparkline touches the card edges for free.
<div class="lay-dash"> <!-- grid: tracks + gap --><div class="lay-widget"> <!-- container: gap --><b class="lay-metric">$48.2k</b> <!-- leaf --><span class="lay-spark"></span> <!-- bleeds: owns no pad --></div></div>.lay-dash { display:grid; gap:1rem;grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); }.lay-widget { display:flex; flex-direction:column; gap:0.5rem;overflow:hidden; border-radius:0.5rem; }.lay-metric { padding-inline:1rem; }
resizable split
the handle is a leaf too: one column wide, and the panes never pad around it.
wrong · the panes pad
fn main() { println!("hi") }
preview
the tab bar needs negative margins to reach the pane edge, and every resize re-snaps it.
right · the leaves pad
fn main() { println!("hi") }
preview
drag the handle: the left pane resizes, the tab bar stays glued to its edge.
the split owns widths; panes own arrangement; leaves own padding. dragging changes one inline width and nothing re-flows.
<div class="lay-split"> <!-- flex: owns widths --><div class="lay-splitpane is-left"> <!-- container --><div class="lay-tabbar">editor.rs</div> <!-- leaf --></div><div class="lay-handle"></div> <!-- leaf: one column wide --></div>.lay-split { display:flex; overflow:hidden; }.lay-splitpane.is-left { width:50%; flex-shrink:0; }.lay-tabbar { border-bottom:1px solid var(--rule);padding:0.5rem 1rem; }.lay-handle { width:0.25rem; cursor:col-resize; }