clairity.css 0.1.2 → 0.2.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.
@@ -11,14 +11,18 @@
11
11
  // -------------------------------------------------------------------------- */
12
12
 
13
13
  /* TODO: moved from components.css; make sure no unintended consequences appear;
14
- sectioning children of body should be .readable by default - keep in sync
15
- with classes.css - [0001] specificity */
14
+ sectioning children of body should be .readable by default so keep in sync
15
+ with .readable in classes.css - [0001] specificity
16
+ // .......................................................................... */
16
17
  body > :where(header, nav, main, section, div, figure, footer) {
17
18
  width: 100%;
18
19
  max-width: var(--line-length); /* for horizontal centering */
19
20
  margin-inline: auto; /* centers if width is set */
20
21
  }
21
22
 
23
+ /* make bare divs in body grid padded by default; should probably go in shims */
24
+ body > :is(section, div) { grid-column: 2/-2; }
25
+
22
26
  /* bare pages should not have grid applied */
23
27
  body:not(:has(main)):has(h1, p) { /* [0003] specificity */
24
28
  display: block;
@@ -52,6 +56,30 @@ nav > menu > li { display: inline; } /* only direct children, as menu
52
56
  text-decoration-style: dotted;
53
57
  }
54
58
 
59
+ body > footer:last-of-type { margin-top: var(--l); }
60
+
61
+
62
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
63
+ /* -----------------------------------------------------------------------------
64
+ // #links - for linking to other documents
65
+ // -------------------------------------------------------------------------- */
66
+
67
+ /* #mailto #tel #sms #file #external #bookmark #download - special link icons -
68
+ this uses the svg mask technique to place & color icons on hover; as such, it
69
+ must be in a separate pseudo-element so masking doesn't bleed out to text */
70
+ /* #icons - set --icon to an svg from icons.css, set color with --icon-color */
71
+ [href^="tel:"] { --icon: var(--i-phone); }
72
+ [href^="sms:"] { --icon: var(--i-message-2); }
73
+ [href^="file:"] { --icon: var(--i-file); }
74
+ [download] { --icon: var(--i-file-download); }
75
+ [href^="mailto:"] { --icon: var(--i-mail); }
76
+ [rel~="external"] { --icon: var(--i-external-link); }
77
+ [rel~="bookmark"] { --icon: var(--i-bookmark); }
78
+
79
+ /* give followed fragment links some room at the top - [0010] specificity */
80
+ [id] { scroll-margin-top: var(--l); }
81
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
82
+
55
83
 
56
84
  /* -----------------------------------------------------------------------------
57
85
  // #lists - ordered and unordered lists of items
@@ -72,6 +100,50 @@ ul:where(:has(li [type="checkbox"], li [type="radio"])) {
72
100
  list-style: none;
73
101
  }
74
102
 
103
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
104
+ /* #ul #ol - removes vertical gaps for lists within lists - uses :where() to get
105
+ [0001] specificity rather than [0002] */
106
+ :where(ul, ol) :is(ul, ol) { margin: 0; }
107
+
108
+
109
+ /* -----------------------------------------------------------------------------
110
+ // #tables - for tabular data
111
+ // -------------------------------------------------------------------------- */
112
+
113
+ /* makes the first column sticky - [0012] specificity */
114
+ :not(tfoot) > tr th:first-of-type {
115
+ position: sticky; /* works best w/ <table> display ≅ block */
116
+ left: 0;
117
+ background-color: var(--background); /* is transparent otherwise */
118
+ }
119
+ /* makes the table header row sticky - [0002] specificity */
120
+ thead th {
121
+ position: sticky;
122
+ top: 0;
123
+ z-index: 1; /* puts header row on top of tbody rows, including
124
+ header column */
125
+ background-color: var(--background); /* is transparent otherwise */
126
+ }
127
+ /* sticks top left box on top of both header columns/rows - [0012] specificity*/
128
+ thead th:first-child { z-index: 2; }
129
+
130
+ /* zebra-striping of table rows - [0013] specificity */
131
+ tbody tr:nth-child(even), tbody tr:nth-child(even) th {
132
+ background-color: var(--bg-contrast);
133
+ }
134
+ /* this is more robust because it excludes hidden rows, but only safari and
135
+ chrome support this syntax - [0023] specificity */
136
+ @supports selector(:nth-child(even of :not([hidden]))) {
137
+ tbody tr:where(:nth-child( even of :not([hidden]) )),
138
+ tbody tr:where(:nth-child( even of :not([hidden]) )) th {
139
+ background-color: var(--bg-contrast);
140
+ }}
141
+
142
+ /* adds sticky borders below thead and above tfoot */
143
+ thead tr:last-of-type th {box-shadow: inset 0 -2px var(--secondary, --neutral);}
144
+ tfoot :where(td, th) {box-shadow: inset 0 2px var(--secondary, --neutral);}
145
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
146
+
75
147
 
76
148
  /* -----------------------------------------------------------------------------
77
149
  // #forms - for submitting data to the server
@@ -79,15 +151,138 @@ ul:where(:has(li [type="checkbox"], li [type="radio"])) {
79
151
 
80
152
  /* #form #section #p #div - would prefer subgrid to have containers layout
81
153
  contents on the grid, but its not yet supported by chrome/edge. use
82
- display: contents; to pierce the grid instead - [0002] specificity
154
+ display: contents; to pierce the grid instead - [0002] specificity
83
155
  // .......................................................................... */
84
- form section, form p, form div {
156
+ form section, form p, form div { /* TODO: should be a shim eventually */
85
157
  display: contents; /* make contents align to form grid */
86
158
  margin: 0; /* let contents, not container, set spacing */
159
+ container-type: unset; /*let contents adjust to outer form container*/
87
160
  }
88
161
  /* #h2 - make form headers/paragraphs span the full width - [0002] specificity*/
89
162
  form h2, form p { grid-column: full; }
90
163
 
164
+ /* #fieldset grid should span full form grid in narrower form containers
165
+ // .......................................................................... */
166
+ @container form (width <= 35rem) {
167
+ fieldset {
168
+ grid-column: full;
169
+ border-inline: none;
170
+ border-color: var(--deemphasized);
171
+ }
172
+ /* #legend should be visually de-emphasized as a separator as well */
173
+ legend {
174
+ border: none;
175
+ margin-bottom: var(--m);
176
+ font-weight: var(--bold);
177
+ }
178
+ }
179
+
180
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
181
+ /* #form #ul - since lists in forms typically list out form controls, remove
182
+ the bullet styling from them - [0002] specificity */
183
+ form ul { list-style: none; }
184
+
185
+ /* #form #section #p #div - extend the subgrid into common, but strictly
186
+ // non-semantic, container elements used within forms - subgrid is firefox 71+ &
187
+ // safari 16+ only 20221001
188
+ // .......................................................................... */
189
+ @supports (grid-template-columns: subgrid) {
190
+ /* :where() can be used here, since @supports is also a recent addition */
191
+ form :where(section, p, div) { /* [0001] specificity */
192
+ grid-column: full;
193
+ display: grid;
194
+ grid-template-columns: subgrid;
195
+ gap: inherit;
196
+ }
197
+
198
+ /* TEMP: swap the grid placement of radio/checkboxes & their labels */
199
+ :where(form) :where(section, p, div) :is([type='checkbox'], [type='radio']) {
200
+ grid-column: labels;
201
+ justify-self: right;
202
+ }
203
+ :where(form) :is(:where(section, p, div)
204
+ :is([type='checkbox'], [type='radio'])+label) {
205
+ grid-column: elements;
206
+ justify-self: left;
207
+ }
208
+ }
209
+ /*form section :where(h1,h2,h3,h4,h5,h6) + p { display: block; }*/
210
+
211
+ /* chrome/edge doesn't support subgrid yet but does support :has() & :where() */
212
+ @supports selector(:has(*)) {
213
+ /* set up a form grid on fieldsets that include form elements */
214
+ fieldset:where(:has(label, input, button, textarea, select, fieldset)) {
215
+ margin: 0;
216
+ display: grid;
217
+ grid-template-columns:[labels full-start] 3fr [elements] 7fr [full-end];
218
+ gap: var(--m);
219
+ }
220
+ /* for fieldsets containing <p> tags that encompass checkboxes/radios, but no
221
+ other form inputs, remove extraneous gap between label and element */
222
+ fieldset:where(:has(p :is([type='checkbox'], [type='radio'])):not(:has(select,
223
+ textarea, [type="text"], [type="date"], [type="email"], [type="password"],
224
+ [type="datetime-local"], [type="search"]))) {
225
+ row-gap: 0;
226
+ }
227
+ /* since grid properties fall through p tags, assign margin-top to first child
228
+ elements to get a gap between paragraphs of different input types */
229
+ fieldset p:has([type='checkbox'], [type='radio']) + p:has([type='radio'],
230
+ [type='checkbox']) :is([type='radio'], [type='checkbox'],
231
+ label):first-of-type {
232
+ margin-top: var(--m);
233
+ }
234
+ /* chrome/edge doesn't support subgrid, so pierce the grid barrier instead */
235
+ fieldset :where(p:has(label, input, button, textarea, select, fieldset)) {
236
+ display: contents;
237
+ }
238
+ /* labels go on the labels gridline */
239
+ :where(fieldset :is(p, div)) label {
240
+ grid-column: labels;
241
+ }
242
+ /* lists that contain radios/checkboxes go on the elements gridline */
243
+ form:has(fieldset :where(select, textarea, [type="text"], [type="date"],
244
+ [type="email"], [type="password"], [type="datetime-local"],
245
+ [type="search"])) fieldset ul:has(li label :where([type='radio'],
246
+ [type='checkbox'])) {
247
+ grid-column: elements;
248
+ }
249
+
250
+ /* inputs on the elements gridline; pad right side away from fieldset line */
251
+ :where(fieldset) :where(p):has(input, button, textarea, select, fieldset)
252
+ :where(input:not(:is([type='checkbox'],[type='radio']), button,
253
+ textarea, select, fieldset)) {
254
+ grid-column: elements;
255
+ margin-right: var(--m);
256
+ }
257
+ /* for radios & checks, invert the placement of the input and label */
258
+ /* NOTE: align-self & justify-self are not properly supported for grid by IE
259
+ anyway, so just use the combined property `place-self` here */
260
+ :where(fieldset) :where(p):has(label) :where([type='checkbox'],
261
+ [type='radio']):has(+ label) {
262
+ grid-column: labels;
263
+ place-self: center end;
264
+ }
265
+ :where(fieldset p:has(label) :is([type='checkbox'],
266
+ [type='radio']):has(+ label)) + label {
267
+ grid-column: elements;
268
+ justify-self: start;
269
+ }
270
+ /* for paragraph tags that aren't form element containers, span the grid */
271
+ :where(fieldset) :where(p, div, h2, h3, h4, h5, h6):not(:has(label, input,
272
+ button, textarea, select, fieldset)) {
273
+ display: block;
274
+ grid-column: full;
275
+ }
276
+ }
277
+ /*form :where(fieldset, input, select, button, input[type="button"]) {
278
+ grid-column: elements;
279
+ }*/
280
+
281
+ fieldset > :last-child {
282
+ margin-bottom: 0;
283
+ }
284
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
285
+
91
286
 
92
287
  /* -----------------------------------------------------------------------------
93
288
  // #selections - dropdown/selection form controls
@@ -99,6 +294,16 @@ select { background-image: var(--i-chevron); }
99
294
  /* only pad options inside optgroups - [0002] specificity */
100
295
  optgroup option { padding: 0 0 0 var(--m); }
101
296
 
297
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
298
+ /* #label for taller #multiple #textarea should align top - firefox 106 still
299
+ doesn't properly support :has() with combinator selectors */
300
+ @supports selector(:has(*)) {
301
+ label:where(:has(+ [multiple],+ textarea,+ select[size])){/*[0001] specificity*/
302
+ vertical-align: top;
303
+ align-self: start;
304
+ }}
305
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
306
+
102
307
 
103
308
  /* -----------------------------------------------------------------------------
104
309
  // #inputs - core form elements
@@ -107,7 +312,7 @@ optgroup option { padding: 0 0 0 var(--m); }
107
312
  /* #label #checkbox - checkboxes inside labels is a common layout - firefox
108
313
  only understands simple :has() selectors, so can't use the direct descendent
109
314
  selector > here until it understands it - [0011] specificity
110
- // ...........................................................................*/
315
+ // .......................................................................... */
111
316
  label:has([type="checkbox"]) {
112
317
  grid-column: elements;
113
318
  justify-self: left;
@@ -119,6 +324,56 @@ label + [type="image"] {
119
324
  vertical-align: middle;
120
325
  }
121
326
 
327
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
328
+ /* if [size] is set on an input, respect that choice - [0011] specificity */
329
+ input[size] {
330
+ width: fit-content;
331
+ min-width: unset;
332
+ max-width: unset;
333
+ }
334
+
335
+ /* -----------------------------------------------------------------------------
336
+ // specialized inputs - #date #time #datetime-local #month #week #datetime
337
+ // #email #password #search #file #image #url #tel #color
338
+ // #range #number #hidden
339
+ // -------------------------------------------------------------------------- */
340
+
341
+ /* input images */
342
+ [type="date"], [type="time"], [type="datetime"], [type="datetime-local"],
343
+ [type="month"], [type="week"], [type="url"], [type="email"],
344
+ [type="number"], [type="tel"], [type="password"], [type="search"] {
345
+ padding-left: var(--height);
346
+ background-blend-mode: var(--icon-blend-mode);
347
+ }
348
+ [type="date"], [type="month"], [type="week"] {
349
+ background-image: var(--colorize-icon), var(--i-calendar); }
350
+ [type="datetime"], [type="datetime-local"], [type="time"] {
351
+ background-image: var(--colorize-icon), var(--i-calendar-time); }
352
+ [type="url"] { background-image: var(--colorize-icon), var(--i-browser); }
353
+ [type="email"] { background-image: var(--colorize-icon), var(--i-mail); }
354
+ [type="number"] { background-image: var(--colorize-icon), var(--i-numbers); }
355
+ [type="tel"] { background-image: var(--colorize-icon), var(--i-phone); }
356
+ [type="password"]{ background-image: var(--colorize-icon), var(--i-lock); }
357
+ [type="search"] { background-image: var(--colorize-icon), var(--i-search); }
358
+
359
+ /* hide nav search's placeholder text if the background icon is present; opacity
360
+ is used here because other methods are disallowed on ::placeholder - [0001]*/
361
+ :where(nav) :where([type="search"])::placeholder { opacity: 0; }
362
+
363
+ /* if radios/checkboxes are inline, insert a gap between them for readability */
364
+ :where([type="radio"] + label, [type="checkbox"] + label) +
365
+ :is([type="radio"], [type="checkbox"]) { /* [0010] specificity */
366
+ margin-left: var(--m);
367
+ }
368
+
369
+ /* search decorations - [0011] specificity */
370
+ [type="search"]::-webkit-search-cancel-button,
371
+ [type="search"]::-webkit-search-decoration {
372
+ appearance: none; /* needed? */
373
+ }
374
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
375
+
376
+
122
377
  /* -----------------------------------------------------------------------------
123
378
  // #blocks - elements that contain text blocks
124
379
  // -------------------------------------------------------------------------- */
@@ -129,6 +384,27 @@ pre > code, xmp {
129
384
  border-radius: 0 var(--radius) var(--radius) 0;
130
385
  }
131
386
 
387
+ /* #blockquote
388
+ // ...........................................................................*/
389
+ blockquote::before { /* [0002] specificity is the least possible here */
390
+ content: open-quote;
391
+ color: var(--pale);
392
+ font-size: 5rem;
393
+ font-family: var(--serif);
394
+ left: var(--xs);
395
+ line-height: 1;
396
+ position: absolute;
397
+ top: 0;
398
+ z-index: -1;
399
+ }
400
+ blockquote > :first-child { /* [0011] specificity */
401
+ margin-top: 0;
402
+ text-indent: var(--m);
403
+ }
404
+ blockquote > :last-child { /* [0011] specificity */
405
+ margin-bottom: 0;
406
+ }
407
+
132
408
 
133
409
  /* -----------------------------------------------------------------------------
134
410
  // #inline elements - elements that occur principally within text blocks.
@@ -149,6 +425,43 @@ pre > code {
149
425
  }
150
426
 
151
427
 
428
+
429
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
430
+ /* #q - inline quotations - note that the closing smart quote is added manually
431
+ here as <q>'s automatic quotes are otherwise added via pseudo elements
432
+ // ...........................................................................*/
433
+ q[cite]::after { content: "” (cf. " attr(cite) ") "; }
434
+
435
+
436
+ /* -----------------------------------------------------------------------------
437
+ // #media / #embedded - elements that add multimedia to a page
438
+ // -------------------------------------------------------------------------- */
439
+
440
+ /* #figure #headings - #h1 #h2 #h3 #h4 #h5 #h6 ~*/
441
+ figure > :where(h1,h2,h3,h4,h5,h6):first-child { margin-top: 0; }
442
+
443
+ /* #blockquote inside #figure - safari only for now - :where is older than :has
444
+ so it can be used here to reduce specificity - [0001] specificity */
445
+ figure:where(:has(blockquote)) {
446
+ background-color: revert;
447
+ }
448
+ /* fix doubled margin of a blockquote in a figure - [0002] specificity */
449
+ figure > blockquote {
450
+ text-align: start;
451
+ margin: var(--ms);
452
+ padding: var(--ms);
453
+ max-width: calc(var(--line-length) - (var(--ms) * 2));
454
+ }
455
+
456
+ /* #svg - [0001] specificity */
457
+ svg:not(:where(:root)) {
458
+ width: var(--m);
459
+ /*max-width: 100%;*/
460
+ overflow: hidden;
461
+ }
462
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
463
+
464
+
152
465
  /* -----------------------------------------------------------------------------
153
466
  // #interactive - built-in interactive components
154
467
  // -------------------------------------------------------------------------- */
@@ -156,3 +469,44 @@ pre > code {
156
469
  /* a method="dialog" #form with a plain <button> closes the dialog without js!*/
157
470
  /* makes form/close button not be full-width - [0010] specificity */
158
471
  [method="dialog"] { width: min-content; }
472
+
473
+ /* TEMP: moved from states.css ++++++++++++++++++++++++++++++++++++++++++++++ */
474
+ /* #dialog - built-in modal overlay - comes with 'Esc' support with no js! */
475
+ /* wrap long dialogs in a container to scroll the body content sans button */
476
+ dialog > :where(div, section, article) {
477
+ overflow-y: auto; /* scrolls as necessary w/ height set */
478
+ max-height: calc(80vh * 0.8); /* container queries needed! */
479
+ }
480
+
481
+ dialog button {
482
+ margin-top: var(--ms);
483
+ }
484
+
485
+ dialog :where(h1, h2, h3, h4, h5, h6) {
486
+ border-bottom: var(--solid) var(--border);
487
+ border-radius: var(--radius) var(--radius) 0 0;
488
+ color: var(--distinct); /* differentiate dialog headings */
489
+ font-size: var(--large); /* dialogs typically only need 1 heading
490
+ level, so make it all the same size */
491
+ margin: 0 0 0 calc(-1 * var(--m)); /* negative left margin
492
+ lines up heading with paragraph text */
493
+ padding: 0 var(--m) var(--m); /* top padding provided by dialog
494
+ padding so remove it here */
495
+ }
496
+
497
+ /* #details - an accordion-like widget for question & answer style layouts */
498
+ details + details {
499
+ border-top: 0;
500
+ border-radius: 0;
501
+ }
502
+
503
+ details:first-of-type {
504
+ border-top-left-radius: var(--radius);
505
+ border-top-right-radius: var(--radius);
506
+ }
507
+
508
+ details:last-of-type {
509
+ border-bottom-left-radius: var(--radius);
510
+ border-bottom-right-radius: var(--radius);
511
+ }
512
+ /* END: moved from states.css +++++++++++++++++++++++++++++++++++++++++++++++ */
@@ -0,0 +1,65 @@
1
+ /******************************************************************************\
2
+ LEGACY - Graceful degradation for "legacy" browsers, which we define as those
3
+ that don't support modern css, not just IE11.
4
+
5
+ We'll generally aim for [0010] specificity here, as that's the default
6
+ specificity of a single class, which can be overridden in later styles
7
+ using just a single class. Exceptions will be marked with their
8
+ specificity, as usual.
9
+
10
+ \******************************************************************************/
11
+
12
+
13
+ /* -----------------------------------------------------------------------------
14
+ // #containers -
15
+ // -------------------------------------------------------------------------- */
16
+
17
+ /* this doesn't work because some items aren't full width, like asides
18
+ body > *:not(.fluid) {
19
+ margin-inline: var(--m);
20
+ }
21
+ */
22
+
23
+
24
+ /* -----------------------------------------------------------------------------
25
+ // #grid -
26
+ // -------------------------------------------------------------------------- */
27
+
28
+
29
+ /* chrome & edge don't support subgrid yet, though in development - 20230423 */
30
+ @supports not (grid-template-columns: subgrid) {
31
+ .subgrid { display: contents; }
32
+ .subgrid :first-child { /* TODO: this breaks some layouts, like banner images */
33
+ /*grid-column-start: 2;*/ /* TODO: fix right side guttering too */
34
+ }}
35
+
36
+
37
+ /* -----------------------------------------------------------------------------
38
+ // #card -
39
+ // -------------------------------------------------------------------------- */
40
+
41
+ /* TEMP: use media queries for browsers that don't support container queries */
42
+ @supports not (container-type: inline-size) {
43
+ @media (min-width: 47rem) {
44
+ /*.card { flex-direction: row; }*/ /* interferes with single-card section */
45
+ .card > img, .cards > article > img {
46
+ max-height: var(--width);
47
+ max-width: var(--width);
48
+ }
49
+ .cards :last-child:nth-child(3n - 2) {
50
+ grid-column-end: span 3;
51
+ flex-direction: row;
52
+ }
53
+ }}
54
+
55
+
56
+ /* -----------------------------------------------------------------------------
57
+ // #tags -
58
+ // -------------------------------------------------------------------------- */
59
+
60
+ /* TEMP: add margin-top to buttons for browsers that don't support :has() */
61
+ @supports not (:has(a)) {
62
+ .tags + .buttons {
63
+ margin-top: var(--m);
64
+ }}
65
+