Skip to content

Commit 146f343

Browse files
committed
docs: update specs for 3-column grid, .bleed-* classes, and removed heading breakpoint
- nimble-css.md: rename .full-bleed → .bleed-full, .wide → .bleed-wide, add .bleed-edge throughout; update content-width default to 60ch; document clamp()-based shadow visibility; remove heading phone breakpoint references; update file structure, utility list, class count - pico-migration.md: update prescriptive sections to new class names; add v0.12 rename note for historical migration log entries - vanilla-migration.md: update class name references
1 parent 5250cd8 commit 146f343

3 files changed

Lines changed: 51 additions & 37 deletions

File tree

specs/nimble-css.md

Lines changed: 37 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ nimble.css splits its styles into two categories:
138138
- Colors/custom properties (`_colors.scss`)
139139
- Document/body grid (`_document.scss`)
140140
- Grid column assignment (`_grid-columns.scss`)
141-
- Layout utilities (`_layout-utilities.scss`) — `.fluid`, `.full-bleed`, `.grid`, `.wide`, `.container`
141+
- Layout utilities (`_layout-utilities.scss`) — `.fluid`, `.bleed-edge`, `.bleed-wide`, `.bleed-full`, `.grid`, `.container`
142142
- Print styles (`_print.scss`)
143143

144144
**Scopeable styles** — emitted globally by default, optionally wrappable in `@scope`:
@@ -164,7 +164,7 @@ For users who need component isolation (`.no-nimble` opt-out), two paths are ava
164164
1. **JS progressive enhancement (recommended):** Include `no-nimble.js` alongside the CSS. The script uses sentinel CSS custom properties to find the boundary between global and scopeable rules, wraps the scopeable portion in `@scope` at runtime, and auto-detects broken browsers.
165165
2. **SCSS build-time opt-in:** Set `$exclude-selector: '.no-nimble'` for a pure-CSS solution (with the caveat that desktop Safari will be affected).
166166

167-
Layout utilities are intentionally global because they interact with the body grid (e.g., `.full-bleed` sets `grid-column: 1 / -1`). An element with `class="no-nimble full-bleed"` should still participate in the body grid layout even though nimble's component styles (typography, forms, etc.) don't apply inside it.
167+
Layout utilities are intentionally global because they interact with the body grid (e.g., `.bleed-full` sets `grid-column: 1 / -1`). An element with `class="no-nimble bleed-full"` should still participate in the body grid layout even though nimble's component styles (typography, forms, etc.) don't apply inside it.
168168

