Foundations
Layout and shape
Spacing and corners come from two small scales. Control sizes and hit targets come from the platform, so the same layout is dense on a Mac and comfortable under a thumb.
Spacing
Spacing follows a 4pt grid, with 2px and 6px steps for tight optical adjustments.
--mb-space-12px--mb-space-24px--mb-space-36px--mb-space-48px--mb-space-512px--mb-space-616px--mb-space-720px--mb-space-824px--mb-space-932px--mb-space-1040px--mb-space-1148px--mb-space-1264pxUse the tokens for padding, gaps and margins: gap: var(--mb-space-4). Spacing is the same on every platform; what changes is the size of the things being spaced. For the margin between content and the edge of a window or screen, use --mb-content-padding: 20px on macOS and iPadOS, 16px on iPhone.
Group related controls tightly and separate groups generously. A settings group might use --mb-space-4 between rows' contents and --mb-space-8 between groups.
Radius
Seven radius tokens and a capsule:
| Token | At scale 1 | Typical use |
|---|---|---|
--mb-radius-xs | 4px | Small marks, checkbox corners |
--mb-radius-sm | 6px | Small controls, list row highlights on macOS |
--mb-radius-md | 8px | macOS controls, rows on touch |
--mb-radius-lg | 12px | macOS menus and grouped lists |
--mb-radius-xl | 16px | macOS popovers and sheets |
--mb-radius-2xl | 22px | Menus, popovers and grouped lists on touch |
--mb-radius-3xl | 30px | Sheets on touch |
--mb-radius-full | 9999px | Capsules and circles |
Every token except --mb-radius-full is multiplied by the --mb-radius-scale seed. A theme sets it once to make the whole system squarer or rounder:
--mb-radius-scale: 0.7 · Graphite
--mb-radius-scale: 1 · Ember, System
--mb-radius-scale: 1.15 · Nebula
Components use the platform's role tokens rather than the scale directly: --mb-control-radius, --mb-row-radius, --mb-menu-radius, --mb-popup-radius, --mb-sheet-radius and --mb-group-radius. On iPadOS and iOS, control radii are --mb-radius-full, which is why buttons and segmented controls become capsules on touch.
Concentric corners
When one rounded shape sits inside another, make the corners concentric: the inner radius is the outer radius minus the padding between them. Equal radii make the inner corners look swollen.
outer 22 · padding 8 · inner 14
outer 22 · padding 8 · inner 22
.card {
--card-padding: var(--mb-space-4);
border-radius: var(--mb-radius-2xl);
padding: var(--card-padding);
}
.card > .thumbnail {
border-radius: max(var(--mb-radius-xs), calc(var(--mb-radius-2xl) - var(--card-padding)));
}macbetter's own components do this. The segmented control's indicator, for example, uses its track's radius minus the 2px inset.
Control metrics
Control heights, row heights and icon sizes change with the platform. Pick one in the preview to see the values the page resolves:
| Token | Use | Value |
|---|---|---|
--mb-control-height-sm | Small control | — |
--mb-control-height | Control | — |
--mb-control-height-lg | Large control | — |
--mb-row-height | List row | — |
--mb-menu-item-height | Menu item | — |
--mb-hit-target | Minimum hit target | — |
--mb-icon-size | Icon | — |
--mb-bar-height | Toolbar or navigation bar | — |
--mb-content-padding | Content margin | — |
Size your own controls and rows with these tokens, and they'll match macbetter's on every platform:
.toolbar-field {
height: var(--mb-control-height);
padding-inline: var(--mb-control-padding);
border-radius: var(--mb-control-radius);
font: var(--mb-control-font);
}Hit targets
--mb-hit-target is the smallest area a control should respond to: 24px on macOS, where a pointer is precise, and 44px on iPadOS and iOS, the HIG's minimum for a finger. The dashed outlines in the preview above show the area each button responds to.
A control can look smaller than its hit target. macbetter's buttons extend their hit area with a centered, invisible ::after that's at least --mb-hit-target in each direction. Use the same technique for your own small controls:
.close-button {
position: relative;
}
.close-button::after {
content: "";
position: absolute;
inset: 50% auto auto 50%;
width: max(100%, var(--mb-hit-target));
height: max(100%, var(--mb-hit-target));
translate: -50% -50%;
}Leave enough space between neighbouring controls that their hit areas don't overlap.
Safe areas
macbetter doesn't add safe area padding for you. On devices with a notch, rounded corners or a home indicator, set viewport-fit=cover in the viewport meta tag and pad edge-to-edge bars with the browser's env() insets:
.bottom-bar {
padding-bottom: max(var(--mb-space-4), env(safe-area-inset-bottom));
padding-left: max(var(--mb-content-padding), env(safe-area-inset-left));
padding-right: max(var(--mb-content-padding), env(safe-area-inset-right));
}Without viewport-fit=cover the browser keeps the page inside the safe area, and the insets are zero.