@anyblades/blades 2.4.9 → 3.0.0-alpha.2
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 +111 -150
- package/_includes/blades/html.njk +1 -1
- package/_includes/blades/html.twig +1 -1
- package/context7.json +4 -0
- package/css/blades.css +436 -153
- package/css/blades.min.css +145 -0
- package/css/blades.standalone.css +197 -222
- 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} +2 -2
- package/src/{_utilities.css → standalone/_utilities.css} +1 -1
- 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 -1
- package/src/{content → standalone/content}/_code.css +6 -5
- package/src/{content/_typography.css → standalone/content/_list.css} +4 -42
- package/src/standalone/content/_typography.css +38 -0
- package/src/{float-label.core.css → standalone/forms/_float-label.core.css} +12 -4
- 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 -12
- 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 -712
- package/css/blades.standalone.theme.css +0 -143
- 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 -23
- package/src/float-label.css +0 -3
- /package/src/{responsive-table.css → standalone/content/_table-responsive.css} +0 -0
- /package/src/{content → standalone/content}/_table.css +0 -0
- /package/src/{float-label.theme.css → standalone/forms/_float-label.theme.css} +0 -0
|
@@ -1,74 +1,51 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Blades CSS standalone kit v3 🥷
|
|
3
|
+
* Copyright 2026 (https://blades.ninja/css/standalone/)
|
|
4
|
+
* Licensed under MIT
|
|
5
|
+
*/
|
|
1
6
|
/*\3c !--section:code-->```css */
|
|
2
7
|
|
|
3
8
|
/* Follows https://github.com/picocss/pico/blob/main/scss/_index.scss */
|
|
4
9
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
```css */
|
|
25
|
-
|
|
26
|
-
.columns {
|
|
27
|
-
-moz-columns: 25ch auto;
|
|
28
|
-
columns: 25ch auto; /* common container 65ch / 25ch => 2 columns max, with a buffer for list paddings */
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/* Avoid breaking inside elements, such as nested lists */
|
|
32
|
-
|
|
33
|
-
.columns > * {
|
|
34
|
-
-moz-column-break-inside: avoid;
|
|
35
|
-
break-inside: avoid;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/*```\3c !--section:jump-->
|
|
39
|
-
|
|
40
|
-
`data-jump-to="top"` fixes element to the corner and adds extra top padding to make it easy to click:
|
|
41
|
-
```css */
|
|
42
|
-
|
|
43
|
-
[data-jump-to="top"] {
|
|
44
|
-
position: fixed;
|
|
45
|
-
right: 0;
|
|
46
|
-
bottom: 0;
|
|
47
|
-
padding-top: 50vh;
|
|
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
|
+
);
|
|
48
29
|
}
|
|
49
30
|
|
|
31
|
+
/* Layout */
|
|
50
32
|
/*
|
|
51
33
|
\3c !--section:code-->
|
|
52
34
|
```css */
|
|
53
|
-
|
|
54
35
|
.breakout,
|
|
55
36
|
.breakout-all {
|
|
56
37
|
max-width: calc(10% + 65ch + 10%);
|
|
57
38
|
/* Prepare the container for breakout elements */
|
|
58
39
|
padding-inline: 10%;
|
|
59
40
|
}
|
|
60
|
-
|
|
61
41
|
@media (width < 768px) {
|
|
62
|
-
|
|
63
42
|
.breakout,
|
|
64
43
|
.breakout-all {
|
|
65
44
|
max-width: calc(1rem + 65ch + 1rem);
|
|
66
45
|
padding-inline: 1rem
|
|
67
46
|
}
|
|
68
47
|
}
|
|
69
|
-
|
|
70
48
|
/* Breakout direct children only */
|
|
71
|
-
|
|
72
49
|
.breakout > *:is(
|
|
73
50
|
table,
|
|
74
51
|
pre,
|
|
@@ -94,17 +71,14 @@ How it works:
|
|
|
94
71
|
margin-left: 50%;
|
|
95
72
|
transform: translateX(-50%);
|
|
96
73
|
}
|
|
97
|
-
|
|
98
74
|
/* Respect img/picture min-width */
|
|
99
|
-
|
|
100
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 */ {
|
|
101
76
|
min-width: auto;
|
|
102
77
|
}
|
|
103
|
-
|
|
104
78
|
/* Max out the width of the element */
|
|
105
|
-
|
|
106
79
|
.breakout > *.breakout-item-max, .breakout-all > *.breakout-item-max {
|
|
107
|
-
width: min(125%, 100dvw) !important;
|
|
80
|
+
width: min(125%, 100dvw) !important;
|
|
81
|
+
/* !important is for cases like figure.breakout-item-max @TODO */
|
|
108
82
|
}
|
|
109
83
|
|
|
110
84
|
.breakout-all > *:is(h2, h3, h4, h5, h6, hr):not([class]) {
|
|
@@ -147,15 +121,10 @@ How it works:
|
|
|
147
121
|
height: 100%;
|
|
148
122
|
transform: translateX(-50%);
|
|
149
123
|
}
|
|
150
|
-
|
|
151
124
|
/*```
|
|
152
|
-
\3c !--section:summary-->
|
|
153
|
-
|
|
154
|
-
The `.breakout` layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.
|
|
155
|
-
|
|
156
125
|
\3c !--section:docs-->
|
|
157
126
|
|
|
158
|
-
|
|
127
|
+
The `.breakout` layout allows images, tables, and other figures to automatically extend or bleed beyond their parent container’s width.
|
|
159
128
|
|
|
160
129
|
Break out a wide image from the text flow:
|
|
161
130
|
|
|
@@ -189,10 +158,48 @@ Or anything else:
|
|
|
189
158
|
<hr>
|
|
190
159
|
|
|
191
160
|
\3c !--section--> */
|
|
161
|
+
/*\3c !--section:docs-->
|
|
162
|
+
|
|
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-->
|
|
189
|
+
|
|
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
|
+
}
|
|
192
198
|
|
|
193
199
|
/* Content */
|
|
200
|
+
/*\3c !--section:docs-->
|
|
194
201
|
|
|
195
|
-
|
|
202
|
+
## Heading anchors
|
|
196
203
|
|
|
197
204
|
Links with `href="#..."` inside headings are automatically displayed as anchors:
|
|
198
205
|
|
|
@@ -202,7 +209,6 @@ Links with `href="#..."` inside headings are automatically displayed as anchors:
|
|
|
202
209
|
|
|
203
210
|
How it works:
|
|
204
211
|
```css */
|
|
205
|
-
|
|
206
212
|
h1,
|
|
207
213
|
h2,
|
|
208
214
|
h3,
|
|
@@ -211,7 +217,6 @@ h5,
|
|
|
211
217
|
h6 {
|
|
212
218
|
position: relative;
|
|
213
219
|
}
|
|
214
|
-
|
|
215
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"] {
|
|
216
221
|
visibility: hidden;
|
|
217
222
|
position: absolute;
|
|
@@ -222,18 +227,14 @@ h1 a[aria-hidden="true"], h2 a[aria-hidden="true"], h3 a[aria-hidden="true"], h4
|
|
|
222
227
|
color: silver;
|
|
223
228
|
text-decoration: none;
|
|
224
229
|
}
|
|
225
|
-
|
|
226
230
|
@media /* to avoid double-tap on touch devices */ (hover: hover) {
|
|
227
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"] {
|
|
228
232
|
visibility: visible;
|
|
229
233
|
}
|
|
230
234
|
}
|
|
235
|
+
/*\3c !--section:docs-->
|
|
231
236
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
**PRO** example of automatic anchors for `11ty`+`markdown-it-anchor`: https://github.com/anyblades/eleventy-blades/blob/main/src/eleventy.config.js
|
|
235
|
-
|
|
236
|
-
\3c !--section:list-->
|
|
237
|
+
## Custom markers
|
|
237
238
|
|
|
238
239
|
Customize markers using inline `style="--list-marker:..."` on `<ul>/<ol>` or even individual `<li>`:
|
|
239
240
|
|
|
@@ -252,26 +253,21 @@ Customize markers using inline `style="--list-marker:..."` on `<ul>/<ol>` or eve
|
|
|
252
253
|
|
|
253
254
|
How it works:
|
|
254
255
|
```css */
|
|
255
|
-
|
|
256
256
|
ul[style*="--list-marker:"], ol[style*="--list-marker:"] {
|
|
257
257
|
list-style-type: var(--list-marker);
|
|
258
258
|
}
|
|
259
|
-
|
|
260
259
|
ul[style*="--list-marker:"] > li, ol[style*="--list-marker:"] > li {
|
|
261
260
|
list-style-type: inherit;
|
|
262
261
|
}
|
|
263
|
-
|
|
264
262
|
ul li[style*="--list-marker:"], ol li[style*="--list-marker:"] {
|
|
265
263
|
list-style-type: var(--list-marker);
|
|
266
264
|
}
|
|
267
|
-
|
|
268
265
|
ul li[data-marker]::marker, ol li[data-marker]::marker {
|
|
269
266
|
content: attr(data-marker) " "; /* ⚠️ Chrome and Firefox only */
|
|
270
267
|
}
|
|
271
|
-
|
|
272
268
|
/*```
|
|
273
269
|
|
|
274
|
-
|
|
270
|
+
## Markerless
|
|
275
271
|
|
|
276
272
|
`.markerless` removes markers and reduces padding:
|
|
277
273
|
|
|
@@ -286,18 +282,15 @@ ul li[data-marker]::marker, ol li[data-marker]::marker {
|
|
|
286
282
|
|
|
287
283
|
How it works:
|
|
288
284
|
```css */
|
|
289
|
-
|
|
290
285
|
ul.markerless, ol.markerless {
|
|
291
286
|
padding-inline-start: 1.25rem;
|
|
292
287
|
}
|
|
293
|
-
|
|
294
288
|
ul.markerless li, ol.markerless li {
|
|
295
289
|
list-style: none;
|
|
296
290
|
}
|
|
297
|
-
|
|
298
291
|
/*```
|
|
299
292
|
|
|
300
|
-
|
|
293
|
+
## Unlist
|
|
301
294
|
|
|
302
295
|
`.unlist` removes list styling at all:
|
|
303
296
|
|
|
@@ -314,7 +307,6 @@ ul.markerless li, ol.markerless li {
|
|
|
314
307
|
|
|
315
308
|
How it works:
|
|
316
309
|
```css */
|
|
317
|
-
|
|
318
310
|
ul.unlist,
|
|
319
311
|
ul.unlist-all,
|
|
320
312
|
.unlist-all ul,
|
|
@@ -323,80 +315,9 @@ ul.unlist,
|
|
|
323
315
|
.unlist-all ol {
|
|
324
316
|
padding-inline-start: 0;
|
|
325
317
|
}
|
|
326
|
-
|
|
327
318
|
ul.unlist > li, ul.unlist-all > li, .unlist-all ul > li, ol.unlist > li, ol.unlist-all > li, .unlist-all ol > li {
|
|
328
319
|
list-style: none;
|
|
329
320
|
}
|
|
330
|
-
|
|
331
|
-
/* Extends https://github.com/picocss/pico/blob/main/scss/content/_link.scss
|
|
332
|
-
\3c !--section:code-->
|
|
333
|
-
```css */
|
|
334
|
-
|
|
335
|
-
/* Use inline flex only if link contains an icon */
|
|
336
|
-
|
|
337
|
-
a:not(.does-not-exist):has(> i) {
|
|
338
|
-
display: inline-flex;
|
|
339
|
-
overflow-y: clip; /* to work in pair with text-underline-offset in Safari */
|
|
340
|
-
gap: 0.375ch; /* =3/8 */
|
|
341
|
-
text-wrap: balance;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
a:not(.does-not-exist) > i {
|
|
345
|
-
float: left; /* ✅ Chrome ❌ Safari */
|
|
346
|
-
font-style: normal;
|
|
347
|
-
text-underline-offset: -2em; /* ❌ Chrome ✅ Safari - to clip it with overflow-y */
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
/* Favicons */
|
|
351
|
-
|
|
352
|
-
a:not(.does-not-exist) > i > img {
|
|
353
|
-
display: inline-block; /* for Tailwind CSS Typography */
|
|
354
|
-
max-width: none; /* to keep ratio safe */
|
|
355
|
-
height: 1.25em;
|
|
356
|
-
margin-block-start: calc(-0.25em / 2);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
a:not(.does-not-exist) > i[class^="fa-"],
|
|
360
|
-
a:not(.does-not-exist) > i[class*=" fa-"] {
|
|
361
|
-
line-height: inherit;
|
|
362
|
-
--fa-width: auto;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/* Font Awesome */
|
|
366
|
-
|
|
367
|
-
a:not(.does-not-exist) > i.fa-lg {
|
|
368
|
-
line-height: normal;
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/*```
|
|
372
|
-
\3c !--section:summary-->
|
|
373
|
-
|
|
374
|
-
Use *Bl*ades `<i>`-helper to wrap emojis, favicons, or simply drop Font Awesome icons inside links.
|
|
375
|
-
It automatically handles sizing and alignment while preventing underline on icons.
|
|
376
|
-
|
|
377
|
-
\3c !--section:docs-->
|
|
378
|
-
|
|
379
|
-
<article class="breakout-item">
|
|
380
|
-
|
|
381
|
-
| Use `<i>`-helper with | Clean HTML without `<span>ning` |
|
|
382
|
-
| ------------------------------------------------------------------------------------- | ------------------------------------ |
|
|
383
|
-
| [<i>🥷</i> Emojis](#) | `<a><i>🥷</i> Text</a>` |
|
|
384
|
-
| [<i></i> Favicons](#) | `<a><i><img src="..."></i> Text</a>` |
|
|
385
|
-
| [<i class="fa-brands fa-github fa-lg"></i> Font Awesome icons](#) | `<a><i class="fa-..."></i> Text</a>` |
|
|
386
|
-
</article>
|
|
387
|
-
|
|
388
|
-
Or even for:
|
|
389
|
-
|
|
390
|
-
<article>
|
|
391
|
-
<a href="#" style="margin: 0 0 0 1rem"><i>🥷</i> very-very-very-very-very-<br>long-multiline-links</a>
|
|
392
|
-
</article>
|
|
393
|
-
|
|
394
|
-
How we made it: https://codepen.io/editor/anydigital/pen/019d2b94-5616-75dc-a23e-e111869d5237
|
|
395
|
-
|
|
396
|
-
**PRO** example of automatic favicons for `11ty`: https://blades.ninja/build-awesome-11ty/processors/#auto-link-favicons
|
|
397
|
-
|
|
398
|
-
\3c !--section--> */
|
|
399
|
-
|
|
400
321
|
/*\3c !--section:docs-->
|
|
401
322
|
|
|
402
323
|
## Column expanders
|
|
@@ -418,22 +339,18 @@ Living examples of big tables with `<hr>`-expanders: \3c !--A-Z-->
|
|
|
418
339
|
|
|
419
340
|
How it works:
|
|
420
341
|
```css */
|
|
421
|
-
|
|
422
342
|
th hr {
|
|
423
343
|
visibility: hidden;
|
|
424
344
|
width: 12ch; /* min ~65/12 = ~5 cols */
|
|
425
345
|
height: 0;
|
|
426
346
|
margin: 0;
|
|
427
347
|
}
|
|
428
|
-
|
|
429
348
|
th hr.lg {
|
|
430
349
|
width: 18ch;
|
|
431
350
|
}
|
|
432
|
-
|
|
433
351
|
th hr.x2 {
|
|
434
352
|
width: 24ch;
|
|
435
353
|
}
|
|
436
|
-
|
|
437
354
|
/*```
|
|
438
355
|
|
|
439
356
|
## Borderless table
|
|
@@ -450,16 +367,13 @@ th hr.x2 {
|
|
|
450
367
|
</article>
|
|
451
368
|
|
|
452
369
|
\3c !--section-->*/
|
|
453
|
-
|
|
454
370
|
table.borderless th,
|
|
455
371
|
table.borderless td {
|
|
456
372
|
border: none;
|
|
457
373
|
}
|
|
458
|
-
|
|
459
374
|
/*
|
|
460
375
|
\3c !--section:code-->
|
|
461
376
|
```css */
|
|
462
|
-
|
|
463
377
|
table.responsive,
|
|
464
378
|
.breakout > table:not(.does-not-exist),
|
|
465
379
|
.breakout-all > table:not(.does-not-exist) {
|
|
@@ -479,7 +393,6 @@ table.responsive,
|
|
|
479
393
|
transform: translateX(-50%);
|
|
480
394
|
-webkit-overflow-scrolling: touch; /* Smooth scroll for iOS */
|
|
481
395
|
}
|
|
482
|
-
|
|
483
396
|
table.responsive th,
|
|
484
397
|
table.responsive td,
|
|
485
398
|
.breakout > table:not(.does-not-exist) th,
|
|
@@ -488,7 +401,6 @@ table.responsive th,
|
|
|
488
401
|
.breakout-all > table:not(.does-not-exist) td {
|
|
489
402
|
padding-inline-start: 0;
|
|
490
403
|
}
|
|
491
|
-
|
|
492
404
|
/*```
|
|
493
405
|
`table:not(.does-not-exist)` trick (inspired by postcss) is used here to increase specificity against selectors like `&:is(table, .table)`
|
|
494
406
|
|
|
@@ -516,23 +428,21 @@ Living examples: \3c !--A-Z-->
|
|
|
516
428
|
- https://blades.ninja/ssg/
|
|
517
429
|
|
|
518
430
|
\3c !--section--> */
|
|
519
|
-
|
|
520
431
|
/*\3c !--section:docs-->
|
|
521
432
|
|
|
522
433
|
The `<pre><code>` blocks are Prism-compatible and support captions via `data-caption="..."` attribute:
|
|
523
434
|
|
|
524
|
-
```treeview {data-caption="Blades CSS:"}
|
|
525
|
-
|
|
526
|
-
├── blades.
|
|
527
|
-
├── blades.
|
|
528
|
-
|
|
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)
|
|
529
441
|
```
|
|
530
442
|
|
|
531
443
|
\3c !--section:code-->
|
|
532
444
|
```css */
|
|
533
|
-
|
|
534
445
|
@media (width < 768px) {
|
|
535
|
-
|
|
536
446
|
pre {
|
|
537
447
|
border-radius: 0
|
|
538
448
|
}
|
|
@@ -549,28 +459,43 @@ code[data-caption]::before {
|
|
|
549
459
|
}
|
|
550
460
|
|
|
551
461
|
/* Forms */
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
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-->
|
|
555
468
|
|
|
556
469
|
First, we target either:
|
|
557
470
|
1. `<label>` which `:has` inner form inputs (classless approach)
|
|
558
471
|
2. or explicit `.has-float-label` class (explicit approach)
|
|
559
472
|
|
|
560
473
|
```css */
|
|
561
|
-
|
|
562
|
-
|
|
474
|
+
label:has(> span):has(
|
|
475
|
+
input:not([type="checkbox"], [type="radio"], [type="range"]),
|
|
476
|
+
textarea,
|
|
477
|
+
select
|
|
478
|
+
),
|
|
563
479
|
.has-float-label {
|
|
564
480
|
display: block;
|
|
565
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 */
|
|
566
485
|
}
|
|
567
|
-
|
|
568
486
|
/*```
|
|
569
487
|
Then, we define the default/fallback state (when the float label should be minimized):
|
|
570
488
|
```css */
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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,
|
|
574
499
|
.has-float-label > span,
|
|
575
500
|
.has-float-label label {
|
|
576
501
|
position: absolute;
|
|
@@ -579,46 +504,120 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
579
504
|
font-size: 75%;
|
|
580
505
|
cursor: text;
|
|
581
506
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
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 {
|
|
588
512
|
opacity: 0;
|
|
589
513
|
}
|
|
590
|
-
|
|
591
|
-
|
|
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 {
|
|
592
519
|
opacity: 0;
|
|
593
520
|
}
|
|
594
|
-
|
|
595
|
-
|
|
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 {
|
|
596
526
|
opacity: 0;
|
|
597
527
|
}
|
|
598
|
-
|
|
599
|
-
|
|
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 {
|
|
600
537
|
font-size: inherit;
|
|
601
538
|
opacity: 50%;
|
|
602
539
|
}
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
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,
|
|
606
550
|
.has-float-label:has(*:placeholder-shown:not(:focus)) > span,
|
|
607
551
|
.has-float-label:has(*:placeholder-shown:not(:focus)) label {
|
|
608
552
|
font-size: inherit;
|
|
609
553
|
opacity: 50%;
|
|
610
554
|
}
|
|
611
|
-
|
|
612
555
|
/*```
|
|
613
556
|
|
|
614
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.
|
|
615
558
|
|
|
616
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.
|
|
617
560
|
|
|
618
|
-
|
|
561
|
+
*/
|
|
619
562
|
|
|
620
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-->
|
|
602
|
+
|
|
603
|
+
<article class="breakout-item">
|
|
621
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--> */
|
|
622
621
|
/*\3c !--section:docs-->
|
|
623
622
|
|
|
624
623
|
Use `dl.timeline` or wrap a `<dl>` with `.has-timeline` to style it as a
|
|
@@ -635,18 +634,16 @@ Mar 15, 2025
|
|
|
635
634
|
</article>
|
|
636
635
|
|
|
637
636
|
\3c !--section:code-->```css */
|
|
638
|
-
|
|
639
637
|
dl.timeline dd, .has-timeline > dl dd {
|
|
640
638
|
margin-block: 0;
|
|
641
639
|
padding: 0.25rem 0 0.75rem 1rem;
|
|
642
|
-
border-inline-start: 0.25rem solid
|
|
640
|
+
border-inline-start: 0.25rem solid var(--blades-timeline-border-color);
|
|
643
641
|
}
|
|
644
642
|
|
|
645
643
|
/* Utilities */
|
|
646
|
-
|
|
647
644
|
/*\3c !--section:docs-->
|
|
648
645
|
|
|
649
|
-
##
|
|
646
|
+
## Dark auto
|
|
650
647
|
|
|
651
648
|
`.dark-auto` automatically creates a simple dark version of any element:
|
|
652
649
|
|
|
@@ -656,31 +653,23 @@ dl.timeline dd, .has-timeline > dl dd {
|
|
|
656
653
|
|
|
657
654
|
How it works:
|
|
658
655
|
```css */
|
|
659
|
-
|
|
660
656
|
/* Per https://picocss.com/docs/css-variables#css-variables-for-color-schemes */
|
|
661
|
-
|
|
662
657
|
:root {
|
|
663
658
|
--blades-dark-filter: invert(100%) hue-rotate(180deg);
|
|
664
659
|
}
|
|
665
|
-
|
|
666
660
|
.dark-auto {
|
|
667
661
|
/* Dark color scheme (Forced) */
|
|
668
662
|
}
|
|
669
|
-
|
|
670
663
|
/* Dark color scheme (Auto) */
|
|
671
|
-
|
|
672
664
|
@media (prefers-color-scheme: dark) {
|
|
673
|
-
|
|
674
665
|
.dark-auto {
|
|
675
666
|
filter: var(--blades-dark-filter)
|
|
676
667
|
}
|
|
677
668
|
}
|
|
678
|
-
|
|
679
669
|
.dark-auto[data-theme="dark"],
|
|
680
670
|
.dark-auto:where([data-theme="dark"] *) {
|
|
681
671
|
filter: var(--blades-dark-filter);
|
|
682
672
|
}
|
|
683
|
-
|
|
684
673
|
/*```
|
|
685
674
|
|
|
686
675
|
## Faded
|
|
@@ -693,28 +682,21 @@ How it works:
|
|
|
693
682
|
|
|
694
683
|
How it works:
|
|
695
684
|
```css */
|
|
696
|
-
|
|
697
685
|
.faded {
|
|
698
686
|
opacity: 50%;
|
|
699
687
|
}
|
|
700
|
-
|
|
701
688
|
.faded:hover {
|
|
702
689
|
opacity: 87.5%;
|
|
703
690
|
}
|
|
704
|
-
|
|
705
691
|
/*```
|
|
706
692
|
\3c !--section--> */
|
|
707
693
|
|
|
708
694
|
/* Fix the scrollbar color when inverted by https://tailwindcss.com/docs/filter-invert */
|
|
709
|
-
|
|
710
695
|
.invert ::-webkit-scrollbar {
|
|
711
696
|
filter: invert(1) !important;
|
|
712
697
|
}
|
|
713
|
-
|
|
714
698
|
/*\3c !--section:code-->```css */
|
|
715
|
-
|
|
716
699
|
/* Default/fallback state */
|
|
717
|
-
|
|
718
700
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) > span,
|
|
719
701
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) label,
|
|
720
702
|
.has-float-label > span,
|
|
@@ -724,7 +706,6 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
724
706
|
opacity: 75%;
|
|
725
707
|
transition: all 0.25s;
|
|
726
708
|
}
|
|
727
|
-
|
|
728
709
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) input,
|
|
729
710
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) textarea,
|
|
730
711
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select) select,
|
|
@@ -735,24 +716,19 @@ label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"
|
|
|
735
716
|
padding-inline-start: 1rem; /* match Pico */
|
|
736
717
|
padding-block: 1.125rem 0.375rem; /* match Pico's total: 2 x 0.75rem = 1.5rem */
|
|
737
718
|
}
|
|
738
|
-
|
|
739
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 {
|
|
740
720
|
opacity: 100%;
|
|
741
721
|
-moz-transition: all 0.25s;
|
|
742
722
|
transition: all 0.25s;
|
|
743
723
|
}
|
|
744
|
-
|
|
745
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 {
|
|
746
725
|
opacity: 100%;
|
|
747
726
|
transition: all 0.25s;
|
|
748
727
|
}
|
|
749
|
-
|
|
750
728
|
/* Enlarged state */
|
|
751
|
-
|
|
752
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 {
|
|
753
730
|
padding-block: 0.75rem; /* match Pico */
|
|
754
731
|
}
|
|
755
|
-
|
|
756
732
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) > span,
|
|
757
733
|
label:has(> span):has(input:not([type="checkbox"], [type="radio"], [type="range"]), textarea, select):has(*:placeholder-shown:not(:focus)) label,
|
|
758
734
|
.has-float-label:has(*:placeholder-shown:not(:focus)) > span,
|
|
@@ -813,7 +789,6 @@ h5,
|
|
|
813
789
|
h6 {
|
|
814
790
|
text-wrap: balance;
|
|
815
791
|
}
|
|
816
|
-
|
|
817
792
|
h1 {
|
|
818
793
|
margin-bottom: 1rem; /* for tw-typography */
|
|
819
794
|
font-size: 2.5em; /* for pico.css & tw-typography */
|
|
@@ -858,15 +833,15 @@ table pre {
|
|
|
858
833
|
margin-bottom: 0.25rem;
|
|
859
834
|
}
|
|
860
835
|
|
|
861
|
-
[
|
|
836
|
+
[href="#top"] {
|
|
862
837
|
opacity: 25%;
|
|
863
838
|
}
|
|
864
839
|
|
|
865
|
-
[
|
|
840
|
+
[href="#top"]:hover {
|
|
866
841
|
opacity: 75%;
|
|
867
842
|
}
|
|
868
843
|
|
|
869
|
-
[
|
|
844
|
+
[href="#top"] > i {
|
|
870
845
|
display: inline-block;
|
|
871
846
|
margin: 0.5rem;
|
|
872
847
|
padding: 0.25rem 0.375rem;
|