|
| 1 | +--- |
| 2 | +title: Base Size Scaling System |
| 3 | +description: How the sizing system scales from a single control point, why 14px is the default, and why a 2px grid is necessary for dense application UIs. |
| 4 | +keywords: [base-size, scaling, 14px, 2px grid, dense UI, sizing tokens] |
| 5 | +audience: contributing |
| 6 | +type: doc |
| 7 | +--- |
| 8 | + |
| 9 | +# Base Size Scaling System |
| 10 | + |
| 11 | +## The Single Control Point |
| 12 | + |
| 13 | +The entire sizing system scales from one variable: |
| 14 | + |
| 15 | +```css |
| 16 | +--base-size: 14; /* Change to 16 for marketing sites */ |
| 17 | +``` |
| 18 | + |
| 19 | +Changing this value proportionally scales all size tokens, pixel utilities, and spacing values throughout the framework. |
| 20 | + |
| 21 | +## Industry Standard: 16px Base, 4px Grid |
| 22 | + |
| 23 | +The overwhelming majority of CSS frameworks use a 16px base font size with a 4px spacing grid: |
| 24 | + |
| 25 | +| Framework | Base Size | Grid Unit | |
| 26 | +|-----------|-----------|-----------| |
| 27 | +| Tailwind CSS | 16px | 4px | |
| 28 | +| Chakra UI | 16px | 4px | |
| 29 | +| Radix | 16px | 4px | |
| 30 | +| Open Props | 16px | 4px | |
| 31 | +| MUI | 16px | 8px (4px half-step) | |
| 32 | +| Mantine | 16px | varies | |
| 33 | + |
| 34 | +This works well because: |
| 35 | +- 16px is the browser default, requiring no override |
| 36 | +- 16 divides cleanly by 4 (4 subdivisions) and 8 (2 subdivisions) |
| 37 | +- Content-focused sites benefit from generous spacing |
| 38 | + |
| 39 | +These frameworks target marketing sites, documentation, and general-purpose web content where information density is not a constraint. |
| 40 | + |
| 41 | +## Why 14px Default (Not 16px) |
| 42 | + |
| 43 | +Most CSS frameworks default to 16px because it's the browser default and works well for content-focused sites. Semantic UI defaults to 14px because it targets **information-dense application UIs**. |
| 44 | + |
| 45 | +Dense workflow software—admin panels, developer tools, ERP systems, financial applications—requires tighter spacing to fit complex layouts. At 16px base, default padding and margins consume too much screen real estate for these use cases. |
| 46 | + |
| 47 | +The framework is designed for the harder problem (dense UIs) and scales up for simpler cases, rather than the reverse. |
| 48 | + |
| 49 | +## Why 2px Grid (Not 4px) |
| 50 | + |
| 51 | +The 4px grid has become an industry standard, but it assumes a 16px base: |
| 52 | + |
| 53 | +``` |
| 54 | +16px ÷ 4 = 4 clean subdivisions |
| 55 | +``` |
| 56 | + |
| 57 | +With a 14px base, the 4px grid doesn't align: |
| 58 | + |
| 59 | +``` |
| 60 | +14px ÷ 4 = 3.5 (fractional, can't render crisply) |
| 61 | +``` |
| 62 | + |
| 63 | +A 2px grid restores clean alignment: |
| 64 | + |
| 65 | +``` |
| 66 | +14px ÷ 2 = 7 clean subdivisions |
| 67 | +``` |
| 68 | + |
| 69 | +### The Alignment Problem |
| 70 | + |
| 71 | +Consider a container with 1em padding (14px at base). With a 4px grid, your spacing options are: |
| 72 | + |
| 73 | +``` |
| 74 | +4px - too tight |
| 75 | +8px - doesn't subdivide 14 evenly |
| 76 | +12px - doesn't subdivide 14 evenly |
| 77 | +16px - larger than the container padding itself |
| 78 | +``` |
| 79 | + |
| 80 | +None of these create harmonious internal proportions with a 14px container. |
| 81 | + |
| 82 | +With a 2px grid, you get: |
| 83 | + |
| 84 | +``` |
| 85 | +2px, 4px, 6px, 8px, 10px, 12px, 14px |
| 86 | +``` |
| 87 | + |
| 88 | +Now 6px (3 units) and 8px (4 units) are available, and 14px lands exactly on-grid. Internal elements can align with the container's natural rhythm. |
| 89 | + |
| 90 | +### Practical Example |
| 91 | + |
| 92 | +A button with 14px base and 1em padding: |
| 93 | +- **4px grid**: Internal icon gap must be 4px or 8px—neither feels right |
| 94 | +- **2px grid**: 6px gap available, proportionally balanced with 14px padding |
| 95 | + |
| 96 | +The 2px grid isn't about wanting more granularity—it's about **maintaining alignment when your base em is 14px**. |
| 97 | + |
| 98 | +## How Scaling Works |
| 99 | + |
| 100 | +### Layer 1: Design Baseline Ratios |
| 101 | + |
| 102 | +The size scale is designed at 14px, with each step defined as a ratio: |
| 103 | + |
| 104 | +```css |
| 105 | +/* global/sizing.css */ |
| 106 | +--base-size: 14; |
| 107 | + |
| 108 | +--base-3xs: round(calc((10 / 14) * var(--base-size))); /* tiny */ |
| 109 | +--base-2xs: round(calc((11 / 14) * var(--base-size))); |
| 110 | +--base-xs: round(calc((12 / 14) * var(--base-size))); |
| 111 | +--base-s: round(calc((13 / 14) * var(--base-size))); |
| 112 | +--base-m: var(--base-size); /* anchor */ |
| 113 | +--base-l: round(calc((16 / 14) * var(--base-size))); |
| 114 | +--base-xl: round(calc((18 / 14) * var(--base-size))); |
| 115 | +--base-2xl: round(calc((20 / 14) * var(--base-size))); |
| 116 | +--base-3xl: round(calc((24 / 14) * var(--base-size))); |
| 117 | +``` |
| 118 | + |
| 119 | +The hardcoded `14` in the ratios is intentional—it's the **design reference point**, not a value to parameterize. The ratios express "at 14px base, large is 16px" as a fixed design decision. |
| 120 | + |
| 121 | +### Layer 2: Rounding for Pixel Precision |
| 122 | + |
| 123 | +The `round()` function ensures whole-pixel values when scaling: |
| 124 | + |
| 125 | +| Size | At base-size: 14 | At base-size: 16 | |
| 126 | +|------|------------------|------------------| |
| 127 | +| `--base-3xs` | round((10/14) × 14) = **10** | round((10/14) × 16) = **11** | |
| 128 | +| `--base-m` | 14 | 16 | |
| 129 | +| `--base-l` | round((16/14) × 14) = **16** | round((16/14) × 16) = **18** | |
| 130 | + |
| 131 | +Without rounding, `--base-l` at 16 would be 18.29px—a fractional value that can't render crisply. |
| 132 | + |
| 133 | +### Layer 3: Normalized rem/em Values |
| 134 | + |
| 135 | +Computed sizing divides by `--base-size` to produce normalized units: |
| 136 | + |
| 137 | +```css |
| 138 | +/* computed/sizing.css */ |
| 139 | +--size-m: calc((var(--base-m) / var(--base-size)) * 1rem); /* always 1rem */ |
| 140 | +--size-l: calc((var(--base-l) / var(--base-size)) * 1rem); |
| 141 | + |
| 142 | +--14px: calc((14 / var(--base-size)) * 1rem); |
| 143 | +--16px: calc((16 / var(--base-size)) * 1rem); |
| 144 | +``` |
| 145 | + |
| 146 | +This keeps `--size-m` pinned at exactly 1rem (the anchor point) while other sizes scale proportionally around it. |
| 147 | + |
| 148 | +### Layer 4: Pixel Token Stability |
| 149 | + |
| 150 | +The `--Npx` tokens maintain their visual pixel value regardless of base size: |
| 151 | + |
| 152 | +| Token | base-size: 14 | base-size: 16 | Visual Result | |
| 153 | +|-------|---------------|---------------|---------------| |
| 154 | +| `--14px` | (14/14) × 1rem = 1rem | (14/16) × 1rem = 0.875rem | 14px | |
| 155 | +| `--16px` | (16/14) × 1rem = 1.143rem | (16/16) × 1rem = 1rem | 16px | |
| 156 | + |
| 157 | +A `--14px` token always renders as 14 visual pixels. The rem value adjusts so the output stays constant. |
| 158 | + |
| 159 | +## Switching to 16px for Marketing Sites |
| 160 | + |
| 161 | +For content-focused sites where 16px base is appropriate: |
| 162 | + |
| 163 | +```css |
| 164 | +:root { |
| 165 | + --base-size: 16; |
| 166 | +} |
| 167 | +``` |
| 168 | + |
| 169 | +All tokens automatically recalculate: |
| 170 | +- Size scale steps increase proportionally |
| 171 | +- Pixel tokens maintain visual values |
| 172 | +- Spacing inherits the new base through `--space-unit: var(--relative-2px)` |
| 173 | +- Component padding scales with `--relative-Npx` tokens |
| 174 | + |
| 175 | +### Switching to 4px Grid |
| 176 | + |
| 177 | +When using 16px base, you can also switch to the industry-standard 4px grid: |
| 178 | + |
| 179 | +```css |
| 180 | +:root { |
| 181 | + --base-size: 16; |
| 182 | + --space-unit: var(--relative-4px); |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +This changes the `--space-{n}` scale from 2px increments to 4px increments: |
| 187 | + |
| 188 | +| Token | With 2px unit | With 4px unit | |
| 189 | +|-------|---------------|---------------| |
| 190 | +| `--space-1` | 2px | 4px | |
| 191 | +| `--space-2` | 4px | 8px | |
| 192 | +| `--space-4` | 8px | 16px | |
| 193 | +| `--space-8` | 16px | 32px | |
| 194 | + |
| 195 | +The t-shirt scale (`--spacing-xs`, `--gap-m`, etc.) continues to work unchanged—those use rem/em values independent of the space unit. |
| 196 | + |
| 197 | +### When to Use Each Configuration |
| 198 | + |
| 199 | +| Configuration | Use Case | |
| 200 | +|---------------|----------| |
| 201 | +| `--base-size: 14` + 2px grid | Dense application UIs (default) | |
| 202 | +| `--base-size: 16` + 2px grid | Content sites wanting fine control | |
| 203 | +| `--base-size: 16` + 4px grid | Content sites matching Tailwind/ecosystem conventions | |
| 204 | + |
| 205 | +## Summary |
| 206 | + |
| 207 | +| Decision | Rationale | |
| 208 | +|----------|-----------| |
| 209 | +| 14px default | Dense application UIs need tighter spacing | |
| 210 | +| 2px grid | 14px doesn't divide evenly by 4 | |
| 211 | +| Hardcoded 14 in ratios | Design reference point, not parameterized | |
| 212 | +| `round()` in calculations | Ensures whole-pixel rendering | |
| 213 | +| Single `--base-size` control | One change scales entire system | |
0 commit comments