actual-css 0.3.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +67 -3
- package/README.md +35 -30
- package/dist/actual.css +73 -4946
- package/dist/actual.full.css +7090 -0
- package/dist/actual.full.js +1 -0
- package/dist/actual.full.min.css +1 -0
- package/dist/actual.js +1 -1
- package/dist/actual.min.css +1 -1
- package/docs/design-notes/cascade-layer.md +34 -13
- package/docs/design-notes/column-layout.md +677 -0
- package/docs/design-notes/forced-colors.md +3 -0
- package/docs/design-notes/grid.md +612 -0
- package/docs/design-notes/naming.md +15 -0
- package/docs/design-notes/widget-primitives.md +1 -0
- package/docs/navigation.json +5 -1
- package/docs/pages/components/alert.md +16 -14
- package/docs/pages/components/aura.md +1 -1
- package/docs/pages/components/avatar.md +6 -6
- package/docs/pages/components/badge.md +7 -7
- package/docs/pages/components/button.md +16 -16
- package/docs/pages/components/card.md +13 -9
- package/docs/pages/components/chat.md +8 -8
- package/docs/pages/components/dialog.md +7 -7
- package/docs/pages/components/drawer.md +3 -3
- package/docs/pages/components/fab.md +7 -7
- package/docs/pages/components/navbar.md +9 -8
- package/docs/pages/components/pagination.md +4 -3
- package/docs/pages/components/skeleton.md +4 -4
- package/docs/pages/components/spinner.md +5 -5
- package/docs/pages/components/table.md +30 -5
- package/docs/pages/enhancements/flyout.md +13 -13
- package/docs/pages/enhancements/overview.md +1 -1
- package/docs/pages/enhancements/scrollspy.md +6 -6
- package/docs/pages/enhancements/status-bar.md +5 -1
- package/docs/pages/enhancements/tabs.md +6 -6
- package/docs/pages/enhancements/tooltip.md +1 -1
- package/docs/pages/examples/overview.md +39 -22
- package/docs/pages/forms/choice-cards.md +11 -6
- package/docs/pages/forms/controls.md +1 -1
- package/docs/pages/forms/detached-actions.md +1 -1
- package/docs/pages/forms/floating-field.md +10 -5
- package/docs/pages/forms/form-actions.md +1 -1
- package/docs/pages/forms/input-policy.md +1 -1
- package/docs/pages/forms/joined-controls.md +4 -4
- package/docs/pages/forms/labels.md +6 -6
- package/docs/pages/forms/otp.md +1 -1
- package/docs/pages/forms/overview.md +19 -19
- package/docs/pages/forms/password.md +1 -1
- package/docs/pages/forms/range.md +1 -1
- package/docs/pages/forms/states-and-sizes.md +41 -45
- package/docs/pages/forms/sticky-actions.md +3 -3
- package/docs/pages/forms/switch.md +110 -2
- package/docs/pages/forms/validation.md +9 -9
- package/docs/pages/foundations/philosophy.md +1 -1
- package/docs/pages/foundations/theming.md +17 -2
- package/docs/pages/foundations/tokens.md +22 -10
- package/docs/pages/foundations/typography.md +50 -20
- package/docs/pages/guides/bootstrap.md +11 -11
- package/docs/pages/guides/integrating-actual-css.md +186 -0
- package/docs/pages/guides/introduction.md +23 -26
- package/docs/pages/guides/modular-import.md +173 -0
- package/docs/pages/guides/progressive-enhancement.md +81 -78
- package/docs/pages/guides/tailwind.md +6 -8
- package/docs/pages/layout/app-shell.md +1 -1
- package/docs/pages/layout/center.md +1 -1
- package/docs/pages/layout/choosing.md +39 -0
- package/docs/pages/layout/column-layout.md +206 -0
- package/docs/pages/layout/frame.md +6 -1
- package/docs/pages/layout/grid.md +100 -102
- package/docs/pages/layout/list.md +1 -1
- package/docs/pages/layout/media.md +1 -1
- package/docs/pages/layout/overview.md +15 -2
- package/docs/pages/layout/scroll-snap.md +2 -2
- package/docs/pages/layout/scroll-target.md +45 -0
- package/docs/pages/layout/sidebar-layout.md +20 -19
- package/docs/pages/layout/stack.md +53 -1
- package/docs/pages/layout/switcher.md +10 -26
- package/docs/pages/layout/topbar.md +2 -2
- package/docs/pages/patterns/actions.md +1 -1
- package/docs/pages/patterns/code-block.md +1 -1
- package/docs/pages/patterns/exclusive-accordion.md +1 -1
- package/docs/pages/patterns/hierarchical-nav.md +1 -1
- package/docs/pages/patterns/icon-input.md +1 -1
- package/docs/pages/patterns/intent-nesting.md +1 -1
- package/docs/pages/patterns/navigation-list.md +1 -1
- package/docs/pages/patterns/overview.md +1 -1
- package/docs/pages/patterns/structured-lists.md +1 -1
- package/docs/pages/utilities/accessibility.md +3 -3
- package/docs/pages/utilities/flex.md +15 -15
- package/docs/pages/utilities/links.md +4 -4
- package/docs/pages/utilities/list.md +8 -8
- package/docs/pages/utilities/overflow.md +8 -8
- package/docs/pages/utilities/overview.md +1 -1
- package/docs/pages/utilities/shape.md +3 -3
- package/docs/pages/utilities/sizing-wrapping.md +23 -16
- package/docs/pages/utilities/spacing.md +20 -20
- package/docs/pages/utilities/text.md +10 -10
- package/llms.txt +46 -4
- package/package.json +42 -13
- package/scripts/reserved-classes.json +261 -0
- package/src/cli/actual-css.js +133 -0
- package/src/css/actual.css +1 -31
- package/src/css/actual.full.css +11 -2
- package/src/css/components/alert.css +17 -4
- package/src/css/components/badge.css +18 -6
- package/src/css/components/breadcrumb.css +1 -1
- package/src/css/components/button.css +19 -1
- package/src/css/components/card.css +27 -2
- package/src/css/components/drawer.css +27 -2
- package/src/css/components/flyout.css +5 -0
- package/src/css/components/index.css +32 -27
- package/src/css/components/join.css +8 -1
- package/src/css/components/key.css +2 -0
- package/src/css/components/menu.css +11 -1
- package/src/css/components/meter.css +4 -1
- package/src/css/components/modal.css +5 -0
- package/src/css/components/pagination.css +11 -0
- package/src/css/components/spinner.css +5 -0
- package/src/css/components/status-bar.css +5 -0
- package/src/css/components/surface.css +5 -0
- package/src/css/components/table.css +6 -0
- package/src/css/components/tooltip.css +5 -0
- package/src/css/core/index.css +9 -0
- package/src/css/core/print.css +18 -0
- package/src/css/{theme.css → core/theme.css} +20 -10
- package/src/css/{tokens.css → core/tokens.css} +15 -2
- package/src/css/{variants.css → core/variants.css} +3 -2
- package/src/css/effects/index.css +2 -0
- package/src/css/forms/base.css +8 -0
- package/src/css/forms/choice-card.css +5 -4
- package/src/css/forms/choice.css +49 -37
- package/src/css/forms/control.css +4 -1
- package/src/css/forms/custom-select.css +2 -0
- package/src/css/{optional → forms}/floating-field.css +25 -7
- package/src/css/forms/index.css +10 -13
- package/src/css/forms/native.css +15 -2
- package/src/css/{optional → forms}/otp.css +20 -16
- package/src/css/forms/switch.css +31 -29
- package/src/css/layout/app-shell.css +6 -0
- package/src/css/layout/center.css +13 -0
- package/src/css/layout/cluster.css +21 -0
- package/src/css/layout/column-layout.css +144 -0
- package/src/css/layout/container-query.css +13 -0
- package/src/css/layout/frame.css +19 -0
- package/src/css/layout/grid.css +141 -0
- package/src/css/layout/index.css +42 -0
- package/src/css/layout/measure.css +9 -0
- package/src/css/layout/media.css +10 -0
- package/src/css/layout/scroll-target.css +15 -0
- package/src/css/layout/scroller.css +41 -0
- package/src/css/layout/sidebar-layout.css +31 -0
- package/src/css/layout/stack.css +21 -0
- package/src/css/layout/switcher.css +23 -0
- package/src/css/{optional/layout-extra.css → layout/topbar.css} +0 -20
- package/src/css/typography/index.css +5 -0
- package/src/css/typography/lead.css +7 -0
- package/src/css/{components → typography}/overline.css +2 -2
- package/src/css/{prose.css → typography/prose.css} +53 -38
- package/src/css/{utilities.css → utilities/base.css} +2 -0
- package/src/css/utilities/index.css +3 -0
- package/src/js/escape.js +36 -0
- package/src/js/flyout.js +22 -12
- package/src/js/full.js +26 -0
- package/src/js/index.js +5 -21
- package/src/js/surface.js +1 -31
- package/src/js/tooltip.js +46 -18
- package/src/js/validation.js +1 -1
- package/src/tooling/css-bundle.js +308 -0
- package/dist/actual-themes.min.css +0 -1
- package/dist/optional.css +0 -1048
- package/dist/optional.min.css +0 -1
- package/docs/pages/guides/optional-components.md +0 -33
- package/src/css/grid.css +0 -109
- package/src/css/layout.css +0 -123
- package/src/css/optional/index.css +0 -10
- package/src/css/optional/scroller.css +0 -63
- package/src/css/print.css +0 -47
- package/src/css/themes/corporate.css +0 -60
- package/src/css/themes/cyberpunk.css +0 -60
- package/src/css/themes/dim.css +0 -33
- package/src/css/themes/edge.css +0 -117
- package/src/css/themes/forest.css +0 -65
- package/src/css/themes/gradient.css +0 -97
- package/src/css/themes/index.css +0 -47
- package/src/css/themes/indigo.css +0 -33
- package/src/css/themes/lavender.css +0 -66
- package/src/css/themes/mono.css +0 -60
- package/src/css/themes/neon.css +0 -66
- package/src/css/themes/ocean.css +0 -60
- package/src/css/themes/petrol.css +0 -64
- package/src/css/themes/spruce.css +0 -64
- package/src/css/themes/square.css +0 -65
- package/src/css/themes/sunset.css +0 -66
- /package/src/css/{optional → components}/chat.css +0 -0
- /package/src/css/{optional → components}/fab.css +0 -0
- /package/src/css/{base.css → core/base.css} +0 -0
- /package/src/css/{focus.css → core/focus.css} +0 -0
- /package/src/css/{intents.css → core/intents.css} +0 -0
- /package/src/css/{reset.css → core/reset.css} +0 -0
- /package/src/css/{optional → effects}/aura.css +0 -0
- /package/src/css/{optional → layout}/scroll-snap.css +0 -0
- /package/src/css/{optional/typography-fluid.css → typography/fluid.css} +0 -0
- /package/src/css/{optional/utilities-extra.css → utilities/extra.css} +0 -0
|
@@ -0,0 +1,612 @@
|
|
|
1
|
+
# Grid Responsiveness and Balanced Subdivision
|
|
2
|
+
|
|
3
|
+
## Status
|
|
4
|
+
|
|
5
|
+
Design note for Actual CSS 0.4.
|
|
6
|
+
|
|
7
|
+
This document explains the intended behavior of `.grid` and `.grid-N`, the alternatives considered, and the CSS constraints that prevent a single mechanism from satisfying every use case.
|
|
8
|
+
|
|
9
|
+
The goal is to preserve these decisions so future changes do not accidentally reintroduce previously rejected approaches.
|
|
10
|
+
|
|
11
|
+
## Problem
|
|
12
|
+
|
|
13
|
+
Actual CSS exposes two related but distinct grid use cases:
|
|
14
|
+
|
|
15
|
+
* a free collection that should adapt naturally to available space;
|
|
16
|
+
* a structured collection where a known column density should collapse through visually balanced subdivisions.
|
|
17
|
+
|
|
18
|
+
These goals are not equivalent.
|
|
19
|
+
|
|
20
|
+
A generic intrinsic grid can efficiently fill available space, but it does not know whether the resulting number of columns produces a balanced distribution for the number of items.
|
|
21
|
+
|
|
22
|
+
Conversely, a structurally balanced grid can preserve predictable subdivisions, but CSS cannot make it fully autonomous without introducing other layout constraints.
|
|
23
|
+
|
|
24
|
+
The distinction matters most when resizing a collection.
|
|
25
|
+
|
|
26
|
+
For six items, a purely space-driven grid may naturally move through:
|
|
27
|
+
|
|
28
|
+
```text
|
|
29
|
+
6 → 5 → 4 → 3 → 2 → 1
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This maximizes use of available space, but produces layouts such as:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
5 + 1
|
|
36
|
+
4 + 2
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Actual's structural grid use case instead prefers:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
6 → 3 → 2 → 1
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Every state is a natural subdivision of six and every item has the same width.
|
|
46
|
+
|
|
47
|
+
## Core principle
|
|
48
|
+
|
|
49
|
+
Actual distinguishes **space-driven grids** from **count-driven grids**.
|
|
50
|
+
|
|
51
|
+
### `.grid`: space-driven collection
|
|
52
|
+
|
|
53
|
+
`.grid` is an intrinsic responsive collection.
|
|
54
|
+
|
|
55
|
+
Its behavior is driven by:
|
|
56
|
+
|
|
57
|
+
* the width of its containing block;
|
|
58
|
+
* `--grid-min`;
|
|
59
|
+
* the number of tracks that can fit.
|
|
60
|
+
|
|
61
|
+
A typical implementation uses `auto-fit`.
|
|
62
|
+
|
|
63
|
+
The browser is free to choose any number of columns that satisfies the minimum item width.
|
|
64
|
+
|
|
65
|
+
No guarantee is made about balanced final rows.
|
|
66
|
+
|
|
67
|
+
Conceptually:
|
|
68
|
+
|
|
69
|
+
```text
|
|
70
|
+
available space
|
|
71
|
+
↓
|
|
72
|
+
how many items fit?
|
|
73
|
+
↓
|
|
74
|
+
auto-fit
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
This is appropriate for collections where filling available space is more important than preserving a particular structural rhythm.
|
|
78
|
+
|
|
79
|
+
### `.grid-N`: count-driven structural grid
|
|
80
|
+
|
|
81
|
+
`.grid-2`, `.grid-3`, `.grid-4`, and `.grid-6` express a preferred structural density.
|
|
82
|
+
|
|
83
|
+
Their responsive progression should favor natural divisors of that density.
|
|
84
|
+
|
|
85
|
+
The intended chains are:
|
|
86
|
+
|
|
87
|
+
```text
|
|
88
|
+
.grid-2 2 → 1
|
|
89
|
+
.grid-3 3 → 1
|
|
90
|
+
.grid-4 4 → 2 → 1
|
|
91
|
+
.grid-6 6 → 3 → 2 → 1
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
This deliberately skips intermediate column counts that would create visibly uneven subdivisions.
|
|
95
|
+
|
|
96
|
+
For example, `.grid-6` should not pass through five or four columns simply because five or four tracks happen to fit.
|
|
97
|
+
|
|
98
|
+
The defining property of `.grid-N` is therefore not merely:
|
|
99
|
+
|
|
100
|
+
> at most N columns
|
|
101
|
+
|
|
102
|
+
It is:
|
|
103
|
+
|
|
104
|
+
> a structural density of N columns that collapses through balanced subdivisions of N.
|
|
105
|
+
|
|
106
|
+
## Equal-width items are an invariant
|
|
107
|
+
|
|
108
|
+
Actual does not attempt to repair an incomplete row by stretching individual items, changing their span independently, or making the last card wider than its peers.
|
|
109
|
+
|
|
110
|
+
At every responsive state, all direct items in a structural grid should have the same width.
|
|
111
|
+
|
|
112
|
+
Layouts such as this are intentionally avoided:
|
|
113
|
+
|
|
114
|
+
```text
|
|
115
|
+
[A][B][C]
|
|
116
|
+
[ D ][E]
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The grid may contain an incomplete final row when its item count is incompatible with the selected density, but the items themselves remain regular.
|
|
120
|
+
|
|
121
|
+
Visual consistency of the grid is more important than artificially filling every pixel.
|
|
122
|
+
|
|
123
|
+
## Item count and structural density are different inputs
|
|
124
|
+
|
|
125
|
+
A structural density does not imply that CSS knows the actual number of items.
|
|
126
|
+
|
|
127
|
+
For example, `.grid-6` describes the sequence:
|
|
128
|
+
|
|
129
|
+
```text
|
|
130
|
+
6 → 3 → 2 → 1
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
but it does not guarantee a balanced final row for an arbitrary number of children.
|
|
134
|
+
|
|
135
|
+
With eight items, six columns still produce:
|
|
136
|
+
|
|
137
|
+
```text
|
|
138
|
+
6 + 2
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
and three columns produce:
|
|
142
|
+
|
|
143
|
+
```text
|
|
144
|
+
3 + 3 + 2
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
CSS is not inferring the child count and selecting an optimal divisor of that count.
|
|
148
|
+
|
|
149
|
+
The contract is narrower:
|
|
150
|
+
|
|
151
|
+
> `.grid-N` provides balanced subdivisions of the declared structural density N.
|
|
152
|
+
|
|
153
|
+
This works particularly well when collection sizes are naturally compatible with that density.
|
|
154
|
+
|
|
155
|
+
For paginated collections, the server knows the page size and should choose a page size that works well with the expected presentation densities.
|
|
156
|
+
|
|
157
|
+
A partial final page is normal. CSS should not contain pagination heuristics intended to disguise a poor full-page item count.
|
|
158
|
+
|
|
159
|
+
## Why `auto-fit` alone is insufficient
|
|
160
|
+
|
|
161
|
+
`auto-fit` answers a spatial question:
|
|
162
|
+
|
|
163
|
+
> How many tracks of this minimum size fit in the available width?
|
|
164
|
+
|
|
165
|
+
It does not answer:
|
|
166
|
+
|
|
167
|
+
> Which number of tracks produces the most balanced subdivision?
|
|
168
|
+
|
|
169
|
+
For six items, if five columns fit, `auto-fit` may use five columns.
|
|
170
|
+
|
|
171
|
+
That behavior is correct for an intrinsic collection and incorrect for the structural-grid contract.
|
|
172
|
+
|
|
173
|
+
Therefore `.grid-N` cannot simply be implemented as `.grid` with a maximum column count if balanced subdivision remains a goal.
|
|
174
|
+
|
|
175
|
+
## Why `auto-fill` does not solve subdivision
|
|
176
|
+
|
|
177
|
+
`auto-fill` differs from `auto-fit` mainly in its treatment of empty tracks.
|
|
178
|
+
|
|
179
|
+
This matters when fewer items exist than the available grid capacity.
|
|
180
|
+
|
|
181
|
+
For example, with a four-column capacity and three items:
|
|
182
|
+
|
|
183
|
+
```text
|
|
184
|
+
auto-fit
|
|
185
|
+
[A ][B ][C ]
|
|
186
|
+
|
|
187
|
+
auto-fill
|
|
188
|
+
[A][B][C][ ]
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`auto-fill` can therefore preserve card width on a partial final page instead of expanding the remaining items.
|
|
192
|
+
|
|
193
|
+
That is useful behavior for catalogue-like layouts.
|
|
194
|
+
|
|
195
|
+
However, it does not solve the subdivision problem.
|
|
196
|
+
|
|
197
|
+
With six items and enough room for four columns, both mechanisms can still produce:
|
|
198
|
+
|
|
199
|
+
```text
|
|
200
|
+
[A][B][C][D]
|
|
201
|
+
[E][F]
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Neither `auto-fit` nor `auto-fill` understands that three columns would form the more balanced `3 + 3` subdivision.
|
|
205
|
+
|
|
206
|
+
`auto-fill` is therefore not a replacement for the `.grid-N` responsive model.
|
|
207
|
+
|
|
208
|
+
## Historical implementation in 0.3.1
|
|
209
|
+
|
|
210
|
+
Actual CSS 0.3.1 already distinguished intrinsic grids from structural grids.
|
|
211
|
+
|
|
212
|
+
The structural presets changed their column count using container queries.
|
|
213
|
+
|
|
214
|
+
This allowed responsive behavior to depend on the size of the grid's local layout context rather than on the viewport.
|
|
215
|
+
|
|
216
|
+
The important architectural property was:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
query container
|
|
220
|
+
↓
|
|
221
|
+
.grid-N
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
The grid itself remained an ordinary grid item and therefore retained its normal intrinsic sizing behavior.
|
|
225
|
+
|
|
226
|
+
The main drawback was ergonomic: responsive structural grids depended on an explicit ancestor establishing the query container.
|
|
227
|
+
|
|
228
|
+
The requirement looked like an implementation detail in markup, which motivated attempts to make `.grid-N` autonomous in 0.4.
|
|
229
|
+
|
|
230
|
+
The behavior was worth preserving; the mechanism was the part under investigation.
|
|
231
|
+
|
|
232
|
+
## Demoted, not rejected: bounded intrinsic grids
|
|
233
|
+
|
|
234
|
+
One proposed 0.4 design implemented `.grid-N` as an intrinsic `auto-fit` or
|
|
235
|
+
`auto-fill` grid capped at N columns.
|
|
236
|
+
|
|
237
|
+
This removed breakpoints and container-query requirements.
|
|
238
|
+
|
|
239
|
+
It cannot be the whole answer, because it optimizes for available space:
|
|
240
|
+
|
|
241
|
+
```text
|
|
242
|
+
6 -> 5 -> 4 -> 3 -> 2 -> 1
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
where a structural grid is expected to optimize for subdivision:
|
|
246
|
+
|
|
247
|
+
```text
|
|
248
|
+
6 -> 3 -> 2 -> 1
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
The mechanism therefore answers a different question than the one `.grid-N`
|
|
252
|
+
asks.
|
|
253
|
+
|
|
254
|
+
It is nevertheless the right **baseline**. Bounded at N, using `auto-fill`, it
|
|
255
|
+
is responsive, overflow-safe, and equal-width at every state, and it needs
|
|
256
|
+
nothing above Actual's Minimal floor. Adopting it as the unenhanced behavior of
|
|
257
|
+
`.grid-N` is what makes the query container an opt-in for precision rather than
|
|
258
|
+
a prerequisite for responsiveness. This is the single most important difference
|
|
259
|
+
from 0.3.1, where a preset used without a wrapper stayed frozen at N columns
|
|
260
|
+
and was a genuine trap.
|
|
261
|
+
|
|
262
|
+
## Rejected approach: `smart-grid` item-count heuristics
|
|
263
|
+
|
|
264
|
+
Another direction attempted to choose intermediate column counts that avoided orphan rows.
|
|
265
|
+
|
|
266
|
+
For a collection containing `itemCount` items and `c` columns, a one-item final row appears when:
|
|
267
|
+
|
|
268
|
+
```text
|
|
269
|
+
itemCount mod c = 1
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
This observation is useful, but it is not a suitable basis for a generic grid class.
|
|
273
|
+
|
|
274
|
+
The undesirable column counts depend on the actual number of items, not only on the declared grid density.
|
|
275
|
+
|
|
276
|
+
A fixed `.grid-4` class cannot know whether three columns are desirable:
|
|
277
|
+
|
|
278
|
+
* for ten items, three columns produces `3 + 3 + 3 + 1`;
|
|
279
|
+
* for twelve items, three columns produces a perfect `3 + 3 + 3 + 3`.
|
|
280
|
+
|
|
281
|
+
Hard-coding `.grid-4` to skip three columns would encode the answer for one item count and penalize another.
|
|
282
|
+
|
|
283
|
+
More importantly, avoiding a singleton is weaker than balanced subdivision.
|
|
284
|
+
|
|
285
|
+
For six items, four columns gives `4 + 2`. There is no singleton, but `3 + 3` is still structurally preferable.
|
|
286
|
+
|
|
287
|
+
Actual therefore does not attempt to infer an optimal layout from item count in CSS.
|
|
288
|
+
|
|
289
|
+
## Rejected approach: make `.grid-N` its own query container
|
|
290
|
+
|
|
291
|
+
A promising prototype used:
|
|
292
|
+
|
|
293
|
+
```css
|
|
294
|
+
.grid-N {
|
|
295
|
+
container-type: inline-size;
|
|
296
|
+
}
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
and kept a fixed internal track count.
|
|
300
|
+
|
|
301
|
+
Instead of changing `grid-template-columns` on the container, container queries changed `grid-column: span ...` on its children.
|
|
302
|
+
|
|
303
|
+
For a six-track grid:
|
|
304
|
+
|
|
305
|
+
```text
|
|
306
|
+
span 1 → 6 columns
|
|
307
|
+
span 2 → 3 columns
|
|
308
|
+
span 3 → 2 columns
|
|
309
|
+
span 6 → 1 column
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
This successfully produced:
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
6 → 3 → 2 → 1
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
without requiring an external query-container wrapper.
|
|
319
|
+
|
|
320
|
+
It also guaranteed equal-width items.
|
|
321
|
+
|
|
322
|
+
Technically, the mechanism is valid: descendants can query the dimensions of their ancestor query container.
|
|
323
|
+
|
|
324
|
+
However, the solution has a serious side effect.
|
|
325
|
+
|
|
326
|
+
### Inline-size containment changes intrinsic sizing
|
|
327
|
+
|
|
328
|
+
`container-type: inline-size` introduces inline-size containment.
|
|
329
|
+
|
|
330
|
+
The contents of the grid no longer contribute normally to the grid's intrinsic inline size.
|
|
331
|
+
|
|
332
|
+
Probes showed the following behavior:
|
|
333
|
+
|
|
334
|
+
| Context | Observed grid width |
|
|
335
|
+
| ------------------------------- | ------------------: |
|
|
336
|
+
| normal block | 1192px |
|
|
337
|
+
| parent grid `auto` track | 992px |
|
|
338
|
+
| parent grid `min-content` track | 48px |
|
|
339
|
+
| flex item with `flex: 0 1 auto` | 48px |
|
|
340
|
+
| `width: fit-content` | 48px |
|
|
341
|
+
| float | 48px |
|
|
342
|
+
| inline-block | 0px |
|
|
343
|
+
|
|
344
|
+
The self-container therefore works when the grid already receives a definite or stretched width, but can collapse almost completely in shrink-to-fit or intrinsic-sizing contexts.
|
|
345
|
+
|
|
346
|
+
This is not merely an artificial CSS edge case.
|
|
347
|
+
|
|
348
|
+
Actual's own composition primitives can create such contexts.
|
|
349
|
+
|
|
350
|
+
For example:
|
|
351
|
+
|
|
352
|
+
```html
|
|
353
|
+
<div class="cluster">
|
|
354
|
+
<div class="grid-4">...</div>
|
|
355
|
+
</div>
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
`.cluster` is a wrapping flex row whose children retain normal `flex: 0 1 auto` sizing.
|
|
359
|
+
|
|
360
|
+
A self-contained `.grid-4` can therefore exhibit exactly the collapse observed in the probe.
|
|
361
|
+
|
|
362
|
+
Similar intrinsic-sizing concerns exist when a structural grid participates in auto-sized tracks or other shrink-to-fit compositions.
|
|
363
|
+
|
|
364
|
+
### Why this approach is rejected
|
|
365
|
+
|
|
366
|
+
Making `.grid-N` its own query container removes an explicit wrapper at the cost of changing the fundamental sizing behavior of the primitive.
|
|
367
|
+
|
|
368
|
+
That trade-off is not acceptable for a composable layout library.
|
|
369
|
+
|
|
370
|
+
Attempts to compensate with `contain-intrinsic-size`, special rules for `.cluster`, or other context-specific fixes would add complexity and create coupling between otherwise independent primitives.
|
|
371
|
+
|
|
372
|
+
The self-container approach is therefore rejected.
|
|
373
|
+
|
|
374
|
+
## Why an external query container is not merely a workaround
|
|
375
|
+
|
|
376
|
+
A size container query cannot make an element react to its own size without applying containment to that element.
|
|
377
|
+
|
|
378
|
+
Placing the query container on an ancestor preserves the intrinsic sizing behavior of `.grid-N` while still allowing the grid to react to local available space.
|
|
379
|
+
|
|
380
|
+
The relationship is:
|
|
381
|
+
|
|
382
|
+
```text
|
|
383
|
+
.container-query
|
|
384
|
+
↓ observes local available width
|
|
385
|
+
.grid-N
|
|
386
|
+
↓ changes structural subdivision
|
|
387
|
+
items
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
The extra ancestor is therefore not accidental ceremony.
|
|
391
|
+
|
|
392
|
+
It represents a real boundary imposed by the CSS containment model.
|
|
393
|
+
|
|
394
|
+
Actual should not hide that boundary if hiding it requires changing the sizing semantics of the grid.
|
|
395
|
+
|
|
396
|
+
## Out of scope: explicit per-region placement
|
|
397
|
+
|
|
398
|
+
Editorial or application layouts that need arbitrary per-region spans and starts
|
|
399
|
+
are outside the `.grid` / `.grid-N` collection contract. Both primitives lay out
|
|
400
|
+
uniform peers; neither expresses "this region occupies seven units starting at
|
|
401
|
+
the third".
|
|
402
|
+
|
|
403
|
+
That case is answered by `.column-layout`, an opt-in twelve-column coordinate
|
|
404
|
+
system with no automatic responsive behavior. See `column-layout.md`. It also
|
|
405
|
+
narrows `--grid-columns` to its intended role: track templates whose sizes carry
|
|
406
|
+
meaning, rather than a stand-in for a coordinate system.
|
|
407
|
+
|
|
408
|
+
## Progressive enhancement
|
|
409
|
+
|
|
410
|
+
Container queries are newer than Actual's Minimal browser baseline.
|
|
411
|
+
|
|
412
|
+
Structural grids must therefore have a usable fallback without them.
|
|
413
|
+
|
|
414
|
+
The fallback should remain structurally valid and readable. It does not need to reproduce the full responsive subdivision behavior.
|
|
415
|
+
|
|
416
|
+
Modern browsers may enhance the grid when it is placed inside a query container.
|
|
417
|
+
|
|
418
|
+
This follows Actual's general compatibility rule:
|
|
419
|
+
|
|
420
|
+
> Modern CSS should not raise the Minimal baseline when a progressive fallback is possible at low cost.
|
|
421
|
+
|
|
422
|
+
## Relationship with `--grid-min`
|
|
423
|
+
|
|
424
|
+
`--grid-min` belongs naturally to `.grid`.
|
|
425
|
+
|
|
426
|
+
It expresses the minimum desirable width of an item in a space-driven collection.
|
|
427
|
+
|
|
428
|
+
Structural `.grid-N` presets are different: their behavior is driven by a known count and a predefined subdivision sequence.
|
|
429
|
+
|
|
430
|
+
Trying to derive their container-query thresholds from `--grid-min` is not currently practical because size container-query conditions cannot use arbitrary custom-property values as their thresholds.
|
|
431
|
+
|
|
432
|
+
The APIs should therefore remain conceptually separate:
|
|
433
|
+
|
|
434
|
+
```text
|
|
435
|
+
.grid
|
|
436
|
+
input: --grid-min
|
|
437
|
+
strategy: available-space driven
|
|
438
|
+
|
|
439
|
+
.grid-N
|
|
440
|
+
input: structural density N
|
|
441
|
+
strategy: divisor-driven subdivision
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
The fact that both produce CSS Grid layouts does not mean they require the same responsive algorithm.
|
|
445
|
+
|
|
446
|
+
## Supported structural densities
|
|
447
|
+
|
|
448
|
+
The current useful presets are:
|
|
449
|
+
|
|
450
|
+
```text
|
|
451
|
+
2 → 1
|
|
452
|
+
3 → 1
|
|
453
|
+
4 → 2 → 1
|
|
454
|
+
6 → 3 → 2 → 1
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Not every integer necessarily deserves a preset.
|
|
458
|
+
|
|
459
|
+
For example, five has only trivial divisors:
|
|
460
|
+
|
|
461
|
+
```text
|
|
462
|
+
5 → 1
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
Adding `.grid-5` would either produce an abrupt transition or require introducing non-divisor heuristics such as `5 → 2 → 1`.
|
|
466
|
+
|
|
467
|
+
Actual should not add structural presets merely to complete a numerical sequence.
|
|
468
|
+
|
|
469
|
+
New presets should have a clear layout use case and a defensible subdivision chain.
|
|
470
|
+
|
|
471
|
+
## Thresholds are visual design decisions
|
|
472
|
+
|
|
473
|
+
The subdivision chain can be derived from the structural density.
|
|
474
|
+
|
|
475
|
+
The width thresholds at which transitions occur cannot.
|
|
476
|
+
|
|
477
|
+
Values such as:
|
|
478
|
+
|
|
479
|
+
```text
|
|
480
|
+
28rem
|
|
481
|
+
48rem
|
|
482
|
+
64rem
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
must be validated against realistic Actual content rather than inherited mechanically from historical breakpoints.
|
|
486
|
+
|
|
487
|
+
Before changing structural-grid thresholds, probes should verify:
|
|
488
|
+
|
|
489
|
+
* realistic cards rather than empty boxes;
|
|
490
|
+
* narrow parent inside a wide viewport;
|
|
491
|
+
* every expected subdivision state;
|
|
492
|
+
* equal item widths;
|
|
493
|
+
* full and partial rows;
|
|
494
|
+
* interaction with common Actual composition primitives;
|
|
495
|
+
* fallback behavior without container-query support.
|
|
496
|
+
|
|
497
|
+
The viewport itself should not determine the result; the relevant local container should.
|
|
498
|
+
|
|
499
|
+
## API guidance
|
|
500
|
+
|
|
501
|
+
Use `.grid` when the number of columns should emerge naturally from available space.
|
|
502
|
+
|
|
503
|
+
Use `.grid-N` when the declared density and its balanced subdivisions are part of the intended composition.
|
|
504
|
+
|
|
505
|
+
Use structural grids for uniform peer items. They are not intended as editorial grids with arbitrary per-item spans.
|
|
506
|
+
|
|
507
|
+
Do not use CSS layout heuristics to compensate for a pagination size that produces undesirable full-page distributions when the server already knows the item count.
|
|
508
|
+
|
|
509
|
+
## Decision
|
|
510
|
+
|
|
511
|
+
Actual keeps two different grid contracts.
|
|
512
|
+
|
|
513
|
+
```text
|
|
514
|
+
.grid
|
|
515
|
+
intrinsic
|
|
516
|
+
space-driven
|
|
517
|
+
auto-fit
|
|
518
|
+
configurable through --grid-min
|
|
519
|
+
no guarantee of balanced rows
|
|
520
|
+
|
|
521
|
+
.grid-N
|
|
522
|
+
structural
|
|
523
|
+
count-driven
|
|
524
|
+
equal-width items
|
|
525
|
+
responsive through natural subdivisions of N
|
|
526
|
+
local-container driven when enhanced
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
A structural grid must not become its own inline-size query container, because doing so breaks intrinsic and shrink-to-fit composition.
|
|
530
|
+
|
|
531
|
+
If local responsive subdivision requires a size container query, that query container must remain outside the structural grid.
|
|
532
|
+
|
|
533
|
+
The explicit container boundary is preferable to hidden containment side effects.
|
|
534
|
+
|
|
535
|
+
The guiding principle is:
|
|
536
|
+
|
|
537
|
+
> `.grid` optimizes for available space. `.grid-N` optimizes for balanced subdivision.
|
|
538
|
+
|
|
539
|
+
Future grid changes should preserve that distinction unless the public contract itself is intentionally reconsidered.
|
|
540
|
+
|
|
541
|
+
## Resolution
|
|
542
|
+
|
|
543
|
+
`.grid-N` is a bounded `auto-fill` grid by default, and a divisor-chain grid
|
|
544
|
+
inside a query container.
|
|
545
|
+
|
|
546
|
+
```text
|
|
547
|
+
.grid space-driven, auto-fit, --grid-min
|
|
548
|
+
.grid-N count-driven baseline, auto-fill bounded at N,
|
|
549
|
+
may pass through non-divisor column counts
|
|
550
|
+
.container-query .grid-N balanced subdivision, N -> divisors of N -> 1
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
The whole enhancement lives inside `@supports (container-type: inline-size)`.
|
|
554
|
+
Browsers below the floor get the baseline whether or not a wrapper is present,
|
|
555
|
+
which removes the parallel `@media` block 0.3.1 had to maintain in lockstep
|
|
556
|
+
with its container thresholds.
|
|
557
|
+
|
|
558
|
+
### `--grid-min` is not a `.grid-N` hook
|
|
559
|
+
|
|
560
|
+
`@container` thresholds cannot resolve a custom property. A hook honored in the
|
|
561
|
+
baseline would therefore fall silent the moment an author added a query
|
|
562
|
+
container — exactly the kind of hidden, position-dependent contract this
|
|
563
|
+
redesign set out to remove. The baseline hard-codes `16rem` instead.
|
|
564
|
+
|
|
565
|
+
The resulting API split is the clearer one anyway: item width is `.grid`'s
|
|
566
|
+
contract, column density is `.grid-N`'s.
|
|
567
|
+
|
|
568
|
+
### Thresholds
|
|
569
|
+
|
|
570
|
+
Three shared steps, not one calibrated per preset:
|
|
571
|
+
|
|
572
|
+
```text
|
|
573
|
+
28rem first horizontal density .grid-2, .grid-4, .grid-6 -> 2 columns
|
|
574
|
+
48rem three columns .grid-3, .grid-6 -> 3 columns
|
|
575
|
+
64rem dense densities .grid-4 -> 4, .grid-6 -> 6
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
An earlier draft tuned each final step so that every preset landed an item
|
|
579
|
+
around 240px, which put `.grid-6` at 80rem or 96rem. That was the wrong
|
|
580
|
+
optimization, and worth recording so it is not re-derived.
|
|
581
|
+
|
|
582
|
+
Calibrating every preset to the same item width erases the information N
|
|
583
|
+
carries. An author does not reach for `.grid-N` to say *I have N things*; they
|
|
584
|
+
say *my content suits this density*. `.grid-6` should reach six columns early
|
|
585
|
+
precisely because choosing it is a statement that the items are compact. At
|
|
586
|
+
96rem an item is back to `.grid`'s 16rem default, and the preset has no reason
|
|
587
|
+
to exist.
|
|
588
|
+
|
|
589
|
+
The right probe is therefore each preset against the content it targets, not
|
|
590
|
+
one specimen across all of them:
|
|
591
|
+
|
|
592
|
+
| Preset | Probed with | Item at its final step | Result |
|
|
593
|
+
| --------- | ---------------------------------- | ---------------------- | ------ |
|
|
594
|
+
| `.grid-2` | large card, summary, action | 218px @ 28rem | clean |
|
|
595
|
+
| `.grid-3` | standard card | 248px @ 48rem | clean |
|
|
596
|
+
| `.grid-4` | compact card, stat | 247px @ 64rem | clean |
|
|
597
|
+
| `.grid-6` | stat, avatar, thumbnail, icon tile | 161px @ 64rem | clean |
|
|
598
|
+
|
|
599
|
+
161px is small for a card with a heading and a paragraph — and that is the
|
|
600
|
+
point. A preset that needs 250px per item is `.grid-4`, not `.grid-6`.
|
|
601
|
+
|
|
602
|
+
The framework does not guess appropriate item size. The author states it by
|
|
603
|
+
choosing a density; the framework then guarantees a clean structural collapse
|
|
604
|
+
of that density.
|
|
605
|
+
|
|
606
|
+
### Why there is no `.grid-5`
|
|
607
|
+
|
|
608
|
+
The divisors of five are five and one, so the chain would be `5 -> 1` with no
|
|
609
|
+
intermediate state. The system exposes densities that subdivide well, not every
|
|
610
|
+
integer. Proposals to give `.grid-5` a hand-picked `5 -> 2 -> 1` chain are
|
|
611
|
+
covered by the rejected `smart-grid` section above: those steps encode an
|
|
612
|
+
assumption about item count that the class cannot verify.
|
|
@@ -37,3 +37,18 @@ Actual CSS is intended for new projects. Existing projects with class collisions
|
|
|
37
37
|
- Shared runtime primitives may have public JavaScript APIs without becoming author-facing CSS or HTML vocabulary. Do not introduce `.surface` or `data-surface-*`; components keep their feature-specific author APIs (`data-flyout-*`, `data-context-menu-*`, CSS `.flyout`, `.menu`, …).
|
|
38
38
|
- `data-enhance` is the one un-namespaced attribute — it carries *opt-in* for any feature, not *configuration* for one feature. Feature-namespaced attributes carry configuration.
|
|
39
39
|
- Custom events use the `actual:*` namespace.
|
|
40
|
+
|
|
41
|
+
## Utilities
|
|
42
|
+
|
|
43
|
+
Utilities ship in two layers that follow the same class grammar.
|
|
44
|
+
|
|
45
|
+
- **Base utilities** are a curated set of common ergonomic shortcuts
|
|
46
|
+
(`.overflow-auto`, `.gap-none`, `.text-nowrap`, `.px`, `.py`).
|
|
47
|
+
- **Optional utilities** use explicit property/value names
|
|
48
|
+
(`.overflow-hidden`, `.gap-sm`, `.white-space-normal`).
|
|
49
|
+
|
|
50
|
+
Base utilities may use compact names for a small set of frequent operations
|
|
51
|
+
(`.px`, `.py`, `.mbs`, `.mbe`). Extra utilities use explicit property/value
|
|
52
|
+
names and must not duplicate an operation already provided by base. The two
|
|
53
|
+
sets may cover the same CSS property, but must not expose competing names for
|
|
54
|
+
the same declaration.
|
|
@@ -7,6 +7,7 @@ The JS runtime doubles as a primitive kit for building custom widgets.
|
|
|
7
7
|
| Need | Primitive | Import |
|
|
8
8
|
|------|-----------|--------|
|
|
9
9
|
| Opt-in discovery + lifecycle + cleanup | `enhance`, `registerEnhancement` | `actual-css/js/enhance` |
|
|
10
|
+
| Per-document LIFO Escape dismissal | `escape` (`registerEscapeDismissal`) | `actual-css/js/escape` |
|
|
10
11
|
| Positioning, flip/shift, `--available-height`, `data-placement` | `floating` (`track`, `reposition`, `repositionAt`) | `actual-css/js/floating` |
|
|
11
12
|
| Open/close, sheet on mobile, backdrop, outside-click, Escape, focus restore | `surface` | `actual-css/js/surface` |
|
|
12
13
|
| Directional item lookup, edges, wrapping, RTL | `keys` (`itemForKey`, `firstItem`, `lastItem`, `nextItem`) | `actual-css/js/keys` |
|
package/docs/navigation.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
"slug": "guides",
|
|
6
6
|
"pages": [
|
|
7
7
|
"introduction",
|
|
8
|
-
"
|
|
8
|
+
"integrating-actual-css",
|
|
9
|
+
"modular-import",
|
|
9
10
|
"progressive-enhancement",
|
|
10
11
|
"bootstrap",
|
|
11
12
|
"tailwind"
|
|
@@ -21,15 +22,18 @@
|
|
|
21
22
|
"slug": "layout",
|
|
22
23
|
"pages": [
|
|
23
24
|
"overview",
|
|
25
|
+
"choosing",
|
|
24
26
|
"stack",
|
|
25
27
|
"cluster",
|
|
26
28
|
"grid",
|
|
29
|
+
"column-layout",
|
|
27
30
|
"center",
|
|
28
31
|
"sidebar-layout",
|
|
29
32
|
"media",
|
|
30
33
|
"switcher",
|
|
31
34
|
"topbar",
|
|
32
35
|
"scroll-snap",
|
|
36
|
+
"scroll-target",
|
|
33
37
|
"frame",
|
|
34
38
|
"app-shell",
|
|
35
39
|
"list"
|