169169
See [Section 15.2](#152-third-party-component-isolation-no-nimble-opt-out) for usage details and design rationale.
170170

@@ -265,7 +265,7 @@ nimble.css takes a **middle path**: ~20 semantic custom properties on `:root`, p
265265
/* --- Spacing & Layout --- */
266266
--nc-radius: /* default border radius */
267267
--nc-spacing: /* base spacing unit */
268-
--nc-content-width: /* max-width for centered container (~720px) */
268+
--nc-content-width: /* max-width for centered container (60ch, ~480-600px depending on font) */
269269
}
270270
```
271271

@@ -277,7 +277,7 @@ Compared to the original draft's ~25, we cut:
277277
- `transition` -- hardcoded `0.2s ease-in-out`
278278
- `text-1` / `text-2` -- replaced by single `--nc-text`; muted text uses `color-mix()` inline
279279
- `text-heading` -- headings differentiate via size, not color
280-
- `wide-width` -- hardcoded in `.wide` utility
280+
- `wide-width` -- hardcoded in `.bleed-wide` utility
281281
- `line-height`, `font-size` -- hardcoded sensible defaults (1.5, 100%)
282282

283283
### 4.4 Why These Specific Properties
@@ -482,25 +482,36 @@ body > * {
482482
This approach (from simple.css) is superior to PicoCSS's max-width + breakpoint approach because:
483483
- Content is centered with real padding (not zero-padding with width tricks).
484484
- No breakpoints needed for basic centering.
485-
- Full-bleed elements can use `grid-column: 1 / -1`.
485+
- Full-bleed elements can use `.bleed-full` (or `grid-column: 1 / -1`).
486486

487487
**Content width defaults:**
488-
- `--nc-content-width: 720px` (approximately 65ch at 16px base, good for readability)
488+
- `--nc-content-width: 60ch` (aligns with Open Props `--size-content-3`; ~480-600px depending on font, good for readability)
489489
- Overridable per-element or globally
490490

491491
**Breaking out of the container:**
492492

493+
Breakout hierarchy (narrow -> wide):
494+
- `.bleed-edge` — content + shadow gap on each side (shadow boundary); goes full-width when shadow is hidden
495+
- `.bleed-wide` — up to 1200px, centered
496+
- `.bleed-full` — full viewport width
497+
493498
```css
494-
.full-bleed {
499+
.bleed-edge {
495500
grid-column: 1 / -1;
501+
max-width: clamp(content-width + 2*gap, ..., 100%); /* shadow-aware */
502+
margin-inline: auto;
496503
}
497504

498-
.wide {
505+
.bleed-wide {
499506
grid-column: 1 / -1;
500507
max-width: 1200px;
501508
margin-inline: auto;
502509
padding-inline: var(--nc-spacing);
503510
}
511+
512+
.bleed-full {
513+
grid-column: 1 / -1;
514+
}
504515
```
505516

506517
**Responsive equal-column grid:**
@@ -567,7 +578,7 @@ line-height: 1.5;
567578
PicoCSS scales font-size from 100% to 131.25% across 6 breakpoints. nimble.css uses a simpler approach:
568579
569580
- Base size stays at `100%` for all viewports.
570-
- On the phone breakpoint, headings scale down slightly.
581+
- Headings use the same size at all viewport widths (no breakpoint scaling). The differences were too small to justify a jarring layout shift.
571582
- Users who want larger text on large screens can set `font-size: 112.5%` on `:root`.
572583
573584
### 8.3 Heading Scale
@@ -581,11 +592,7 @@ h5: 1.125rem (18px) line-height: 1.4
581592
h6: 1rem (16px) line-height: 1.5
582593
```
583594
584-
On the phone breakpoint (`max-width: 720px`):
585-
586-
```
587-
h1: 1.75rem h2: 1.5rem h3: 1.3rem
588-
```
595+
Heading sizes are the same at all viewport widths. The previous phone-breakpoint scale-down (h1: 1.75rem, h2: 1.5rem, h3: 1.3rem) was removed — the differences were too small (3-4px) to justify a jarring layout shift, and `text-wrap: balance` handles long headings on narrow screens.
589596
590597
### 8.4 Vertical Rhythm
591598
@@ -931,9 +938,10 @@ These interact with the body grid and must work everywhere, including on `.no-ni
931938
```css
932939
.container /* centered content width (useful inside fluid layout) */
933940
.fluid /* full viewport width with padding */
934-
.full-bleed /* break out of centered container to full width */
941+
.bleed-edge /* break out to shadow/paper boundary (content + gap); full-width when shadow hidden */
942+
.bleed-wide /* break out to 1200px max-width */
943+
.bleed-full /* break out to full viewport width */
935944
.grid /* responsive equal-column grid (1fr mobile, auto-fit desktop) */
936-
.wide /* break out to 1200px max-width */
937945
```
938946

939947
### 10.2 Buttons (Scoped)
@@ -964,7 +972,7 @@ These interact with the body grid and must work everywhere, including on `.no-ni
964972

965973
The `.no-nimble` class requires opt-in activation — either via `no-nimble.js` (recommended) or the `$exclude-selector` SCSS flag. Without activation, the class has no effect. See [Section 15.2](#152-third-party-component-isolation-no-nimble-opt-out) for details.
966974

967-
**Total class count: ~10** (~9 utilities + `.no-nimble` opt-out).
975+
**Total class count: ~11** (~10 utilities + `.no-nimble` opt-out).
968976

969977
## 11. Breakpoints
970978

@@ -976,15 +984,17 @@ nimble.css uses:
976984

977985
| Name | Value | Purpose |
978986
|---|---|---|
979-
| `phone` | `max-width: 720px` | Scale down headings, make form inputs full-width |
987+
| `phone` | `max-width: 720px` | Make form inputs full-width, collapse `.grid` to single column |
980988
| `tablet` (optional) | `max-width: 1024px` | May be used for wide-content breakout adjustments |
981989

982990
That's it. The grid-based centered layout is inherently responsive without breakpoints.
983991
984992
### 11.2 What Changes at the Phone Breakpoint
985993
986-
- Headings h1-h3 scale down (see Section 8.3).
987994
- Form inputs, select, and textarea go full-width.
995+
- `.grid` collapses to a single column.
996+
997+
The content shadow visibility is **not** controlled by the phone breakpoint — it uses a `clamp()` formula that snaps the shadow to 0 width when there isn't enough space for meaningful gaps between the shadow edge and viewport edge. This means the shadow disappears at a content-width-dependent threshold, not at a fixed pixel breakpoint.
988998

989999
## 12. File Structure & Build
9901000

@@ -999,7 +1009,7 @@ nimble.css/
9991009
_colors.scss # Color properties (oklch generation + light-dark())
10001010
_document.scss # html, body, *, ::selection
10011011
_grid-columns.scss # Global: body grid column assignment (body > *)
1002-
_layout-utilities.scss # Global: .fluid, .full-bleed, .grid, .wide, .container
1012+
_layout-utilities.scss # Global: .fluid, .bleed-edge, .bleed-wide, .bleed-full, .grid, .container
10031013
_scopeable.scss # Mixin loading scopeable modules via meta.load-css()
10041014
_typography.scss # Scopeable: headings, p, lists, blockquote, hr, mark
10051015
_links.scss # Scopeable: a
@@ -1093,7 +1103,7 @@ $font-mono: ui-monospace, 'Cascadia Code', 'Source Code Pro',
10931103
// --- Spacing & Layout ---
10941104
$spacing: 1rem !default;
10951105
$radius: 0.25rem !default;
1096-
$content-width: 720px !default;
1106+
$content-width: 60ch !default;
10971107
$wide-width: 1200px !default;
10981108

10991109
// --- Breakpoints ---
@@ -1208,7 +1218,7 @@ Published via GitHub Pages, built by CI. No built CSS in the repo.
12081218
Lessons from MVP.css, new.css, and HN discussions:
12091219

12101220
- **MVP.css** abuses semantic HTML (using `aside` for cards, `a strong` for buttons) to avoid classes. This harms accessibility and confuses developers.
1211-
- **Pure classless is insufficient** for real-world use. You need at least: a way to distinguish primary/secondary buttons, striped tables, layout modes, and full-bleed content.
1221+
- **Pure classless is insufficient** for real-world use. You need at least: a way to distinguish primary/secondary buttons, striped tables, layout modes, and bleed/breakout content.
12121222
- **Minimum viable classes**: nimble.css uses ~9 classes total. Every class has a clear, non-overlapping purpose.
12131223

12141224
### 15.2 Third-Party Component Isolation (`.no-nimble` Opt-Out)
@@ -1229,17 +1239,17 @@ This means nimble's component styles apply everywhere **except** inside elements
12291239

12301240
```html
12311241
<!-- nimble styles apply here -->
1232-
<main class="fluid full-bleed">
1242+
<main class="fluid bleed-full">
12331243
<h1>Styled by nimble</h1>
12341244

12351245
<!-- nimble component styles do NOT apply inside this element -->
1236-
<div class="no-nimble full-bleed">
1246+
<div class="no-nimble bleed-full">
12371247
<ThirdPartyDataTable />
12381248
</div>
12391249
</main>
12401250
```
12411251

1242-
Note that layout utilities (`.fluid`, `.full-bleed`, `.wide`, `.container`) are global, so they work on `.no-nimble` elements — you can still control layout while opting out of nimble's component styling.
1252+
Note that layout utilities (`.fluid`, `.bleed-edge`, `.bleed-wide`, `.bleed-full`, `.container`) are global, so they work on `.no-nimble` elements — you can still control layout while opting out of nimble's component styling.
12431253

12441254
**Enabling `.no-nimble` — two paths:**
12451255

@@ -1459,15 +1469,15 @@ One partial per element group. Each can be implemented and visually tested indep
14591469

14601470
Utilities, extended demo, and final validation.
14611471

1462-
- [x] `src/_utilities.scss``.container`, `.fluid`, `.full-bleed`, `.wide`, `.striped`, `.visually-hidden`, `.overflow-auto` (in `@layer nimble.utilities`, behind `$enable-utilities`)
1472+
- [x] `src/_utilities.scss``.container`, `.fluid`, `.bleed-edge`, `.bleed-wide`, `.bleed-full`, `.striped`, `.visually-hidden`, `.overflow-auto` (in `@layer nimble.utilities`, behind `$enable-utilities`)
14631473
- [x] Wire `_utilities.scss` in `nimble.scss`
14641474
- [x] Fix input backgrounds — replaced `surface-3` with `color-mix(in oklch, surface-1, surface-2 20%)` via private `--_input-bg` variable
14651475
- [x] `demo/extended.html` — layout modes, button variants + groups (including same-type groups), form patterns (login/registration/search with pill-shaped search bar), surface hierarchy swatches, dark mode toggle, striped table, dialog demo
14661476
- [x] WCAG AA color audit — lowered `$primary-lightness` from 0.55 to 0.50; switched `primary-contrast` and `secondary-contrast` to `light-dark(#fff, oklch(0.15 0.005 250))` for dark-mode button readability. All pairings pass AA.
14671477
- [x] Light-mode `text-2` lightened from L=0.450 to L=0.580 for visible distinction from `text-1` (L=0.280)
14681478
- [x] Button group fixes — stripped margin on children, box-shadow dividers between same-type siblings, pill-shaped search groups via `[role="search"] [role="group"]`
14691479
- [x] Outline button hover keeps outline style (subtle `primary-focus` tint instead of solid fill)
1470-
- [x] `.wide` utility: added `width: 100%` so it stretches within `grid-column: 1 / -1`
1480+
- [x] `.bleed-wide` utility (formerly `.wide`): added `width: 100%` so it stretches within `grid-column: 1 / -1`
14711481
- [x] Measure `dist/nimble.min.css` against size budget — 11,924 B min / **3,131 B gzipped** (budget: <8 KB min+gz)
14721482
- [x] Verify: all four feature flags (`$enable-dialog`, `$enable-switch`, `$enable-details`, `$enable-utilities`) correctly exclude output when disabled
14731483
- Output: `nimble.css` 15,467 B / `nimble.min.css` 11,924 B / gzipped ~3.1 KB

specs/pico-migration.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,17 +80,19 @@ Pico's `.container` defaults to ~1200px (varies by breakpoint). nimble's centere
8080
If your project uses third-party components (datatables, rich text editors, etc.) that nimble's element styles interfere with, add `class="no-nimble"` to their wrapper:
8181

8282
```html
83-
<div class="no-nimble full-bleed">
83+
<div class="no-nimble bleed-full">
8484
<ThirdPartyDataTable />
8585
</div>
8686
```
8787

88-
nimble's component styles (typography, forms, tables, etc.) won't apply inside `.no-nimble` elements. Layout utilities (`.fluid`, `.full-bleed`, `.wide`, `.container`) still work. See the [nimble spec §15.2](nimble-css.md#152-third-party-component-isolation-no-nimble-opt-out) for details.
88+
nimble's component styles (typography, forms, tables, etc.) won't apply inside `.no-nimble` elements. Layout utilities (`.fluid`, `.bleed-edge`, `.bleed-wide`, `.bleed-full`, `.container`) still work. See the [nimble spec §15.2](nimble-css.md#152-third-party-component-isolation-no-nimble-opt-out) for details.
8989

9090
### 1.6 Check for Pico-specific classes
9191

9292
Replace or remove any Pico-specific classes. See the [Feature Comparison Matrix](#2-feature-comparison-matrix) for mappings.
9393

94+
> **Note:** nimble.css v0.12+ renamed breakout classes: `.full-bleed``.bleed-full`, `.wide``.bleed-wide`, and added `.bleed-edge`. Migration log entries (§6.x) written before this rename still reference the old class names. Projects migrated before v0.12 should update: `.full-bleed``.bleed-full`, `.wide``.bleed-wide`.
95+
9496
### 1.7 Verify visually
9597

9698
Run the dev server and check each page. The main areas to inspect:
@@ -116,10 +118,11 @@ This is the **single largest source of layout dimension mismatches** — without
116118

117119
### 1.9 Full-bleed header backgrounds
118120

119-
Pico's `<header>` is a normal block element spanning the viewport. nimble's body grid constrains all children to the content column. If your header has a background color that should span full width:
121+
Pico's `<header>` is a normal block element spanning the viewport. nimble's body grid constrains all children to the content column. If your header has a background color that should span full width, use a bleed utility class:
120122

121-
```css
122-
header { grid-column: 1 / -1; }
123+
```html
124+
<header class="bleed-full">...</header> <!-- full viewport width -->
125+
<header class="bleed-edge">...</header> <!-- aligns with shadow boundary -->
123126
```
124127

125128
### 1.10 Override surface colors (if needed)
@@ -204,8 +207,9 @@ These work identically in both libraries (write semantic HTML, get styled output
204207
| Centered content | `.container` class (max-width + breakpoints) | Body CSS Grid (automatic) | nimble centers by default; no class needed. |
205208
| Content width | ~1200px (varies by breakpoint) | `60ch` (`--nc-content-width`, aligns with OpenProps `--size-content-3`) | Overridable via CSS custom property. |
206209
| Full-width layout | No built-in fluid mode | `.fluid` class on body | |
207-
| Full-bleed breakout | Not supported | `.full-bleed` class | |
208-
| Wide breakout | Not supported | `.wide` class | |
210+
| Shadow-edge breakout | Not supported | `.bleed-edge` class | Aligns with shadow boundary; full-width when shadow hidden |
211+
| Wide breakout | Not supported | `.bleed-wide` class | Up to 1200px, centered |
212+
| Full-bleed breakout | Not supported | `.bleed-full` class | Full viewport width |
209213

210214
### 2.5 Theming / Customization
211215

@@ -255,7 +259,7 @@ body > * { grid-column: 2; }
255259
Content is always centered with real padding. No breakpoints needed. This means:
256260
- You don't need `class="container"` on a wrapper element for basic centering.
257261
- The `.container` class exists but serves a different purpose (re-centering inside `.fluid` layouts).
258-
- Full-bleed content is possible with `grid-column: 1 / -1`.
262+
- Breakout content uses `.bleed-edge` (shadow boundary), `.bleed-wide` (1200px), or `.bleed-full` (viewport).
259263

260264
**Migration note:** If your Pico project wraps everything in `<main class="container">`, you can keep it (nimble's `.container` applies `max-width` + `margin-inline: auto`), but you may not need it. The body grid already centers direct children at `--nc-content-width` (720px).
261265

specs/vanilla-migration.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Adding nimble.css to these projects provides:
2626
- **CSS reset** (replaces `sanitize.css` where present)
2727
- **Typography baseline** (heading scale, body text, list spacing, `text-wrap: balance`)
2828
- **Form styling** (inputs, selects, textareas, buttons, checkboxes, switches)
29-
- **Body grid layout** (centered content column, full-bleed/wide breakouts)
29+
- **Body grid layout** (centered content column, `.bleed-edge`/`.bleed-wide`/`.bleed-full` breakouts)
3030
- **Light/dark mode** via `light-dark()` and `color-scheme`
3131
- **Cascade layers** (`@layer nimble.reset, nimble.base, nimble.utilities`) — unlayered project CSS always wins
3232

@@ -541,7 +541,7 @@ When nimble's element styles conflict with a component's own styling:
541541
<TranscriptArea class="no-nimble" />
542542
```
543543

544-
Layout utilities (`.fluid`, `.full-bleed`, `.wide`, `.container`) still work inside `.no-nimble`. Only nimble's component styles (typography, forms, tables) are excluded.
544+
Layout utilities (`.fluid`, `.bleed-edge`, `.bleed-wide`, `.bleed-full`, `.container`) still work inside `.no-nimble`. Only nimble's component styles (typography, forms, tables) are excluded.
545545

546546
**Candidates for `.no-nimble` in these projects:**
547547
- rift-transcription: TranscriptArea overlay container

0 commit comments

Comments
 (0)