its-swiss 0.3.0 → 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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +48 -0
- data/README.md +62 -18
- data/app/assets/stylesheets/its_swiss/components.css +84 -27
- data/app/assets/stylesheets/its_swiss/grid.css +2 -2
- data/app/assets/stylesheets/its_swiss/specimen.css +9 -7
- data/app/assets/stylesheets/its_swiss/tokens.css +42 -19
- data/app/assets/stylesheets/its_swiss/type.css +27 -12
- data/app/views/its_swiss/specimen/_figure.html.erb +15 -0
- data/app/views/its_swiss/specimen/_grid.html.erb +1 -1
- data/app/views/its_swiss/specimen/_take.html.erb +1 -0
- data/app/views/its_swiss/specimen/_type.html.erb +8 -5
- data/lib/generators/its_swiss/install/templates/theme.css +9 -1
- data/lib/its_swiss/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d30726333f8265818004958fdb2276a6421ee240b3fbc0b7fc977adf1f39ddb3
|
|
4
|
+
data.tar.gz: 73e52320a14d39e0cb6da2fc22c8b55de7a57167d746a650232c603d12a7d7fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b8c711d2e82584e464c4bc47777a6340a118d53165e20664aff36ab5a43b582273dc60e7f13bbeb55de368054f9e7e9924d637e164d10608db09f1ef97f38631
|
|
7
|
+
data.tar.gz: 6dc95c59d9c700ac68c18c2f8915e0a44e2a79d3701fdaa30ea579ec024cb39a65379498ee40f778f09fa2d3575b3830f6c4eec9e626c586d6e1e443acb71ee0
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
Semver. Consumers pin `~> 0.1`.
|
|
4
4
|
|
|
5
|
+
## 0.4.0 — 2026-08-31
|
|
6
|
+
|
|
7
|
+
**Breaking.** The baseline is now the line, not a third of it. Applications
|
|
8
|
+
setting `--baseline` need to set `--line` instead; everything else follows.
|
|
9
|
+
|
|
10
|
+
### The grid
|
|
11
|
+
|
|
12
|
+
0.3.0 put the type on a baseline grid and then registered it to eight pixels —
|
|
13
|
+
a third of the body line. A block could be a whole number of thirds and still
|
|
14
|
+
land every line of type after it somewhere new, which is what a label on a
|
|
15
|
+
sixteen-pixel leading and a section head on thirty-two did, all the way down a
|
|
16
|
+
column. A third of a line is a spacing unit. It is not a baseline.
|
|
17
|
+
|
|
18
|
+
- **`--line` (24px) replaces `--baseline` (8px)** as the interval everything
|
|
19
|
+
vertical registers to. It is also the body leading, because in a baseline
|
|
20
|
+
grid those are one number.
|
|
21
|
+
- **Every leading is a whole number of lines.** `h1` and `h2` move from 40 and
|
|
22
|
+
32 to 48; the page title from 48 to 72; labels and captions from 16 to 24.
|
|
23
|
+
The page is airier, and that is what the convention looks like.
|
|
24
|
+
- **`--line-2`, `--line-3`, `--line-4`, `--line-6`** for whole-line spacing.
|
|
25
|
+
`--space-*` survives, renamed at its root to `--space-unit`, as the
|
|
26
|
+
**horizontal** step: an inline gap has no baseline to miss.
|
|
27
|
+
- **`--half-line` and `.subgrid`**, the one subgrid, for a block of small
|
|
28
|
+
type. It halves `--line` for the block's *children* — the block's own
|
|
29
|
+
margins belong to the column outside it and are owed whole lines. Declaring
|
|
30
|
+
it on the block itself halved the gap above it and landed the column half a
|
|
31
|
+
line out, which the specimen caught.
|
|
32
|
+
|
|
33
|
+
### Pictures, rules, controls
|
|
34
|
+
|
|
35
|
+
- **`.figure` puts a picture on the line at any width.** Its box is the
|
|
36
|
+
natural height taken up to the next whole line with `round()`, recomputed as
|
|
37
|
+
the container resizes; the picture is fitted inside with `contain`, so
|
|
38
|
+
nothing of it is lost. `.figure--cover` crops instead. `--ratio` is the
|
|
39
|
+
application's to declare. Tested at four widths.
|
|
40
|
+
- `hr` is a line-tall box rather than a rule with margins either side.
|
|
41
|
+
- A text control is two lines of box: one the text sits on, one the rule
|
|
42
|
+
closes. A checkbox is reset out of that, since the browser draws it at a
|
|
43
|
+
size of its own.
|
|
44
|
+
|
|
45
|
+
### Guards
|
|
46
|
+
|
|
47
|
+
- The box test measures in lines, and honours `.subgrid` — a block that
|
|
48
|
+
declares a half-line may use one; the block itself still owes whole lines.
|
|
49
|
+
- A picture is measured at 1400, 1100, 903 and 712 pixels wide.
|
|
50
|
+
- `--baseline` may not reappear in the library. A token that no longer means
|
|
51
|
+
what it says is worse than one that is gone.
|
|
52
|
+
|
|
5
53
|
## 0.3.0 — 2026-09-01
|
|
6
54
|
|
|
7
55
|
The vertical rhythm, twice: once to put every box on the baseline, and again
|
data/README.md
CHANGED
|
@@ -62,34 +62,39 @@ holding all of them. Nothing here has a default the gem could pick honestly.
|
|
|
62
62
|
| `--accent`, `--accent-ink` | State and emphasis only. Unset, the accent is ink |
|
|
63
63
|
| `--font-family` | The typeface. The gem ships none — declare `@font-face` and name it |
|
|
64
64
|
| `--value-chroma`, `--value-hue` | Warms the whole value scale together. Neutral as shipped |
|
|
65
|
-
| `--columns`, `--gutter
|
|
65
|
+
| `--columns`, `--gutter` | How many fields this problem has |
|
|
66
|
+
| `--line` | The baseline: the interval everything vertical registers to |
|
|
67
|
+
| `--ratio` | A picture's aspect ratio, per figure — the library cannot read one |
|
|
66
68
|
| `--cap-correction` | Read, not set: what a trimmed register adds above its cap to reach the next baseline |
|
|
67
69
|
|
|
68
70
|
### The baseline
|
|
69
71
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
`--line` (24px) is the interval everything vertical registers to, and the
|
|
73
|
+
leading of the body text. In this style those are one number, because that is
|
|
74
|
+
what a baseline grid is: Müller-Brockmann's horizontal lines are one line of
|
|
75
|
+
text apart and a field is a whole number of them.
|
|
72
76
|
|
|
73
|
-
|
|
74
|
-
`--
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
caption and a paragraph can both be in step and still be three pixels out of
|
|
78
|
-
register with each other.
|
|
77
|
+
Every leading is `var(--line)` or a whole multiple of it — `--line-2`,
|
|
78
|
+
`--line-3`, `--line-4`, `--line-6`. Every margin, padding and gap on the
|
|
79
|
+
vertical axis is too. `--space-*` survives as the **horizontal** step: an
|
|
80
|
+
inline gap has no baseline to miss.
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
Boxes in step are only the easy half. Where a line's baseline falls inside its
|
|
83
|
+
line box depends on the font's ascent and the leading either side of it, so a
|
|
84
|
+
caption and a paragraph can both be in step and still be out of register with
|
|
85
|
+
each other. So every text register is trimmed to its own type: `text-box:
|
|
86
|
+
trim-both cap alphabetic` makes a block's over edge the cap of its first line
|
|
87
|
+
and its under edge the baseline of its last, and one padding rounds the cap
|
|
88
|
+
height up to the next line —
|
|
84
89
|
|
|
85
90
|
```css
|
|
86
|
-
padding-block-start: calc(round(up, 1cap, var(--
|
|
91
|
+
padding-block-start: calc(round(up, 1cap, var(--line)) - 1cap);
|
|
87
92
|
```
|
|
88
93
|
|
|
89
94
|
— which the browser computes in cap units, so the library still never has to
|
|
90
95
|
be told the font's metrics. It is published as `--cap-correction`: a component
|
|
91
96
|
that sets its own padding on trimmed text adds it, as
|
|
92
|
-
`calc(var(--
|
|
97
|
+
`calc(var(--half-line) + var(--cap-correction))`, which is the right padding
|
|
93
98
|
whether or not the browser trims.
|
|
94
99
|
|
|
95
100
|
Two things opt out, with `text-box: normal; padding-block-start: 0`: a control,
|
|
@@ -99,8 +104,25 @@ content is not type — an image, a swatch, a diagram.
|
|
|
99
104
|
It is behind `@supports`, and the fallback is the box rhythm above. Chromium
|
|
100
105
|
and Safari trim; Firefox does not yet. The two do not render identically:
|
|
101
106
|
trimming takes the leading out of a block's own box, so a trimmed page is a
|
|
102
|
-
few pixels tighter per block
|
|
103
|
-
|
|
107
|
+
few pixels tighter per block. Both stay on the grid.
|
|
108
|
+
|
|
109
|
+
#### The one subgrid
|
|
110
|
+
|
|
111
|
+
A block of small type may sit on a half-line — a dense run of captions, a
|
|
112
|
+
table of figures:
|
|
113
|
+
|
|
114
|
+
```html
|
|
115
|
+
<div class="subgrid">…</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
It halves `--line` for the block's **children**, and the leadings, the spacing
|
|
119
|
+
and the cap correction all follow. The children, not the block: a block's own
|
|
120
|
+
margins belong to the column outside it and are owed whole lines. Set on the
|
|
121
|
+
block itself it halves the gap above it and lands the column half a line out.
|
|
122
|
+
|
|
123
|
+
A block, and only a block. An inline `<small>` shares its paragraph's line and
|
|
124
|
+
must not change it.
|
|
125
|
+
|
|
104
126
|
|
|
105
127
|
### The value scale
|
|
106
128
|
|
|
@@ -136,6 +158,27 @@ Within three units a channel, which is the cost of the four hand-picked
|
|
|
136
158
|
values becoming one ladder with a single chroma and a single hue. Measured in
|
|
137
159
|
Chromium, not calculated.
|
|
138
160
|
|
|
161
|
+
### Pictures
|
|
162
|
+
|
|
163
|
+
The one case that nearly does not transfer from print. A picture's height is
|
|
164
|
+
its fluid width over its ratio, so without help one picture puts the whole
|
|
165
|
+
column below it off the grid at every width but a few.
|
|
166
|
+
|
|
167
|
+
```html
|
|
168
|
+
<figure class="figure" style="--ratio: 1.618">
|
|
169
|
+
<img src="…" alt="…">
|
|
170
|
+
<figcaption class="micro">…</figcaption>
|
|
171
|
+
</figure>
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The box is the picture's natural height taken up to the next whole line, by
|
|
175
|
+
`round()`, recomputed as the container resizes. The picture is fitted inside
|
|
176
|
+
it — `contain` by default, because a library must not crop an image it did not
|
|
177
|
+
choose. `.figure--cover` crops instead, which is the Müller-Brockmann move and
|
|
178
|
+
yours to make where you own the picture.
|
|
179
|
+
|
|
180
|
+
`--ratio` is yours to declare; CSS cannot read an intrinsic one.
|
|
181
|
+
|
|
139
182
|
### The grid
|
|
140
183
|
|
|
141
184
|
The gem ships primitives and never a grid.
|
|
@@ -298,7 +341,8 @@ ladder; the names are the library's rather than the application's.
|
|
|
298
341
|
| `--ink-quiet`, `--ink` | unchanged |
|
|
299
342
|
| `--accent` | unchanged — still the application's to set |
|
|
300
343
|
| `--font` | `--font-family` |
|
|
301
|
-
| `--size-1..5`, `--space-N`, `--
|
|
344
|
+
| `--size-1..5`, `--space-N`, `--measure`, `--page-max` | unchanged |
|
|
345
|
+
| `--baseline` (8px) | **gone.** `--line` (24px) is the baseline now — see 0.4.0 |
|
|
302
346
|
| `.masthead__nav` | `.nav` |
|
|
303
347
|
| `.channels` | `.pairs` |
|
|
304
348
|
| `.form`, `.field`, `.button*`, `.copy`, `.errors`, `.hint`, `.empty` | unchanged |
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
display: flex;
|
|
22
22
|
flex-wrap: wrap;
|
|
23
23
|
align-items: baseline;
|
|
24
|
-
gap: var(--
|
|
25
|
-
padding-block: var(--
|
|
24
|
+
gap: var(--line) var(--space-4);
|
|
25
|
+
padding-block: var(--line) calc(var(--line) - var(--rule-hair));
|
|
26
26
|
border-bottom: var(--rule-hair) solid var(--rule);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
display: flex;
|
|
47
47
|
flex-wrap: wrap;
|
|
48
48
|
align-items: baseline;
|
|
49
|
-
gap: var(--space-3);
|
|
49
|
+
gap: var(--line) var(--space-3);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
.nav a { text-decoration: none; }
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
is not something a library can know. */
|
|
68
68
|
|
|
69
69
|
.footer {
|
|
70
|
-
margin-top: var(--
|
|
71
|
-
padding-block: calc(var(--
|
|
70
|
+
margin-top: var(--line-4);
|
|
71
|
+
padding-block: calc(var(--line) - var(--rule-hair)) var(--line);
|
|
72
72
|
border-top: var(--rule-hair) solid var(--rule);
|
|
73
73
|
font-size: var(--size-1);
|
|
74
74
|
line-height: var(--space-3);
|
|
@@ -87,14 +87,56 @@
|
|
|
87
87
|
the page. Both weights fit the same box, which is why the heavy one only
|
|
88
88
|
changes the drawing. */
|
|
89
89
|
hr {
|
|
90
|
-
height: var(--
|
|
90
|
+
height: var(--line);
|
|
91
91
|
border: 0;
|
|
92
92
|
border-top: var(--rule-hair) solid var(--rule);
|
|
93
|
-
margin-block: var(--
|
|
93
|
+
margin-block: var(--line) 0;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
hr.rule--heavy { border-top-width: var(--rule-heavy); border-color: var(--ink); }
|
|
97
97
|
|
|
98
|
+
/* --- Pictures -----------------------------------------------------------
|
|
99
|
+
The hard case, and the one place the convention nearly does not transfer.
|
|
100
|
+
In print a picture is cropped to a field, and a field is a whole number
|
|
101
|
+
of lines — Müller-Brockmann sized photographs exactly that way. On screen
|
|
102
|
+
the width is fluid, so the height is a fraction of a moving number and
|
|
103
|
+
lands wherever it lands, and the column below it is off the grid for the
|
|
104
|
+
rest of the page.
|
|
105
|
+
|
|
106
|
+
round() closes that: the box is the picture's natural height taken up to
|
|
107
|
+
the next whole line, recomputed as the container resizes. The picture is
|
|
108
|
+
then fitted inside it — contain by default, because a library must not
|
|
109
|
+
crop an image it did not choose, and the leftover is at most a line of
|
|
110
|
+
space. .figure--cover crops instead, which is the Müller-Brockmann move
|
|
111
|
+
and yours to make where you own the picture.
|
|
112
|
+
|
|
113
|
+
--ratio is the application's to declare. An intrinsic ratio cannot be
|
|
114
|
+
read in CSS, and guessing one is how a picture ends up letterboxed
|
|
115
|
+
against nothing.
|
|
116
|
+
|
|
117
|
+
No @supports: where round() is unknown the declaration drops and the
|
|
118
|
+
picture takes its natural height, which is what it would have done. */
|
|
119
|
+
.figure {
|
|
120
|
+
container-type: inline-size;
|
|
121
|
+
margin-block: var(--line);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.figure > img,
|
|
125
|
+
.figure > svg,
|
|
126
|
+
.figure > video {
|
|
127
|
+
inline-size: 100%;
|
|
128
|
+
block-size: round(up, calc(100cqw / var(--ratio, 1.5)), var(--line));
|
|
129
|
+
object-fit: contain;
|
|
130
|
+
/* The space the rounding adds falls under the picture, where the grid
|
|
131
|
+
wants it, rather than being split above and below it. */
|
|
132
|
+
object-position: left top;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
.figure--cover > img,
|
|
136
|
+
.figure--cover > video { object-fit: cover; }
|
|
137
|
+
|
|
138
|
+
.figure figcaption { margin-block-start: var(--line); }
|
|
139
|
+
|
|
98
140
|
/* --- Table --------------------------------------------------------------
|
|
99
141
|
A grid of values, ruled horizontally and not vertically: the columns are
|
|
100
142
|
already held apart by the type, and a vertical rule between them draws a
|
|
@@ -107,12 +149,12 @@
|
|
|
107
149
|
|
|
108
150
|
.table caption {
|
|
109
151
|
color: var(--ink-quiet);
|
|
110
|
-
margin-bottom: var(--
|
|
152
|
+
margin-bottom: var(--line);
|
|
111
153
|
}
|
|
112
154
|
|
|
113
155
|
.table th,
|
|
114
156
|
.table td {
|
|
115
|
-
padding-block: calc(var(--
|
|
157
|
+
padding-block: calc(var(--half-line) + var(--cap-correction)) calc(var(--half-line) - var(--rule-hair));
|
|
116
158
|
padding-inline-end: var(--space-3);
|
|
117
159
|
border-bottom: var(--rule-hair) solid var(--rule);
|
|
118
160
|
vertical-align: baseline;
|
|
@@ -145,7 +187,7 @@
|
|
|
145
187
|
display: grid;
|
|
146
188
|
grid-template-columns: max-content 1fr;
|
|
147
189
|
column-gap: var(--space-3);
|
|
148
|
-
row-gap:
|
|
190
|
+
row-gap: 0;
|
|
149
191
|
}
|
|
150
192
|
|
|
151
193
|
.pairs dt { font-weight: 700; }
|
|
@@ -157,7 +199,7 @@
|
|
|
157
199
|
row-gap: 0;
|
|
158
200
|
}
|
|
159
201
|
|
|
160
|
-
.pairs--stacked dt { margin-top: var(--
|
|
202
|
+
.pairs--stacked dt { margin-top: var(--line); }
|
|
161
203
|
|
|
162
204
|
.pairs--stacked dt:first-child { margin-top: 0; }
|
|
163
205
|
|
|
@@ -171,7 +213,7 @@
|
|
|
171
213
|
display: flex;
|
|
172
214
|
flex-direction: column;
|
|
173
215
|
align-items: flex-start;
|
|
174
|
-
gap: var(--
|
|
216
|
+
gap: var(--line);
|
|
175
217
|
max-width: var(--measure);
|
|
176
218
|
}
|
|
177
219
|
|
|
@@ -179,20 +221,20 @@
|
|
|
179
221
|
flex-direction: row;
|
|
180
222
|
flex-wrap: wrap;
|
|
181
223
|
align-items: flex-end;
|
|
182
|
-
gap: var(--space-2);
|
|
224
|
+
gap: var(--line) var(--space-2);
|
|
183
225
|
}
|
|
184
226
|
|
|
185
227
|
.field {
|
|
186
228
|
display: flex;
|
|
187
229
|
flex-direction: column;
|
|
188
|
-
gap:
|
|
230
|
+
gap: 0;
|
|
189
231
|
width: 100%;
|
|
190
232
|
}
|
|
191
233
|
|
|
192
234
|
.field--inline {
|
|
193
235
|
flex-direction: row;
|
|
194
236
|
align-items: baseline;
|
|
195
|
-
gap: var(--space-2);
|
|
237
|
+
gap: var(--line) var(--space-2);
|
|
196
238
|
}
|
|
197
239
|
|
|
198
240
|
.field input,
|
|
@@ -206,25 +248,40 @@
|
|
|
206
248
|
font: inherit;
|
|
207
249
|
/* No padding above it: the rule belongs under the text, not a line's
|
|
208
250
|
height below it, or the label reads as belonging to nothing. */
|
|
209
|
-
|
|
251
|
+
block-size: var(--line-2);
|
|
252
|
+
/* The rule sits a whole line under the text rather than a few pixels
|
|
253
|
+
under it. A control is two lines of box: one the text is set on, one
|
|
254
|
+
the rule closes. */
|
|
255
|
+
padding-block: 0 calc(var(--line) - var(--rule-hair));
|
|
210
256
|
}
|
|
211
257
|
|
|
212
258
|
/* A select takes its height from the browser rather than from the leading
|
|
213
259
|
it was given — `font: inherit` hands it the family and the size and puts
|
|
214
260
|
the line box back to normal — so it is the one control told what it is:
|
|
215
261
|
the same four baselines the others come out at. */
|
|
216
|
-
.field select { height: var(--space-4); }
|
|
217
262
|
|
|
218
|
-
|
|
263
|
+
|
|
264
|
+
.field textarea {
|
|
265
|
+
block-size: var(--line-4);
|
|
266
|
+
resize: vertical;
|
|
267
|
+
}
|
|
219
268
|
|
|
220
269
|
/* A checkbox or a radio is the one control whose label sits beside it. */
|
|
221
270
|
.choice {
|
|
222
271
|
display: inline-flex;
|
|
223
272
|
align-items: baseline;
|
|
224
|
-
gap: var(--space-1);
|
|
273
|
+
gap: var(--line) var(--space-1);
|
|
225
274
|
}
|
|
226
275
|
|
|
227
|
-
|
|
276
|
+
/* The browser draws this one at a size of its own, so it takes none of the
|
|
277
|
+
box a text control is given — including the two lines of height, which
|
|
278
|
+
it would otherwise wear as a 48px checkbox. */
|
|
279
|
+
.choice input {
|
|
280
|
+
inline-size: auto;
|
|
281
|
+
block-size: auto;
|
|
282
|
+
border: revert;
|
|
283
|
+
padding-block: 0;
|
|
284
|
+
}
|
|
228
285
|
|
|
229
286
|
/* Refused. The accent is the whole signal here and it is a rule, not a
|
|
230
287
|
fill: the field is still the field. */
|
|
@@ -252,7 +309,7 @@
|
|
|
252
309
|
background: transparent;
|
|
253
310
|
color: var(--ink);
|
|
254
311
|
font-family: inherit;
|
|
255
|
-
padding-block: calc(var(--
|
|
312
|
+
padding-block: calc(var(--half-line) - var(--rule-hair));
|
|
256
313
|
padding-inline: var(--space-2);
|
|
257
314
|
cursor: pointer;
|
|
258
315
|
text-decoration: none;
|
|
@@ -347,9 +404,9 @@
|
|
|
347
404
|
display: flex;
|
|
348
405
|
flex-wrap: wrap;
|
|
349
406
|
align-items: baseline;
|
|
350
|
-
gap:
|
|
351
|
-
margin-top: var(--
|
|
352
|
-
padding-top: calc(var(--
|
|
407
|
+
gap: 0 var(--space-2);
|
|
408
|
+
margin-top: var(--line-2);
|
|
409
|
+
padding-top: calc(var(--line) - var(--rule-hair));
|
|
353
410
|
border-top: var(--rule-hair) solid var(--rule);
|
|
354
411
|
}
|
|
355
412
|
|
|
@@ -376,7 +433,7 @@
|
|
|
376
433
|
|
|
377
434
|
.errors {
|
|
378
435
|
width: 100%;
|
|
379
|
-
padding-top: calc(var(--
|
|
436
|
+
padding-top: calc(var(--line) - var(--rule-heavy));
|
|
380
437
|
border-top: var(--rule-heavy) solid var(--accent);
|
|
381
438
|
}
|
|
382
439
|
|
|
@@ -384,7 +441,7 @@
|
|
|
384
441
|
|
|
385
442
|
.errors ul {
|
|
386
443
|
color: var(--ink-quiet);
|
|
387
|
-
margin-top:
|
|
444
|
+
margin-top: 0;
|
|
388
445
|
}
|
|
389
446
|
|
|
390
447
|
.empty { color: var(--ink-quiet); }
|
|
@@ -413,7 +470,7 @@
|
|
|
413
470
|
left: var(--space-2);
|
|
414
471
|
top: var(--space-2);
|
|
415
472
|
z-index: 1;
|
|
416
|
-
padding-block: calc(var(--
|
|
473
|
+
padding-block: calc(var(--half-line) - var(--rule-hair));
|
|
417
474
|
padding-inline: var(--space-2);
|
|
418
475
|
background: var(--paper);
|
|
419
476
|
border: var(--rule-hair) solid var(--ink);
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
display: flex;
|
|
56
56
|
flex-wrap: wrap;
|
|
57
57
|
align-items: baseline;
|
|
58
|
-
gap: var(--space-2);
|
|
58
|
+
gap: var(--line) var(--space-2);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
/* The same idea turned ninety degrees. */
|
|
62
62
|
.stack {
|
|
63
63
|
display: flex;
|
|
64
64
|
flex-direction: column;
|
|
65
|
-
gap: var(--
|
|
65
|
+
gap: var(--line);
|
|
66
66
|
}
|
|
67
67
|
}
|
|
@@ -5,20 +5,20 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
@layer its-swiss.specimen {
|
|
8
|
-
[data-specimen-take] { margin-top: var(--
|
|
8
|
+
[data-specimen-take] { margin-top: var(--line-4); }
|
|
9
9
|
|
|
10
|
-
[data-specimen] { margin-top: var(--
|
|
10
|
+
[data-specimen] { margin-top: var(--line-2); }
|
|
11
11
|
|
|
12
|
-
[data-specimen] > h3 { margin-bottom: var(--
|
|
12
|
+
[data-specimen] > h3 { margin-bottom: var(--line); }
|
|
13
13
|
|
|
14
|
-
[data-specimen] > * + * { margin-top: var(--
|
|
14
|
+
[data-specimen] > * + * { margin-top: var(--line); }
|
|
15
15
|
|
|
16
16
|
/* A block of value, the height of a line box so it sits on the baseline
|
|
17
17
|
beside the token that names it. */
|
|
18
18
|
.specimen__value {
|
|
19
19
|
display: block;
|
|
20
20
|
width: var(--space-13);
|
|
21
|
-
height: var(--
|
|
21
|
+
height: var(--line);
|
|
22
22
|
box-shadow: inset 0 0 0 var(--rule-hair) color-mix(in oklch, var(--ink) 12%, transparent);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -30,11 +30,13 @@
|
|
|
30
30
|
|
|
31
31
|
/* The field, drawn. Each child is one span, and the bar inside it shows
|
|
32
32
|
where that span starts and stops against the page. */
|
|
33
|
-
|
|
33
|
+
/* Three rows of a half-line, and a half-line under the last, so the
|
|
34
|
+
diagram is a whole number of lines however many rows it draws. */
|
|
35
|
+
.specimen__grid { row-gap: var(--half-line); padding-block-end: var(--half-line); }
|
|
34
36
|
|
|
35
37
|
.specimen__field {
|
|
36
38
|
display: block;
|
|
37
|
-
height: var(--
|
|
39
|
+
height: var(--half-line);
|
|
38
40
|
background: var(--value-2);
|
|
39
41
|
}
|
|
40
42
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* A consuming application fills three slots — the accent, the typeface, and
|
|
8
8
|
* how many fields its grid has. Everything else it inherits, and everything
|
|
9
9
|
* else it can still override, because these are unlayered properties read
|
|
10
|
-
* from inside a layer: setting --
|
|
10
|
+
* from inside a layer: setting --line in the application's own stylesheet
|
|
11
11
|
* reproportions the library without touching it.
|
|
12
12
|
*/
|
|
13
13
|
|
|
@@ -104,24 +104,47 @@
|
|
|
104
104
|
--size-4: 2rem; /* 32 — subhead, large values */
|
|
105
105
|
--size-5: 3rem; /* 48 — page title */
|
|
106
106
|
|
|
107
|
-
/* --- The
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
--
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
--
|
|
123
|
-
--
|
|
124
|
-
--
|
|
107
|
+
/* --- The baseline -----------------------------------------------------
|
|
108
|
+
The interval everything vertical registers to, and the leading of the
|
|
109
|
+
body text. In this style those are one number, because that is what a
|
|
110
|
+
baseline grid is: Müller-Brockmann's horizontal lines are one line of
|
|
111
|
+
text apart, and a field is a whole number of them.
|
|
112
|
+
|
|
113
|
+
0.1.0 called eight pixels the baseline. Eight pixels is a third of the
|
|
114
|
+
body line, so a block could be a whole number of them and still put
|
|
115
|
+
every line of type after it somewhere new — which is what a label at
|
|
116
|
+
sixteen and a section head at thirty-two did, all the way down a
|
|
117
|
+
column. A third of a line is a spacing unit. It is not a baseline. */
|
|
118
|
+
--line: 1.5rem; /* 24 */
|
|
119
|
+
|
|
120
|
+
/* Whole lines, for the vertical axis. Anything that separates two blocks
|
|
121
|
+
is measured in these, or the block below it lands between lines. */
|
|
122
|
+
--line-2: calc(var(--line) * 2); /* 48 */
|
|
123
|
+
--line-3: calc(var(--line) * 3); /* 72 */
|
|
124
|
+
--line-4: calc(var(--line) * 4); /* 96 */
|
|
125
|
+
--line-6: calc(var(--line) * 6); /* 144 */
|
|
126
|
+
|
|
127
|
+
/* The one subgrid. A block of small type may sit on a half-line — and
|
|
128
|
+
only a block: leading belongs to a text role, not to an inline element,
|
|
129
|
+
so a <small> inside a paragraph must not change that paragraph's
|
|
130
|
+
leading. Switched on with .subgrid, which redefines --line for its
|
|
131
|
+
subtree, and everything measured in lines follows it down. */
|
|
132
|
+
--half-line: calc(var(--line) / 2); /* 12 */
|
|
133
|
+
|
|
134
|
+
/* --- Space -------------------------------------------------------------
|
|
135
|
+
The horizontal step. An inline gap has no baseline to miss, so this is
|
|
136
|
+
the one axis a smaller unit belongs on. Named for what it is rather
|
|
137
|
+
than for what it was mistaken for. */
|
|
138
|
+
--space-unit: 0.5rem;
|
|
139
|
+
|
|
140
|
+
--space-1: calc(var(--space-unit) * 1); /* 8 */
|
|
141
|
+
--space-2: calc(var(--space-unit) * 2); /* 16 */
|
|
142
|
+
--space-3: calc(var(--space-unit) * 3); /* 24 */
|
|
143
|
+
--space-4: calc(var(--space-unit) * 4); /* 32 */
|
|
144
|
+
--space-5: calc(var(--space-unit) * 5); /* 40 */
|
|
145
|
+
--space-6: calc(var(--space-unit) * 6); /* 48 */
|
|
146
|
+
--space-8: calc(var(--space-unit) * 8); /* 64 */
|
|
147
|
+
--space-13: calc(var(--space-unit) * 13); /* 104 */
|
|
125
148
|
|
|
126
149
|
/* --- The grid ----------------------------------------------------------
|
|
127
150
|
Primitives, not a grid. Six fields divide into halves and thirds and is
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
font-family: var(--font-family);
|
|
14
14
|
font-size: var(--size-2);
|
|
15
15
|
font-weight: 400;
|
|
16
|
-
line-height: var(--
|
|
16
|
+
line-height: var(--line);
|
|
17
17
|
text-align: left;
|
|
18
18
|
/* A weight the file does not carry is better absent than drawn by the
|
|
19
19
|
browser: a synthesised bold at a large size is visibly a smeared
|
|
@@ -31,17 +31,17 @@
|
|
|
31
31
|
|
|
32
32
|
.page-title {
|
|
33
33
|
font-size: var(--size-5);
|
|
34
|
-
line-height: var(--
|
|
34
|
+
line-height: var(--line-3);
|
|
35
35
|
font-weight: 700;
|
|
36
36
|
letter-spacing: -0.028em;
|
|
37
37
|
text-wrap: balance;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
h1 { font-size: var(--size-4); line-height: var(--
|
|
40
|
+
h1 { font-size: var(--size-4); line-height: var(--line-2); font-weight: 700; letter-spacing: -0.02em; }
|
|
41
41
|
|
|
42
|
-
h2 { font-size: var(--size-3); line-height: var(--
|
|
42
|
+
h2 { font-size: var(--size-3); line-height: var(--line-2); font-weight: 700; letter-spacing: -0.015em; }
|
|
43
43
|
|
|
44
|
-
h3, h4 { font-size: var(--size-2); line-height: var(--
|
|
44
|
+
h3, h4 { font-size: var(--size-2); line-height: var(--line); font-weight: 700; }
|
|
45
45
|
|
|
46
46
|
/* The micro register: labels, metadata, captions. Size and value carry it.
|
|
47
47
|
Nothing here is set in capitals — that is a different tradition, and in
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
label,
|
|
53
53
|
.field label {
|
|
54
54
|
font-size: var(--size-1);
|
|
55
|
-
line-height: var(--
|
|
55
|
+
line-height: var(--line);
|
|
56
56
|
letter-spacing: 0.01em;
|
|
57
57
|
}
|
|
58
58
|
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
.micro--tap,
|
|
63
63
|
.choice label,
|
|
64
64
|
.pagination a,
|
|
65
|
-
.pagination [aria-current] { line-height: var(--
|
|
65
|
+
.pagination [aria-current] { line-height: var(--line); }
|
|
66
66
|
|
|
67
67
|
/* Quiet: this is secondary. One rule, so the whole library says it the same
|
|
68
68
|
way and an application adds its own selectors to the list rather than
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
|
|
79
79
|
.hint {
|
|
80
80
|
font-size: var(--size-1);
|
|
81
|
-
line-height: var(--
|
|
81
|
+
line-height: var(--line);
|
|
82
82
|
max-width: var(--measure);
|
|
83
83
|
}
|
|
84
84
|
|
|
@@ -87,12 +87,12 @@
|
|
|
87
87
|
.lede,
|
|
88
88
|
p { max-width: var(--measure); }
|
|
89
89
|
|
|
90
|
-
.lede { margin-top: var(--
|
|
90
|
+
.lede { margin-top: var(--line); }
|
|
91
91
|
|
|
92
92
|
/* Navigation and actions read at body size. They are how an application is
|
|
93
93
|
used, not annotations on it. */
|
|
94
94
|
.nav a,
|
|
95
|
-
.button { font-size: var(--size-2); line-height: var(--
|
|
95
|
+
.button { font-size: var(--size-2); line-height: var(--line); }
|
|
96
96
|
|
|
97
97
|
/* Anything read as a column of digits rather than as a word. */
|
|
98
98
|
.tabular,
|
|
@@ -128,7 +128,7 @@
|
|
|
128
128
|
Safari trim, Firefox does not yet, and a page that keeps its boxes on the
|
|
129
129
|
ladder is what the two have in common. */
|
|
130
130
|
@supports (text-box: trim-both cap alphabetic) and (padding-top: round(up, 1cap, 8px)) {
|
|
131
|
-
:root { --cap-correction: calc(round(up, 1cap, var(--
|
|
131
|
+
:root { --cap-correction: calc(round(up, 1cap, var(--line)) - 1cap); }
|
|
132
132
|
|
|
133
133
|
.page-title,
|
|
134
134
|
h1, h2, h3, h4,
|
|
@@ -166,7 +166,22 @@
|
|
|
166
166
|
leading has never been what draws them.
|
|
167
167
|
|
|
168
168
|
Inline only. A pre is a block, and a block with no leading has no lines. */
|
|
169
|
+
/* The one subgrid. A block of small type may sit on a half-line rather
|
|
170
|
+
than a whole one — a dense run of captions, a table of figures. It works
|
|
171
|
+
by redefining --line for the subtree, so the leadings, the spacing and
|
|
172
|
+
the cap correction all follow it down without any of them being told.
|
|
173
|
+
|
|
174
|
+
A block, and only a block. An inline <small> inside a paragraph shares
|
|
175
|
+
that paragraph's line and must not change it.
|
|
176
|
+
|
|
177
|
+
Declared on the children rather than on the block itself. The block's own
|
|
178
|
+
margins belong to the column outside it and are owed whole lines; only
|
|
179
|
+
what is inside it may halve them. Set on the block, a .subgrid halves the
|
|
180
|
+
gap above itself and lands the column half a line out — which is exactly
|
|
181
|
+
what it did, and what the specimen caught. */
|
|
182
|
+
.subgrid > * { --line: var(--half-line); }
|
|
183
|
+
|
|
169
184
|
code, kbd, samp { line-height: 0; }
|
|
170
185
|
|
|
171
|
-
pre { line-height: var(--
|
|
186
|
+
pre { line-height: var(--line); }
|
|
172
187
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<section data-specimen="figure">
|
|
2
|
+
<h3>Pictures</h3>
|
|
3
|
+
<figure class="figure" style="--ratio: 1.618">
|
|
4
|
+
<svg viewBox="0 0 162 100" role="img" aria-label="A placeholder standing in for a photograph">
|
|
5
|
+
<rect width="162" height="100" fill="var(--value-2)"></rect>
|
|
6
|
+
<rect x="12" y="12" width="60" height="76" fill="var(--value-4)"></rect>
|
|
7
|
+
<rect x="84" y="40" width="66" height="48" fill="var(--value-3)"></rect>
|
|
8
|
+
</svg>
|
|
9
|
+
<figcaption class="micro">
|
|
10
|
+
A picture at 1.618, in a fluid column. Its box is its natural height
|
|
11
|
+
taken up to the next whole line, so the column below it is still on the
|
|
12
|
+
grid — whatever the window is doing.
|
|
13
|
+
</figcaption>
|
|
14
|
+
</figure>
|
|
15
|
+
</section>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<code>--columns: <%= 6 %></code>; a child says how many fields it takes
|
|
6
6
|
with <code>--span</code>, and a child that says nothing runs the field.
|
|
7
7
|
</p>
|
|
8
|
-
<div class="grid specimen__grid">
|
|
8
|
+
<div class="grid specimen__grid subgrid">
|
|
9
9
|
<% 6.times do %><span style="--span: 1"><span class="specimen__field"></span></span><% end %>
|
|
10
10
|
<span style="--span: 2"><span class="specimen__field"></span></span>
|
|
11
11
|
<span style="--span: 4"><span class="specimen__field"></span></span>
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
<%= render "its_swiss/specimen/masthead" %>
|
|
12
12
|
<%= render "its_swiss/specimen/buttons" %>
|
|
13
13
|
<%= render "its_swiss/specimen/form" %>
|
|
14
|
+
<%= render "its_swiss/specimen/figure" %>
|
|
14
15
|
<%= render "its_swiss/specimen/table" %>
|
|
15
16
|
<%= render "its_swiss/specimen/pairs" %>
|
|
16
17
|
<%= render "its_swiss/specimen/pagination" %>
|
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
<h3>Type scale</h3>
|
|
3
3
|
<p class="hint">
|
|
4
4
|
Five sizes on an alternating 1.33 / 1.5 ratio. Every line box is a whole
|
|
5
|
-
number of
|
|
5
|
+
number of lines, so a heading never lands the type under it off the grid.
|
|
6
6
|
</p>
|
|
7
7
|
<%# The rung and the line box it is set on. Written out rather than derived,
|
|
8
8
|
because the ladder is not every whole number: there is no --space-7, and
|
|
9
9
|
asking for one silently drops the line box back to the browser's. %>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
<%# The rung and the number of lines it is set on. Every one is a whole
|
|
11
|
+
number of them, which is the whole of the grid. %>
|
|
12
|
+
<% { 1 => [ "--line", "Labels and metadata" ], 2 => [ "--line", "Body copy" ],
|
|
13
|
+
3 => [ "--line-2", "Section" ], 4 => [ "--line-2", "Subhead" ],
|
|
14
|
+
5 => [ "--line-3", "Page title" ] }.each do |step, (leading, name)| %>
|
|
15
|
+
<p data-size="<%= step %>" style="font-size: var(--size-<%= step %>); line-height: var(<%= leading %>)">
|
|
16
|
+
<%= name %> — <code>--size-<%= step %></code> on <code><%= leading %></code>
|
|
14
17
|
</p>
|
|
15
18
|
<% end %>
|
|
16
19
|
|
|
@@ -34,7 +34,15 @@
|
|
|
34
34
|
they need, and every width in the app re-proportions. */
|
|
35
35
|
--columns: 6;
|
|
36
36
|
--gutter: 1.5rem;
|
|
37
|
-
|
|
37
|
+
|
|
38
|
+
/* --- The baseline ------------------------------------------------------
|
|
39
|
+
The interval everything vertical registers to, and the leading of the
|
|
40
|
+
body text — one number, because that is what a baseline grid is. Change
|
|
41
|
+
it and every leading, every gap and every picture's box follow.
|
|
42
|
+
|
|
43
|
+
A block of small type may sit on a half-line, with class="subgrid". An
|
|
44
|
+
inline <small> may not: it shares its paragraph's line. */
|
|
45
|
+
--line: 1.5rem;
|
|
38
46
|
}
|
|
39
47
|
|
|
40
48
|
/* The grid itself lives here, not in the gem: which blocks span which fields
|
data/lib/its_swiss/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: its-swiss
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Bobby Meyer
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|
|
@@ -120,6 +120,7 @@ files:
|
|
|
120
120
|
- app/views/its_swiss/shared/_masthead.html.erb
|
|
121
121
|
- app/views/its_swiss/shared/_pagination.html.erb
|
|
122
122
|
- app/views/its_swiss/specimen/_buttons.html.erb
|
|
123
|
+
- app/views/its_swiss/specimen/_figure.html.erb
|
|
123
124
|
- app/views/its_swiss/specimen/_footer.html.erb
|
|
124
125
|
- app/views/its_swiss/specimen/_form.html.erb
|
|
125
126
|
- app/views/its_swiss/specimen/_grid.html.erb
|