@anyblades/blades 2.4.8 → 3.0.0-alpha.1
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/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
- package/.github/ISSUE_TEMPLATE/config.yml +8 -0
- package/.prettierrc.json +6 -0
- package/README.md +130 -104
- package/context7.json +4 -0
- package/css/blades.css +454 -198
- package/css/blades.min.css +145 -0
- package/css/blades.standalone.css +216 -272
- package/css/blades.standalone.min.css +37 -0
- package/css/{blades.ninja.css → ninja.css} +7 -2
- package/css/ninja.min.css +5 -0
- package/css/pico.conditional.css +3189 -0
- package/css/pico.conditional.min.css +107 -0
- package/css/pico.css +3186 -0
- package/css/pico.min.css +105 -0
- package/css/postcss.config.js +23 -0
- package/index.html +63 -0
- package/package.json +27 -11
- package/src/blades.css +4 -3
- package/src/blades.standalone.css +2 -2
- package/src/{blades.ninja.css → ninja.css} +7 -2
- package/src/pico/_components.css +974 -0
- package/src/pico/_content.css +608 -0
- package/src/pico/_forms.css +747 -0
- package/src/pico/_index.css +12 -0
- package/src/pico/_layout.css +128 -0
- package/src/pico/_utilities.css +53 -0
- package/src/pico/_variables.css +671 -0
- package/src/pico.css +1 -0
- package/src/standalone/_core.css +32 -0
- package/src/{blades.standalone.theme.css → standalone/_theme.css} +3 -7
- package/src/{_utilities.css → standalone/_utilities.css} +3 -4
- package/src/standalone/_variables.css +20 -0
- package/src/{link-icon.css → standalone/components/_icon-helper.css} +0 -2
- package/src/{components → standalone/components}/_timeline.css +1 -2
- package/src/{content → standalone/content}/_code.css +9 -12
- package/src/{content/_typography.css → standalone/content/_list.css} +4 -49
- package/src/{content → standalone/content}/_table.css +4 -7
- package/src/standalone/content/_typography.css +38 -0
- package/src/{float-label.core.css → standalone/forms/_float-label.core.css} +22 -14
- package/src/standalone/forms/_float-label.css +2 -0
- package/src/{breakout.css → standalone/layout/_breakout.css} +3 -6
- package/src/{_layout.css → standalone/layout/_columns.css} +2 -20
- package/src/standalone/layout/_scroller.css +10 -0
- package/_config.yml +0 -5
- package/blades.gemspec +0 -16
- package/css/blades.standalone.core.css +0 -738
- package/css/blades.standalone.theme.css +0 -147
- package/css/breakout.css +0 -125
- package/css/float-label.core.css +0 -56
- package/css/float-label.css +0 -96
- package/css/float-label.theme.css +0 -39
- package/css/link-icon.css +0 -59
- package/css/responsive-table.css +0 -57
- package/src/blades.standalone.core.css +0 -21
- package/src/float-label.css +0 -3
- /package/src/{responsive-table.css → standalone/content/_table-responsive.css} +0 -0
- /package/src/{float-label.theme.css → standalone/forms/_float-label.theme.css} +0 -0
|
@@ -1,81 +1,51 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
### Auto-columns
|
|
9
|
-
|
|
10
|
-
`.columns` automatically creates columns with at least 30 characters each:
|
|
11
|
-
|
|
12
|
-
<article class="columns">
|
|
13
|
-
<p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p>
|
|
14
|
-
</article>
|
|
1
|
+
/*!
|
|
2
|
+
* Blades CSS standalone kit v3 🥷
|
|
3
|
+
* Copyright 2026 (https://blades.ninja/css/standalone/)
|
|
4
|
+
* Licensed under MIT
|
|
5
|
+
*/
|
|
6
|
+
/*\3c !--section:code-->```css */
|
|
15
7
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<article class="columns" style="font-size: 65%">
|
|
19
|
-
<p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p>
|
|
20
|
-
</article>
|
|
21
|
-
|
|
22
|
-
Useful for tables of contents and long lists.
|
|
23
|
-
|
|
24
|
-
How it works:
|
|
25
|
-
```css */
|
|
8
|
+
/* Follows https://github.com/picocss/pico/blob/main/scss/_index.scss */
|
|
26
9
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
10
|
+
:scope,
|
|
11
|
+
:host {
|
|
12
|
+
/**
|
|
13
|
+
* Design Tokens !!! NAMING NOT FINALIZED YET !!!
|
|
14
|
+
* `--in-pico: *` props below are for reference only (not to be used)
|
|
15
|
+
*/
|
|
16
|
+
--blades-token-primary: var(--pico-primary, dodgerblue);
|
|
17
|
+
--in-pico: #01aaff;
|
|
18
|
+
--blades-token-secondary: var(--pico-secondary, lightslategray);
|
|
19
|
+
--in-pico: #969eaf;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Inherited Variables
|
|
23
|
+
*/
|
|
24
|
+
--blades-timeline-border-color: color-mix(
|
|
25
|
+
in srgb,
|
|
26
|
+
var(--blades-token-secondary) 50%,
|
|
27
|
+
transparent
|
|
28
|
+
);
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/*
|
|
33
|
-
|
|
34
|
-
.columns > * {
|
|
35
|
-
-moz-column-break-inside: avoid;
|
|
36
|
-
break-inside: avoid;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/*```
|
|
40
|
-
\3c !--section:docs,jump-->
|
|
41
|
-
|
|
42
|
-
### Jump to top
|
|
43
|
-
|
|
44
|
-
`data-jump-to="top"` fixes element to the corner and adds extra top padding to make it easy to click:
|
|
45
|
-
```css */
|
|
46
|
-
|
|
47
|
-
[data-jump-to="top"] {
|
|
48
|
-
position: fixed;
|
|
49
|
-
right: 0;
|
|
50
|
-
bottom: 0;
|
|
51
|
-
padding-top: 50vh;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/*```
|
|
55
|
-
\3c !--section--> */
|
|
56
|
-
|
|
31
|
+
/* Layout */
|
|
57
32
|
/*
|
|
58
33
|
\3c !--section:code-->
|
|
59
34
|
```css */
|
|
60
|
-
|
|
61
35
|
.breakout,
|
|
62
36
|
.breakout-all {
|
|
63
37
|
max-width: calc(10% + 65ch + 10%);
|
|
64
38
|
/* Prepare the container for breakout elements */
|
|
65
39
|
padding-inline: 10%;
|
|
66
40
|
}
|
|
67
|
-
|
|
68
41
|
@media (width < 768px) {
|
|
69
|
-
|
|
70
42
|
.breakout,
|
|
71
43
|
.breakout-all {
|
|
72
44
|
max-width: calc(1rem + 65ch + 1rem);
|
|
73
45
|
padding-inline: 1rem
|
|
74
46
|
}
|
|
75
47
|
}
|
|
76
|
-
|
|
77
48
|
/* Breakout direct children only */
|
|
78
|
-
|
|
79
49
|
.breakout > *:is(
|
|
80
50
|
table,
|
|
81
51
|
pre,
|
|
@@ -101,17 +71,14 @@ How it works:
|
|
|
101
71
|
margin-left: 50%;
|
|
102
72
|
transform: translateX(-50%);
|
|
103
73
|
}
|
|
104
|
-
|
|
105
74
|
/* Respect img/picture min-width */
|
|
106
|
-
|
|
107
75
|
.breakout > *:is(img, picture):not(.does-not-exist), .breakout-all > *:is(img, picture):not(.does-not-exist) /* soft win specificity over .breakout-item above */ {
|
|
108
76
|
min-width: auto;
|
|
109
77
|
}
|
|
110
|
-
|
|
111
78
|
/* Max out the width of the element */
|
|
112
|
-
|
|
113
79
|
.breakout > *.breakout-item-max, .breakout-all > *.breakout-item-max {
|
|
114
|
-
width: min(125%, 100dvw) !important;
|
|
80
|
+
width: min(125%, 100dvw) !important;
|
|
81
|
+
/* !important is for cases like figure.breakout-item-max @TODO */
|
|
115
82
|
}
|
|
116
83
|
|
|
117
84
|
.breakout-all > *:is(h2, h3, h4, h5, h6, hr):not([class]) {
|
|
@@ -154,15 +121,10 @@ How it works:
|
|
|
154
121
|
height: 100%;
|
|
155
122
|
transform: translateX(-50%);
|
|
156
123
|
}
|
|
157
|
-
|
|
158
124
|
/*```
|
|
159
|
-
\3c !--section:summary-->
|
|
160
|
-
|
|
161
|
-
The `.breakout` layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.
|
|
162
|
-
|
|
163
125
|
\3c !--section:docs-->
|
|
164
126
|
|
|
165
|
-
|
|
127
|
+
The `.breakout` layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.
|
|
166
128
|
|
|
167
129
|
Break out a wide image from the text flow:
|
|
168
130
|
|
|
@@ -196,23 +158,57 @@ Or anything else:
|
|
|
196
158
|
<hr>
|
|
197
159
|
|
|
198
160
|
\3c !--section--> */
|
|
161
|
+
/*\3c !--section:docs-->
|
|
199
162
|
|
|
200
|
-
|
|
163
|
+
`.columns` automatically creates columns with at least 30 characters each:
|
|
164
|
+
|
|
165
|
+
<article class="columns">
|
|
166
|
+
<p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p>
|
|
167
|
+
</article>
|
|
168
|
+
|
|
169
|
+
The smaller the font size, the more columns will be created:
|
|
170
|
+
|
|
171
|
+
<article class="columns" style="font-size: 65%">
|
|
172
|
+
<p>1</p><p>2</p><p>3</p><p>4</p><p>5</p><p>6</p><p>7</p><p>8</p><p>9</p>
|
|
173
|
+
</article>
|
|
174
|
+
|
|
175
|
+
Useful for tables of contents and long lists.
|
|
176
|
+
|
|
177
|
+
\3c !--section:code-->
|
|
178
|
+
```css */
|
|
179
|
+
.columns {
|
|
180
|
+
-moz-columns: 25ch auto;
|
|
181
|
+
columns: 25ch auto; /* common container 65ch / 25ch => 2 columns max, with a buffer for list paddings */
|
|
182
|
+
}
|
|
183
|
+
/* Avoid breaking inside elements, such as nested lists */
|
|
184
|
+
.columns > * {
|
|
185
|
+
-moz-column-break-inside: avoid;
|
|
186
|
+
break-inside: avoid;
|
|
187
|
+
}
|
|
188
|
+
/*```\3c !--section:docs-->
|
|
201
189
|
|
|
202
|
-
|
|
203
|
-
|
|
190
|
+
`<a href="#top">` is automatically fixed to the bottom-right corner with extra top padding for easier clicking:
|
|
191
|
+
```css */
|
|
192
|
+
[href="#top"] {
|
|
193
|
+
position: fixed;
|
|
194
|
+
right: 0;
|
|
195
|
+
bottom: 0;
|
|
196
|
+
padding-top: 50vh;
|
|
197
|
+
}
|
|
204
198
|
|
|
205
|
-
|
|
199
|
+
/* Content */
|
|
200
|
+
/*\3c !--section:docs-->
|
|
201
|
+
|
|
202
|
+
## Heading anchors
|
|
206
203
|
|
|
207
204
|
Links with `href="#..."` inside headings are automatically displayed as anchors:
|
|
208
205
|
|
|
209
206
|
<article>
|
|
210
|
-
<h2 style="margin: 0 0 0 1.5rem">Heading with anchor <a
|
|
207
|
+
<h2 style="margin: 0 0 0 1.5rem">Heading with anchor <a aria-hidden="true" style="visibility: visible">#</a></h2>
|
|
211
208
|
</article>
|
|
212
209
|
|
|
213
210
|
How it works:
|
|
214
211
|
```css */
|
|
215
|
-
|
|
216
212
|
h1,
|
|
217
213
|
h2,
|
|
218
214
|
h3,
|
|
@@ -221,7 +217,6 @@ h5,
|
|
|
221
217
|
h6 {
|
|
222
218
|
position: relative;
|
|
223
219
|
}
|
|
224
|
-
|
|
225
220
|
h1 a[aria-hidden="true"], h2 a[aria-hidden="true"], h3 a[aria-hidden="true"], h4 a[aria-hidden="true"], h5 a[aria-hidden="true"], h6 a[aria-hidden="true"] {
|
|
226
221
|
visibility: hidden;
|
|
227
222
|
position: absolute;
|
|
@@ -232,20 +227,14 @@ h1 a[aria-hidden="true"], h2 a[aria-hidden="true"], h3 a[aria-hidden="true"], h4
|
|
|
232
227
|
color: silver;
|
|
233
228
|
text-decoration: none;
|
|
234
229
|
}
|
|
235
|
-
|
|
236
230
|
@media /* to avoid double-tap on touch devices */ (hover: hover) {
|
|
237
231
|
h1:hover a[aria-hidden="true"], h2:hover a[aria-hidden="true"], h3:hover a[aria-hidden="true"], h4:hover a[aria-hidden="true"], h5:hover a[aria-hidden="true"], h6:hover a[aria-hidden="true"] {
|
|
238
232
|
visibility: visible;
|
|
239
233
|
}
|
|
240
234
|
}
|
|
235
|
+
/*\3c !--section:docs-->
|
|
241
236
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
**PRO** example of automatic anchors for `11ty`+`markdown-it-anchor`: https://github.com/anyblades/eleventy-blades/blob/main/src/eleventy.config.js
|
|
245
|
-
|
|
246
|
-
\3c !--section:docs,list-->
|
|
247
|
-
|
|
248
|
-
### List markers
|
|
237
|
+
## Custom markers
|
|
249
238
|
|
|
250
239
|
Customize markers using inline `style="--list-marker:..."` on `<ul>/<ol>` or even individual `<li>`:
|
|
251
240
|
|
|
@@ -264,26 +253,21 @@ Customize markers using inline `style="--list-marker:..."` on `<ul>/<ol>` or eve
|
|
|
264
253
|
|
|
265
254
|
How it works:
|
|
266
255
|
```css */
|
|
267
|
-
|
|
268
256
|
ul[style*="--list-marker:"], ol[style*="--list-marker:"] {
|
|
269
257
|
list-style-type: var(--list-marker);
|
|
270
258
|
}
|
|
271
|
-
|
|
272
259
|
ul[style*="--list-marker:"] > li, ol[style*="--list-marker:"] > li {
|
|
273
260
|
list-style-type: inherit;
|
|
274
261
|
}
|
|
275
|
-
|
|
276
262
|
ul li[style*="--list-marker:"], ol li[style*="--list-marker:"] {
|
|
277
263
|
list-style-type: var(--list-marker);
|
|
278
264
|
}
|
|
279
|
-
|
|
280
265
|
ul li[data-marker]::marker, ol li[data-marker]::marker {
|
|
281
266
|
content: attr(data-marker) " "; /* ⚠️ Chrome and Firefox only */
|
|
282
267
|
}
|
|
283
|
-
|
|
284
268
|
/*```
|
|
285
269
|
|
|
286
|
-
|
|
270
|
+
## Markerless
|
|
287
271
|
|
|
288
272
|
`.markerless` removes markers and reduces padding:
|
|
289
273
|
|
|
@@ -298,18 +282,15 @@ ul li[data-marker]::marker, ol li[data-marker]::marker {
|
|
|
298
282
|
|
|
299
283
|
How it works:
|
|
300
284
|
```css */
|
|
301
|
-
|
|
302
285
|
ul.markerless, ol.markerless {
|
|
303
286
|
padding-inline-start: 1.25rem;
|
|
304
287
|
}
|
|
305
|
-
|
|
306
288
|
ul.markerless li, ol.markerless li {
|
|
307
289
|
list-style: none;
|
|
308
290
|
}
|
|
309
|
-
|
|
310
291
|
/*```
|
|
311
292
|
|
|
312
|
-
|
|
293
|
+
## Unlist
|
|
313
294
|
|
|
314
295
|
`.unlist` removes list styling at all:
|
|
315
296
|
|
|
@@ -326,7 +307,6 @@ ul.markerless li, ol.markerless li {
|
|
|
326
307
|
|
|
327
308
|
How it works:
|
|
328
309
|
```css */
|
|
329
|
-
|
|
330
310
|
ul.unlist,
|
|
331
311
|
ul.unlist-all,
|
|
332
312
|
.unlist-all ul,
|
|
@@ -335,87 +315,12 @@ ul.unlist,
|
|
|
335
315
|
.unlist-all ol {
|
|
336
316
|
padding-inline-start: 0;
|
|
337
317
|
}
|
|
338
|
-
|
|
339
318
|
ul.unlist > li, ul.unlist-all > li, .unlist-all ul > li, ol.unlist > li, ol.unlist-all > li, .unlist-all ol > li {
|
|
340
319
|
list-style: none;
|
|
341
320
|
}
|
|
321
|
+
/*\3c !--section:docs-->
|
|
342
322
|
|
|
343
|
-
|
|
344
|
-
\3c !--section--> */
|
|
345
|
-
|
|
346
|
-
/* Extends https://github.com/picocss/pico/blob/main/scss/content/_link.scss
|
|
347
|
-
\3c !--section:code-->
|
|
348
|
-
```css */
|
|
349
|
-
|
|
350
|
-
/* Use inline flex only if link contains an icon */
|
|
351
|
-
|
|
352
|
-
a:not(.does-not-exist):has(> i) {
|
|
353
|
-
display: inline-flex;
|
|
354
|
-
overflow-y: clip; /* to work in pair with text-underline-offset in Safari */
|
|
355
|
-
gap: 0.375ch; /* =3/8 */
|
|
356
|
-
text-wrap: balance;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
a:not(.does-not-exist) > i {
|
|
360
|
-
float: left; /* ✅ Chrome ❌ Safari */
|
|
361
|
-
font-style: normal;
|
|
362
|
-
text-underline-offset: -2em; /* ❌ Chrome ✅ Safari - to clip it with overflow-y */
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/* Favicons */
|
|
366
|
-
|
|
367
|
-
a:not(.does-not-exist) > i > img {
|
|
368
|
-
display: inline-block; /* for Tailwind CSS Typography */
|
|
369
|
-
max-width: none; /* to keep ratio safe */
|
|
370
|
-
height: 1.25em;
|
|
371
|
-
margin-block-start: calc(-0.25em / 2);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
a:not(.does-not-exist) > i[class^="fa-"],
|
|
375
|
-
a:not(.does-not-exist) > i[class*=" fa-"] {
|
|
376
|
-
line-height: inherit;
|
|
377
|
-
--fa-width: auto;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
/* Font Awesome */
|
|
381
|
-
|
|
382
|
-
a:not(.does-not-exist) > i.fa-lg {
|
|
383
|
-
line-height: normal;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/*```
|
|
387
|
-
\3c !--section:summary-->
|
|
388
|
-
|
|
389
|
-
Use *Bl*ades `<i>`-helper to wrap emojis, favicons, or simply drop Font Awesome icons inside links.
|
|
390
|
-
It automatically handles sizing and alignment while preventing underline on icons.
|
|
391
|
-
|
|
392
|
-
\3c !--section:docs-->
|
|
393
|
-
|
|
394
|
-
<article class="breakout-item">
|
|
395
|
-
|
|
396
|
-
| Use `<i>`-helper with | Clean HTML without `<span>ning` |
|
|
397
|
-
| ------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
398
|
-
| [<i>🥷</i> Emojis](#) | `<a><i>🥷</i> Text</a>` |
|
|
399
|
-
| [<i></i> Favicons](#) | `<a><i><img src="..."></i> Text</a>` |
|
|
400
|
-
| [<i class="fa-brands fa-github fa-lg"></i> Font Awesome icons](#) | `<a><i class="fa-..."></i> Text</a>` |
|
|
401
|
-
</article>
|
|
402
|
-
|
|
403
|
-
Or even for:
|
|
404
|
-
|
|
405
|
-
<article>
|
|
406
|
-
<a href="#" style="margin: 0 0 0 1rem"><i>🥷</i> very-very-very-very-very-<br>long-multiline-links</a>
|
|
407
|
-
</article>
|
|
408
|
-
|
|
409
|
-
How we made it: https://codepen.io/editor/anydigital/pen/019d2b94-5616-75dc-a23e-e111869d5237
|
|
410
|
-
|
|
411
|
-
**PRO** example of automatic favicons for `11ty`: https://blades.ninja/build-awesome-11ty/processors/#auto-link-favicons
|
|
412
|
-
|
|
413
|
-
\3c !--section--> */
|
|
414
|
-
|
|
415
|
-
/* Extends https://github.com/picocss/pico/blob/main/scss/content/_table.scss
|
|
416
|
-
\3c !--section:docs-->
|
|
417
|
-
|
|
418
|
-
### Column expanders
|
|
323
|
+
## Column expanders
|
|
419
324
|
|
|
420
325
|
Place `<hr>` element inside `<th>` column to expand it horizontally:
|
|
421
326
|
|
|
@@ -434,25 +339,21 @@ Living examples of big tables with `<hr>`-expanders: \3c !--A-Z-->
|
|
|
434
339
|
|
|
435
340
|
How it works:
|
|
436
341
|
```css */
|
|
437
|
-
|
|
438
342
|
th hr {
|
|
439
343
|
visibility: hidden;
|
|
440
344
|
width: 12ch; /* min ~65/12 = ~5 cols */
|
|
441
345
|
height: 0;
|
|
442
346
|
margin: 0;
|
|
443
347
|
}
|
|
444
|
-
|
|
445
348
|
th hr.lg {
|
|
446
349
|
width: 18ch;
|
|
447
350
|
}
|
|
448
|
-
|
|
449
351
|
th hr.x2 {
|
|
450
352
|
width: 24ch;
|
|
451
353
|
}
|
|
452
|
-
|
|
453
354
|
/*```
|
|
454
355
|
|
|
455
|
-
|
|
356
|
+
## Borderless table
|
|
456
357
|
|
|
457
358
|
`.borderless` removes all default borders:
|
|
458
359
|
|
|
@@ -465,19 +366,14 @@ th hr.x2 {
|
|
|
465
366
|
{.borderless}
|
|
466
367
|
</article>
|
|
467
368
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
\3c !--section--> */
|
|
471
|
-
|
|
369
|
+
\3c !--section-->*/
|
|
472
370
|
table.borderless th,
|
|
473
371
|
table.borderless td {
|
|
474
372
|
border: none;
|
|
475
373
|
}
|
|
476
|
-
|
|
477
374
|
/*
|
|
478
375
|
\3c !--section:code-->
|
|
479
376
|
```css */
|
|
480
|
-
|
|
481
377
|
table.responsive,
|
|
482
378
|
.breakout > table:not(.does-not-exist),
|
|
483
379
|
.breakout-all > table:not(.does-not-exist) {
|
|
@@ -497,7 +393,6 @@ table.responsive,
|
|
|
497
393
|
transform: translateX(-50%);
|
|
498
394
|
-webkit-overflow-scrolling: touch; /* Smooth scroll for iOS */
|
|
499
395
|
}
|
|
500
|
-
|
|
501
396
|
table.responsive th,
|
|
502
397
|
table.responsive td,
|
|
503
398
|
.breakout > table:not(.does-not-exist) th,
|
|
@@ -506,7 +401,6 @@ table.responsive th,
|
|
|
506
401
|
.breakout-all > table:not(.does-not-exist) td {
|
|
507
402
|
padding-inline-start: 0;
|
|
508
403
|
}
|
|
509
|
-
|
|
510
404
|
/*```
|
|
511
405
|
`table:not(.does-not-exist)` trick (inspired by postcss) is used here to increase specificity against selectors like `&:is(table, .table)`
|
|
512
406
|
|
|
@@ -534,25 +428,21 @@ Living examples: \3c !--A-Z-->
|
|
|
534
428
|
- https://blades.ninja/ssg/
|
|
535
429
|
|
|
536
430
|
\3c !--section--> */
|
|
537
|
-
|
|
538
|
-
/* Extends https://github.com/picocss/pico/blob/main/scss/content/_code.scss
|
|
539
|
-
\3c !--section:docs-->
|
|
540
|
-
|
|
541
|
-
### Code
|
|
431
|
+
/*\3c !--section:docs-->
|
|
542
432
|
|
|
543
433
|
The `<pre><code>` blocks are Prism-compatible and support captions via `data-caption="..."` attribute:
|
|
544
434
|
|
|
545
|
-
```treeview {data-caption="Blades CSS:"}
|
|
546
|
-
|
|
547
|
-
├── blades.
|
|
548
|
-
├── blades.
|
|
549
|
-
|
|
435
|
+
```treeview {data-caption="Blades CSS ships:"}
|
|
436
|
+
/css/
|
|
437
|
+
├── blades.css (Pico CSS successor)
|
|
438
|
+
├── blades.standalone.css (framework-agnostic)
|
|
439
|
+
├── ninja.css (experimental add-ons)
|
|
440
|
+
└── pico.css (underlying fork)
|
|
550
441
|
```
|
|
551
|
-
How it works:
|
|
552
|
-
```css */
|
|
553
442
|
|
|
443
|
+
\3c !--section:code-->
|
|
444
|
+
```css */
|
|
554
445
|
@media (width < 768px) {
|
|
555
|
-
|
|
556
446
|
pre {
|
|
557
447
|
border-radius: 0
|
|
558
448
|
}
|
|
@@ -568,32 +458,44 @@ code[data-caption]::before {
|
|
|
568
458
|
opacity: 50%;
|
|
569
459
|
}
|
|
570
460
|
|
|
571
|
-
/*```
|
|
572
|
-
\3c !--section--> */
|
|
573
|
-
|
|
574
461
|
/* Forms */
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
462
|
+
/*!
|
|
463
|
+
* Float Label CSS v2 by Blades CSS 🥷🏷️
|
|
464
|
+
* Copyright 2016–2026 (https://blades.ninja/css/float-label/)
|
|
465
|
+
* Licensed under MIT
|
|
466
|
+
*/
|
|
467
|
+
/*\3c !--section:docs-->
|
|
578
468
|
|
|
579
469
|
First, we target either:
|
|
580
470
|
1. `<label>` which `:has` inner form inputs (classless approach)
|
|
581
471
|
2. or explicit `.has-float-label` class (explicit approach)
|
|
582
|
-
```css */
|
|
583
472
|
|
|
584
|
-
|
|
473
|
+
```css */
|
|
474
|
+
label:has(> span):has(
|
|
475
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
476
|
+
textarea,
|
|
477
|
+
select
|
|
478
|
+
),
|
|
585
479
|
.has-float-label {
|
|
586
480
|
display: block;
|
|
587
481
|
position: relative;
|
|
482
|
+
/*```
|
|
483
|
+
Finally, we detect if placeholder is shown, but not in focus. That means we can safely hide it, and enlarge the float label instead:
|
|
484
|
+
```css */
|
|
588
485
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
486
|
+
/*```
|
|
487
|
+
Then, we define the default/fallback state (when the float label should be minimized):
|
|
488
|
+
```css */
|
|
489
|
+
label:has(> span):has(
|
|
490
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
491
|
+
textarea,
|
|
492
|
+
select
|
|
493
|
+
) > span,
|
|
494
|
+
label:has(> span):has(
|
|
495
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
496
|
+
textarea,
|
|
497
|
+
select
|
|
498
|
+
) label,
|
|
597
499
|
.has-float-label > span,
|
|
598
500
|
.has-float-label label {
|
|
599
501
|
position: absolute;
|
|
@@ -602,46 +504,120 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
602
504
|
font-size: 75%;
|
|
603
505
|
cursor: text;
|
|
604
506
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) *:placeholder-shown:not(:focus)::-moz-placeholder, .has-float-label *:placeholder-shown:not(:focus)::-moz-placeholder {
|
|
507
|
+
label:has(> span):has(
|
|
508
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
509
|
+
textarea,
|
|
510
|
+
select
|
|
511
|
+
) *:placeholder-shown:not(:focus)::-moz-placeholder, .has-float-label *:placeholder-shown:not(:focus)::-moz-placeholder {
|
|
612
512
|
opacity: 0;
|
|
613
513
|
}
|
|
614
|
-
|
|
615
|
-
|
|
514
|
+
label:has(> span):has(
|
|
515
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
516
|
+
textarea,
|
|
517
|
+
select
|
|
518
|
+
) *:-moz-placeholder:not(:focus)::placeholder, .has-float-label *:-moz-placeholder:not(:focus)::placeholder {
|
|
616
519
|
opacity: 0;
|
|
617
520
|
}
|
|
618
|
-
|
|
619
|
-
|
|
521
|
+
label:has(> span):has(
|
|
522
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
523
|
+
textarea,
|
|
524
|
+
select
|
|
525
|
+
) *:placeholder-shown:not(:focus)::placeholder, .has-float-label *:placeholder-shown:not(:focus)::placeholder {
|
|
620
526
|
opacity: 0;
|
|
621
527
|
}
|
|
622
|
-
|
|
623
|
-
|
|
528
|
+
label:has(> span):has(
|
|
529
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
530
|
+
textarea,
|
|
531
|
+
select
|
|
532
|
+
):has(*:-moz-placeholder:not(:focus)) > span, label:has(> span):has(
|
|
533
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
534
|
+
textarea,
|
|
535
|
+
select
|
|
536
|
+
):has(*:-moz-placeholder:not(:focus)) label, .has-float-label:has(*:-moz-placeholder:not(:focus)) > span, .has-float-label:has(*:-moz-placeholder:not(:focus)) label {
|
|
624
537
|
font-size: inherit;
|
|
625
538
|
opacity: 50%;
|
|
626
539
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
540
|
+
label:has(> span):has(
|
|
541
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
542
|
+
textarea,
|
|
543
|
+
select
|
|
544
|
+
):has(*:placeholder-shown:not(:focus)) > span,
|
|
545
|
+
label:has(> span):has(
|
|
546
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
547
|
+
textarea,
|
|
548
|
+
select
|
|
549
|
+
):has(*:placeholder-shown:not(:focus)) label,
|
|
630
550
|
.has-float-label:has(*:placeholder-shown:not(:focus)) > span,
|
|
631
551
|
.has-float-label:has(*:placeholder-shown:not(:focus)) label {
|
|
632
552
|
font-size: inherit;
|
|
633
553
|
opacity: 50%;
|
|
634
554
|
}
|
|
555
|
+
/*```
|
|
635
556
|
|
|
636
|
-
/*
|
|
637
|
-
```
|
|
638
557
|
The `:has(*:placeholder-shown:not(:focus))` trick allows this input state information to *propagate* to the parent level. This enables modern CSS to target inner float label (`<span>` or `<label>`) regardless of its position relative to the input field.
|
|
639
558
|
|
|
640
559
|
Historically, this was not possible: the float label had to be placed after the input field to be targeted using the `input:focus + label` selector.
|
|
641
|
-
|
|
560
|
+
|
|
561
|
+
*/
|
|
642
562
|
|
|
643
563
|
/* Components */
|
|
564
|
+
/* Extends https://github.com/picocss/pico/blob/main/scss/content/_link.scss
|
|
565
|
+
\3c !--section:code-->
|
|
566
|
+
```css */
|
|
567
|
+
/* Use inline flex only if link contains an icon */
|
|
568
|
+
a:not(.does-not-exist):has(> i) {
|
|
569
|
+
display: inline-flex;
|
|
570
|
+
overflow-y: clip; /* to work in pair with text-underline-offset in Safari */
|
|
571
|
+
gap: 0.375ch; /* =3/8 */
|
|
572
|
+
text-wrap: balance;
|
|
573
|
+
}
|
|
574
|
+
a:not(.does-not-exist) > i {
|
|
575
|
+
float: left; /* ✅ Chrome ❌ Safari */
|
|
576
|
+
font-style: normal;
|
|
577
|
+
text-underline-offset: -2em; /* ❌ Chrome ✅ Safari - to clip it with overflow-y */
|
|
578
|
+
}
|
|
579
|
+
/* Favicons */
|
|
580
|
+
a:not(.does-not-exist) > i > img {
|
|
581
|
+
display: inline-block; /* for Tailwind CSS Typography */
|
|
582
|
+
max-width: none; /* to keep ratio safe */
|
|
583
|
+
height: 1.25em;
|
|
584
|
+
margin-block-start: calc(-0.25em / 2);
|
|
585
|
+
}
|
|
586
|
+
a:not(.does-not-exist) > i[class^="fa-"],
|
|
587
|
+
a:not(.does-not-exist) > i[class*=" fa-"] {
|
|
588
|
+
line-height: inherit;
|
|
589
|
+
--fa-width: auto;
|
|
590
|
+
}
|
|
591
|
+
/* Font Awesome */
|
|
592
|
+
a:not(.does-not-exist) > i.fa-lg {
|
|
593
|
+
line-height: normal;
|
|
594
|
+
}
|
|
595
|
+
/*```
|
|
596
|
+
\3c !--section:summary-->
|
|
597
|
+
|
|
598
|
+
Use *Bl*ades `<i>`-helper to wrap emojis, favicons, or simply drop Font Awesome icons inside links.
|
|
599
|
+
It automatically handles sizing and alignment while preventing underline on icons.
|
|
600
|
+
|
|
601
|
+
\3c !--section:docs-->
|
|
644
602
|
|
|
603
|
+
<article class="breakout-item">
|
|
604
|
+
|
|
605
|
+
| Use `<i>`-helper with | Clean HTML without `<span>ning` |
|
|
606
|
+
| ------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
607
|
+
| [<i>🥷</i> Emojis](#) | `<a><i>🥷</i> Text</a>` |
|
|
608
|
+
| [<i></i> Favicons](#) | `<a><i><img src="..."></i> Text</a>` |
|
|
609
|
+
| [<i class="fa-brands fa-github fa-lg"></i> Font Awesome icons](#) | `<a><i class="fa-..."></i> Text</a>` |
|
|
610
|
+
</article>
|
|
611
|
+
|
|
612
|
+
Or even for:
|
|
613
|
+
|
|
614
|
+
<article>
|
|
615
|
+
<a href="#" style="margin: 0 0 0 1rem"><i>🥷</i> very-very-very-very-very-<br>long-multiline-links</a>
|
|
616
|
+
</article>
|
|
617
|
+
|
|
618
|
+
How we made it: https://codepen.io/editor/anydigital/pen/019d2b94-5616-75dc-a23e-e111869d5237
|
|
619
|
+
|
|
620
|
+
\3c !--section--> */
|
|
645
621
|
/*\3c !--section:docs-->
|
|
646
622
|
|
|
647
623
|
Use `dl.timeline` or wrap a `<dl>` with `.has-timeline` to style it as a
|
|
@@ -658,21 +634,16 @@ Mar 15, 2025
|
|
|
658
634
|
</article>
|
|
659
635
|
|
|
660
636
|
\3c !--section:code-->```css */
|
|
661
|
-
|
|
662
637
|
dl.timeline dd, .has-timeline > dl dd {
|
|
663
638
|
margin-block: 0;
|
|
664
639
|
padding: 0.25rem 0 0.75rem 1rem;
|
|
665
|
-
border-inline-start: 0.25rem solid
|
|
640
|
+
border-inline-start: 0.25rem solid var(--blades-timeline-border-color);
|
|
666
641
|
}
|
|
667
642
|
|
|
668
|
-
/*```*/
|
|
669
|
-
|
|
670
643
|
/* Utilities */
|
|
644
|
+
/*\3c !--section:docs-->
|
|
671
645
|
|
|
672
|
-
|
|
673
|
-
\3c !--section:docs-->
|
|
674
|
-
|
|
675
|
-
### Auto-dark
|
|
646
|
+
## Dark auto
|
|
676
647
|
|
|
677
648
|
`.dark-auto` automatically creates a simple dark version of any element:
|
|
678
649
|
|
|
@@ -682,34 +653,26 @@ dl.timeline dd, .has-timeline > dl dd {
|
|
|
682
653
|
|
|
683
654
|
How it works:
|
|
684
655
|
```css */
|
|
685
|
-
|
|
686
656
|
/* Per https://picocss.com/docs/css-variables#css-variables-for-color-schemes */
|
|
687
|
-
|
|
688
657
|
:root {
|
|
689
658
|
--blades-dark-filter: invert(100%) hue-rotate(180deg);
|
|
690
659
|
}
|
|
691
|
-
|
|
692
660
|
.dark-auto {
|
|
693
661
|
/* Dark color scheme (Forced) */
|
|
694
662
|
}
|
|
695
|
-
|
|
696
663
|
/* Dark color scheme (Auto) */
|
|
697
|
-
|
|
698
664
|
@media (prefers-color-scheme: dark) {
|
|
699
|
-
|
|
700
665
|
.dark-auto {
|
|
701
666
|
filter: var(--blades-dark-filter)
|
|
702
667
|
}
|
|
703
668
|
}
|
|
704
|
-
|
|
705
669
|
.dark-auto[data-theme="dark"],
|
|
706
670
|
.dark-auto:where([data-theme="dark"] *) {
|
|
707
671
|
filter: var(--blades-dark-filter);
|
|
708
672
|
}
|
|
709
|
-
|
|
710
673
|
/*```
|
|
711
674
|
|
|
712
|
-
|
|
675
|
+
## Faded
|
|
713
676
|
|
|
714
677
|
`.faded` reduces the opacity of an element:
|
|
715
678
|
|
|
@@ -719,30 +682,21 @@ How it works:
|
|
|
719
682
|
|
|
720
683
|
How it works:
|
|
721
684
|
```css */
|
|
722
|
-
|
|
723
685
|
.faded {
|
|
724
686
|
opacity: 50%;
|
|
725
687
|
}
|
|
726
|
-
|
|
727
688
|
.faded:hover {
|
|
728
689
|
opacity: 87.5%;
|
|
729
690
|
}
|
|
730
|
-
|
|
731
691
|
/*```
|
|
732
692
|
\3c !--section--> */
|
|
733
693
|
|
|
734
694
|
/* Fix the scrollbar color when inverted by https://tailwindcss.com/docs/filter-invert */
|
|
735
|
-
|
|
736
695
|
.invert ::-webkit-scrollbar {
|
|
737
696
|
filter: invert(1) !important;
|
|
738
697
|
}
|
|
739
|
-
|
|
740
|
-
/*
|
|
741
|
-
\3c !--section:code-->
|
|
742
|
-
```css */
|
|
743
|
-
|
|
698
|
+
/*\3c !--section:code-->```css */
|
|
744
699
|
/* Default/fallback state */
|
|
745
|
-
|
|
746
700
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) > span,
|
|
747
701
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) label,
|
|
748
702
|
.has-float-label > span,
|
|
@@ -752,7 +706,6 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
752
706
|
opacity: 75%;
|
|
753
707
|
transition: all 0.25s;
|
|
754
708
|
}
|
|
755
|
-
|
|
756
709
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input,
|
|
757
710
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea,
|
|
758
711
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select,
|
|
@@ -763,24 +716,19 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
763
716
|
padding-inline-start: 1rem; /* match Pico */
|
|
764
717
|
padding-block: 1.125rem 0.375rem; /* match Pico's total: 2 x 0.75rem = 1.5rem */
|
|
765
718
|
}
|
|
766
|
-
|
|
767
719
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input::-moz-placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea::-moz-placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select::-moz-placeholder, .has-float-label input::-moz-placeholder, .has-float-label textarea::-moz-placeholder, .has-float-label select::-moz-placeholder {
|
|
768
720
|
opacity: 100%;
|
|
769
721
|
-moz-transition: all 0.25s;
|
|
770
722
|
transition: all 0.25s;
|
|
771
723
|
}
|
|
772
|
-
|
|
773
724
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input::placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea::placeholder, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select::placeholder, .has-float-label input::placeholder, .has-float-label textarea::placeholder, .has-float-label select::placeholder {
|
|
774
725
|
opacity: 100%;
|
|
775
726
|
transition: all 0.25s;
|
|
776
727
|
}
|
|
777
|
-
|
|
778
728
|
/* Enlarged state */
|
|
779
|
-
|
|
780
729
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:-moz-placeholder:not(:focus)) > span, label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:-moz-placeholder:not(:focus)) label, .has-float-label:has(*:-moz-placeholder:not(:focus)) > span, .has-float-label:has(*:-moz-placeholder:not(:focus)) label {
|
|
781
730
|
padding-block: 0.75rem; /* match Pico */
|
|
782
731
|
}
|
|
783
|
-
|
|
784
732
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) > span,
|
|
785
733
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) label,
|
|
786
734
|
.has-float-label:has(*:placeholder-shown:not(:focus)) > span,
|
|
@@ -841,7 +789,6 @@ h5,
|
|
|
841
789
|
h6 {
|
|
842
790
|
text-wrap: balance;
|
|
843
791
|
}
|
|
844
|
-
|
|
845
792
|
h1 {
|
|
846
793
|
margin-bottom: 1rem; /* for tw-typography */
|
|
847
794
|
font-size: 2.5em; /* for pico.css & tw-typography */
|
|
@@ -886,15 +833,15 @@ table pre {
|
|
|
886
833
|
margin-bottom: 0.25rem;
|
|
887
834
|
}
|
|
888
835
|
|
|
889
|
-
[
|
|
836
|
+
[href="#top"] {
|
|
890
837
|
opacity: 25%;
|
|
891
838
|
}
|
|
892
839
|
|
|
893
|
-
[
|
|
840
|
+
[href="#top"]:hover {
|
|
894
841
|
opacity: 75%;
|
|
895
842
|
}
|
|
896
843
|
|
|
897
|
-
[
|
|
844
|
+
[href="#top"] > i {
|
|
898
845
|
display: inline-block;
|
|
899
846
|
margin: 0.5rem;
|
|
900
847
|
padding: 0.25rem 0.375rem;
|
|
@@ -913,6 +860,3 @@ table pre {
|
|
|
913
860
|
.faded a {
|
|
914
861
|
text-decoration-style: dotted;
|
|
915
862
|
}
|
|
916
|
-
|
|
917
|
-
/*```
|
|
918
|
-
\3c !--section--> */
|