css-utility-functions 1.0.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/README.md +245 -0
- package/dist/index.css +897 -0
- package/dist/index.min.css +28 -0
- package/package.json +46 -0
- package/src/colors/alpha.css +27 -0
- package/src/colors/complement.css +23 -0
- package/src/colors/contrast-text.css +20 -0
- package/src/colors/darken.css +20 -0
- package/src/colors/desaturate.css +22 -0
- package/src/colors/grayscale.css +22 -0
- package/src/colors/invert.css +22 -0
- package/src/colors/lighten.css +20 -0
- package/src/colors/mix.css +27 -0
- package/src/colors/saturate.css +22 -0
- package/src/effects/diagonal-lines.css +58 -0
- package/src/effects/shadow.css +30 -0
- package/src/index.css +55 -0
- package/src/layout/neg.css +21 -0
- package/src/layout/z-index.css +24 -0
- package/src/logic/and.css +30 -0
- package/src/logic/nand.css +30 -0
- package/src/logic/nor.css +30 -0
- package/src/logic/not.css +23 -0
- package/src/logic/or.css +30 -0
- package/src/logic/xnor.css +30 -0
- package/src/logic/xor.css +30 -0
- package/src/math/circle.css +46 -0
- package/src/math/lerp.css +29 -0
- package/src/math/modular.css +32 -0
- package/src/math/poly-angle.css +27 -0
- package/src/spacing/fluid.css +72 -0
- package/src/spacing/ratio-height.css +29 -0
- package/src/spacing/space.css +30 -0
- package/src/units/to-px.css +19 -0
- package/src/units/to-rem.css +28 -0
package/dist/index.css
ADDED
|
@@ -0,0 +1,897 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CSS Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* A collection of reusable CSS custom functions using the @function syntax.
|
|
5
|
+
* Import this file to use all utility functions in your project.
|
|
6
|
+
*
|
|
7
|
+
* ⚠️ Note: CSS @function is experimental. Check browser support before production use.
|
|
8
|
+
*
|
|
9
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/CSS/@function
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/* Color Utilities */
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* --alpha() — Color Transparency
|
|
16
|
+
*
|
|
17
|
+
* Creates a semi-transparent version of any color.
|
|
18
|
+
* Works exactly like CSS opacity property:
|
|
19
|
+
* - 0 = fully transparent (invisible)
|
|
20
|
+
* - 1 = fully opaque (solid)
|
|
21
|
+
* - 0.5 = 50% opaque (50% transparent)
|
|
22
|
+
*
|
|
23
|
+
* @param {color} --color - The base color
|
|
24
|
+
* @param {number} --opacity - Opacity level (0-1), default: 0.5
|
|
25
|
+
* Higher values = more opaque, lower values = more transparent
|
|
26
|
+
* @returns {color} - Color with applied opacity
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* .overlay {
|
|
30
|
+
* background: --alpha(#6366f1, 0.2); // 20% opaque, 80% transparent
|
|
31
|
+
* }
|
|
32
|
+
* .backdrop {
|
|
33
|
+
* background: --alpha(var(--brand), 0.85); // 85% opaque, 15% transparent
|
|
34
|
+
* }
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
@function --alpha(--color <color>, --opacity <number>: 0.5) returns <color> {
|
|
38
|
+
result: oklch(from var(--color) l c h / var(--opacity));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* --lighten() — Color Luminance Increase
|
|
43
|
+
*
|
|
44
|
+
* Adjust a color's lightness upward.
|
|
45
|
+
* Uses OKLCH lightness channel (0-1 range).
|
|
46
|
+
*
|
|
47
|
+
* @param {color} --color - The base color
|
|
48
|
+
* @param {number} --amount - Amount to lighten (0-1, e.g., 0.1 = 10%, 0.2 = 20%), default: 0.1
|
|
49
|
+
* @returns {color} - Lightened color
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* .btn:hover {
|
|
53
|
+
* background: --lighten(var(--btn-bg), 0.15);
|
|
54
|
+
* }
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
@function --lighten(--color <color>, --amount <number>: 0.1) returns <color> {
|
|
58
|
+
result: oklch(from var(--color) calc(l + var(--amount)) c h);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* --darken() — Color Luminance Decrease
|
|
63
|
+
*
|
|
64
|
+
* Adjust a color's lightness downward.
|
|
65
|
+
* Uses OKLCH lightness channel (0-1 range).
|
|
66
|
+
*
|
|
67
|
+
* @param {color} --color - The base color
|
|
68
|
+
* @param {number} --amount - Amount to darken (0-1, e.g., 0.1 = 10%, 0.2 = 20%), default: 0.1
|
|
69
|
+
* @returns {color} - Darkened color
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* .btn:active {
|
|
73
|
+
* background: --darken(var(--btn-bg), 0.1);
|
|
74
|
+
* }
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
@function --darken(--color <color>, --amount <number>: 0.1) returns <color> {
|
|
78
|
+
result: oklch(from var(--color) calc(l - var(--amount)) c h);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* --saturate() — Color Saturation Increase
|
|
83
|
+
*
|
|
84
|
+
* Adjust a color's chroma (saturation) intensity upward.
|
|
85
|
+
*
|
|
86
|
+
* @param {color} --color - The base color
|
|
87
|
+
* @param {number} --amount - Percentage as decimal (e.g., 0.4 = 40%), default: 0.2
|
|
88
|
+
* @returns {color} - More saturated color
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* .vibrant {
|
|
92
|
+
* background: --saturate(var(--primary), 0.4);
|
|
93
|
+
* }
|
|
94
|
+
*/
|
|
95
|
+
|
|
96
|
+
@function --saturate(
|
|
97
|
+
--color <color>,
|
|
98
|
+
--amount <number>: 0.2
|
|
99
|
+
) returns <color> {
|
|
100
|
+
result: oklch(from var(--color) l calc(c + c * var(--amount)) h);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* --desaturate() — Color Saturation Decrease
|
|
105
|
+
*
|
|
106
|
+
* Adjust a color's chroma (saturation) intensity downward.
|
|
107
|
+
*
|
|
108
|
+
* @param {color} --color - The base color
|
|
109
|
+
* @param {number} --amount - Percentage as decimal (e.g., 0.5 = 50%), default: 0.2
|
|
110
|
+
* @returns {color} - Less saturated (more muted) color
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* .muted {
|
|
114
|
+
* color: --desaturate(var(--text), 0.5);
|
|
115
|
+
* }
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
@function --desaturate(
|
|
119
|
+
--color <color>,
|
|
120
|
+
--amount <number>: 0.2
|
|
121
|
+
) returns <color> {
|
|
122
|
+
result: oklch(from var(--color) l calc(c - c * var(--amount)) h);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* --mix() — Color Mixing
|
|
127
|
+
*
|
|
128
|
+
* Blend two colors by a given percentage.
|
|
129
|
+
*
|
|
130
|
+
* @param {color} --color1 - First color
|
|
131
|
+
* @param {color} --color2 - Second color
|
|
132
|
+
* @param {percentage} --weight - Weight of first color, default: 50%
|
|
133
|
+
* @returns {color} - Mixed color
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* .gradient-mid {
|
|
137
|
+
* background: --mix(var(--start), var(--end), 50%);
|
|
138
|
+
* }
|
|
139
|
+
* .tinted {
|
|
140
|
+
* background: --mix(white, var(--brand), 90%);
|
|
141
|
+
* }
|
|
142
|
+
*/
|
|
143
|
+
|
|
144
|
+
@function --mix(
|
|
145
|
+
--color1 <color>,
|
|
146
|
+
--color2 <color>,
|
|
147
|
+
--weight <percentage>: 50%
|
|
148
|
+
) returns <color> {
|
|
149
|
+
result: color-mix(in oklch, var(--color1) var(--weight), var(--color2));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* --contrast-text() — Auto Contrast Text Color
|
|
154
|
+
*
|
|
155
|
+
* Returns black or white depending on background luminance for optimal readability.
|
|
156
|
+
* Uses a mathematical approach with OKLCH lightness.
|
|
157
|
+
*
|
|
158
|
+
* @param {color} --bg - Background color
|
|
159
|
+
* @returns {color} - Black or white based on luminance
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* .badge {
|
|
163
|
+
* background: var(--badge-color);
|
|
164
|
+
* color: --contrast-text(var(--badge-color));
|
|
165
|
+
* }
|
|
166
|
+
*/
|
|
167
|
+
|
|
168
|
+
@function --contrast-text(--bg <color>) returns <color> {
|
|
169
|
+
result: oklch(from var(--bg) calc((0.6 - l) * infinity) 0 0);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* --grayscale() — Grayscale Conversion
|
|
174
|
+
*
|
|
175
|
+
* Convert any color to grayscale by removing chroma (saturation).
|
|
176
|
+
* Uses OKLCH color space, setting chroma to 0 while preserving lightness.
|
|
177
|
+
*
|
|
178
|
+
* @param {color} --color - The base color
|
|
179
|
+
* @returns {color} - Grayscale version of the color
|
|
180
|
+
*
|
|
181
|
+
* @example
|
|
182
|
+
* .monochrome {
|
|
183
|
+
* background: --grayscale(#6366f1); // Blue becomes gray
|
|
184
|
+
* }
|
|
185
|
+
* .desaturated-image {
|
|
186
|
+
* filter: --grayscale(var(--image-color));
|
|
187
|
+
* }
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
@function --grayscale(--color <color>) returns <color> {
|
|
191
|
+
result: oklch(from var(--color) l 0 h);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* --invert() — Color Inversion
|
|
196
|
+
*
|
|
197
|
+
* Invert a color by flipping its lightness in OKLCH space.
|
|
198
|
+
* Dark colors become light, light colors become dark.
|
|
199
|
+
*
|
|
200
|
+
* @param {color} --color - The base color
|
|
201
|
+
* @returns {color} - Inverted color
|
|
202
|
+
*
|
|
203
|
+
* @example
|
|
204
|
+
* .inverted {
|
|
205
|
+
* background: --invert(#ffffff); // White becomes black
|
|
206
|
+
* }
|
|
207
|
+
* .dark-mode-text {
|
|
208
|
+
* color: --invert(var(--light-text));
|
|
209
|
+
* }
|
|
210
|
+
*/
|
|
211
|
+
|
|
212
|
+
@function --invert(--color <color>) returns <color> {
|
|
213
|
+
result: oklch(from var(--color) calc(1 - l) c h);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* --complement() — Complementary Color
|
|
218
|
+
*
|
|
219
|
+
* Get the complementary color (opposite on color wheel) by rotating hue 180 degrees.
|
|
220
|
+
* Uses OKLCH color space for accurate hue rotation.
|
|
221
|
+
* Note: Achromatic colors (grays) have no hue, so their complement is unchanged.
|
|
222
|
+
*
|
|
223
|
+
* @param {color} --color - The base color
|
|
224
|
+
* @returns {color} - Complementary color
|
|
225
|
+
*
|
|
226
|
+
* @example
|
|
227
|
+
* .accent {
|
|
228
|
+
* background: --complement(#6366f1); // Blue's complement (orange)
|
|
229
|
+
* }
|
|
230
|
+
* .contrast-border {
|
|
231
|
+
* border-color: --complement(var(--primary));
|
|
232
|
+
* }
|
|
233
|
+
*/
|
|
234
|
+
|
|
235
|
+
@function --complement(--color <color>) returns <color> {
|
|
236
|
+
result: oklch(from var(--color) l c calc(h + 180));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* Spacing & Sizing */
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* --space() — Spacing Scale
|
|
243
|
+
*
|
|
244
|
+
* Returns spacing based on a consistent multiplier scale.
|
|
245
|
+
* The base unit can be customized via the --space-base CSS custom property.
|
|
246
|
+
*
|
|
247
|
+
* @param {number} --multiplier - Scale multiplier
|
|
248
|
+
* @param {length} --base - Base spacing unit, default: var(--space-base, 0.25rem)
|
|
249
|
+
* @returns {length} - Calculated spacing
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* :root {
|
|
253
|
+
* --space-base: 0.25rem;
|
|
254
|
+
* }
|
|
255
|
+
*
|
|
256
|
+
* .card {
|
|
257
|
+
* padding: --space(4);
|
|
258
|
+
* margin-bottom: --space(6);
|
|
259
|
+
* gap: --space(2);
|
|
260
|
+
* }
|
|
261
|
+
*
|
|
262
|
+
* .special {
|
|
263
|
+
* padding: --space(4, 0.5rem);
|
|
264
|
+
* }
|
|
265
|
+
*/
|
|
266
|
+
|
|
267
|
+
@function --space(--multiplier <number>, --base <length>: var(--space-base, 0.25rem)) returns <length> {
|
|
268
|
+
result: calc(var(--base) * var(--multiplier));
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* --fluid() — Fluid Viewport-Based Sizing
|
|
273
|
+
*
|
|
274
|
+
* Generates a clamp() value that scales smoothly between viewport widths.
|
|
275
|
+
* Use this for global, viewport-dependent responsive sizing.
|
|
276
|
+
*
|
|
277
|
+
* @param {length} --min - Minimum size
|
|
278
|
+
* @param {length} --max - Maximum size
|
|
279
|
+
* @param {length} --min-vw - Minimum viewport width, default: 375px
|
|
280
|
+
* @param {length} --max-vw - Maximum viewport width, default: 1440px
|
|
281
|
+
* @returns {length} - Fluid clamp value based on viewport width
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* h1 {
|
|
285
|
+
* font-size: --fluid(1.5rem, 4rem);
|
|
286
|
+
* }
|
|
287
|
+
* .container {
|
|
288
|
+
* padding: --fluid(1rem, 3rem, 320px, 1200px);
|
|
289
|
+
* }
|
|
290
|
+
*
|
|
291
|
+
* @see --fluid-container() for container-based fluid sizing
|
|
292
|
+
*/
|
|
293
|
+
|
|
294
|
+
@function --fluid(
|
|
295
|
+
--min <length>,
|
|
296
|
+
--max <length>,
|
|
297
|
+
--min-vw <length>: 375px,
|
|
298
|
+
--max-vw <length>: 1440px
|
|
299
|
+
) returns <length> {
|
|
300
|
+
--slope: calc((var(--max) - var(--min)) / (var(--max-vw) - var(--min-vw)));
|
|
301
|
+
--intercept: calc(var(--min) - var(--slope) * var(--min-vw));
|
|
302
|
+
result: clamp(var(--min), calc(var(--intercept) + var(--slope) * 100vw), var(--max));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* --fluid-container() — Fluid Container-Based Sizing
|
|
307
|
+
*
|
|
308
|
+
* Generates a clamp() value that scales smoothly based on container width.
|
|
309
|
+
* Requires the parent element to have container-type: inline-size or container: name / inline-size.
|
|
310
|
+
* Perfect for component-level responsive design independent of viewport size.
|
|
311
|
+
*
|
|
312
|
+
* @param {length} --min - Minimum size
|
|
313
|
+
* @param {length} --max - Maximum size
|
|
314
|
+
* @param {length} --min-cqw - Minimum container width, default: 20ch
|
|
315
|
+
* @param {length} --max-cqw - Maximum container width, default: 65ch
|
|
316
|
+
* @returns {length} - Fluid clamp value based on container width
|
|
317
|
+
*
|
|
318
|
+
* @example
|
|
319
|
+
* .card {
|
|
320
|
+
* container-type: inline-size;
|
|
321
|
+
* }
|
|
322
|
+
*
|
|
323
|
+
* .card h2 {
|
|
324
|
+
* font-size: --fluid-container(1rem, 2rem);
|
|
325
|
+
* }
|
|
326
|
+
*
|
|
327
|
+
* .card p {
|
|
328
|
+
* font-size: --fluid-container(0.875rem, 1.125rem, 30ch, 60ch);
|
|
329
|
+
* }
|
|
330
|
+
*/
|
|
331
|
+
|
|
332
|
+
@function --fluid-container(
|
|
333
|
+
--min <length>,
|
|
334
|
+
--max <length>,
|
|
335
|
+
--min-cqw <length>: 20ch,
|
|
336
|
+
--max-cqw <length>: 65ch
|
|
337
|
+
) returns <length> {
|
|
338
|
+
--slope: calc((var(--max) - var(--min)) / (var(--max-cqw) - var(--min-cqw)));
|
|
339
|
+
--intercept: calc(var(--min) - var(--slope) * var(--min-cqw));
|
|
340
|
+
result: clamp(var(--min), calc(var(--intercept) + var(--slope) * 100cqw), var(--max));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* --ratio-height() — Aspect Ratio Height
|
|
345
|
+
*
|
|
346
|
+
* Calculate height from width and aspect ratio (useful for images/containers).
|
|
347
|
+
*
|
|
348
|
+
* @param {length} --width - Element width
|
|
349
|
+
* @param {number} --ratio-w - Ratio width part, default: 16
|
|
350
|
+
* @param {number} --ratio-h - Ratio height part, default: 9
|
|
351
|
+
* @returns {length} - Calculated height
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* .video-thumb {
|
|
355
|
+
* width: 320px;
|
|
356
|
+
* height: --ratio-height(320px, 16, 9);
|
|
357
|
+
* }
|
|
358
|
+
* .square-avatar {
|
|
359
|
+
* width: 48px;
|
|
360
|
+
* height: --ratio-height(48px, 1, 1);
|
|
361
|
+
* }
|
|
362
|
+
*/
|
|
363
|
+
|
|
364
|
+
@function --ratio-height(
|
|
365
|
+
--width <length>,
|
|
366
|
+
--ratio-w <number>: 16,
|
|
367
|
+
--ratio-h <number>: 9
|
|
368
|
+
) returns <length> {
|
|
369
|
+
result: calc(var(--width) * var(--ratio-h) / var(--ratio-w));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* Visual Effects */
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* --shadow() — Elevation Shadows
|
|
376
|
+
*
|
|
377
|
+
* Generates layered box-shadows based on elevation level (1-5).
|
|
378
|
+
*
|
|
379
|
+
* @param {number} --level - Elevation level (1-5)
|
|
380
|
+
* @param {color} --color - Shadow color, default: oklch(0% 0 0 / 0.1)
|
|
381
|
+
* @returns {string} - Layered box-shadow value (comma-separated shadow list)
|
|
382
|
+
*
|
|
383
|
+
* @example
|
|
384
|
+
* .card {
|
|
385
|
+
* box-shadow: --shadow(2);
|
|
386
|
+
* }
|
|
387
|
+
* .modal {
|
|
388
|
+
* box-shadow: --shadow(5, oklch(0% 0 0 / 0.25));
|
|
389
|
+
* }
|
|
390
|
+
*/
|
|
391
|
+
|
|
392
|
+
@function --shadow(
|
|
393
|
+
--level <number>,
|
|
394
|
+
--color <color>: oklch(0% 0 0 / 0.1)
|
|
395
|
+
) {
|
|
396
|
+
--y: calc(var(--level) * 2px);
|
|
397
|
+
--blur: calc(var(--level) * 4px);
|
|
398
|
+
--spread: calc(var(--level) * -1px);
|
|
399
|
+
result:
|
|
400
|
+
0 var(--y) var(--blur) var(--spread) var(--color),
|
|
401
|
+
0 calc(var(--y) * 0.5) calc(var(--blur) * 0.5) calc(var(--spread) * 0.5) var(--color);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* --diagonal-lines() — Diagonal Line Pattern Background
|
|
406
|
+
*
|
|
407
|
+
* Generate a repeating diagonal line pattern with configurable angle, colors, and spacing.
|
|
408
|
+
* Returns a complete repeating-linear-gradient that can be used directly as a background value.
|
|
409
|
+
*
|
|
410
|
+
* @param {angle} --angle - Angle of the lines, default: -45deg
|
|
411
|
+
* @param {color} --line-color - Color of the lines, default: currentColor
|
|
412
|
+
* @param {length} --line-width - Width of each line, default: 1px
|
|
413
|
+
* @param {length} --gap-width - Width of the gap between lines, default: 4px
|
|
414
|
+
* @param {color} --gap-color - Color of the gap (background), default: transparent
|
|
415
|
+
* @returns {image} - Complete repeating-linear-gradient value
|
|
416
|
+
*
|
|
417
|
+
* Related - https://stackoverflow.com/questions/33091401/background-image-linear-gradient-jagged-edged-result-needs-to-be-smooth-edged
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* .bg-diagonal {
|
|
421
|
+
* background: --diagonal-lines();
|
|
422
|
+
* }
|
|
423
|
+
*
|
|
424
|
+
* @example
|
|
425
|
+
* .custom-stripes {
|
|
426
|
+
* background: --diagonal-lines(
|
|
427
|
+
* --angle: 45deg,
|
|
428
|
+
* --line-color: #3b82f6,
|
|
429
|
+
* --line-width: 2px,
|
|
430
|
+
* --gap-width: 8px
|
|
431
|
+
* );
|
|
432
|
+
* }
|
|
433
|
+
*
|
|
434
|
+
* @example
|
|
435
|
+
* .subtle-pattern {
|
|
436
|
+
* color: #94a3b8;
|
|
437
|
+
* background: --diagonal-lines(
|
|
438
|
+
* --line-color: currentColor,
|
|
439
|
+
* --line-width: 1px,
|
|
440
|
+
* --gap-width: 10px
|
|
441
|
+
* );
|
|
442
|
+
* }
|
|
443
|
+
*/
|
|
444
|
+
|
|
445
|
+
@function --diagonal-lines(
|
|
446
|
+
--angle <angle>: -45deg,
|
|
447
|
+
--line-color <color>: currentColor,
|
|
448
|
+
--line-width <length>: 1px,
|
|
449
|
+
--gap-width <length>: 4px,
|
|
450
|
+
--gap-color <color>: transparent
|
|
451
|
+
) returns <image> {
|
|
452
|
+
result: repeating-linear-gradient(
|
|
453
|
+
var(--angle),
|
|
454
|
+
var(--line-color) 0,
|
|
455
|
+
var(--line-color) calc(var(--line-width) - 1px),
|
|
456
|
+
var(--gap-color) calc(var(--line-width) + 1px),
|
|
457
|
+
var(--gap-color) calc(var(--line-width) + var(--gap-width))
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/* Layout Utilities */
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* --z() — Z-Index Scale
|
|
465
|
+
*
|
|
466
|
+
* Named z-index layers to avoid magic numbers and conflicts.
|
|
467
|
+
*
|
|
468
|
+
* Layer reference:
|
|
469
|
+
* 1: dropdown, 2: sticky, 3: fixed,
|
|
470
|
+
* 4: drawer, 5: modal, 6: popover,
|
|
471
|
+
* 7: tooltip, 8: toast, 9: max
|
|
472
|
+
*
|
|
473
|
+
* @param {number} --layer - Layer number (1-9)
|
|
474
|
+
* @returns {integer} - Z-index value (layer × 100)
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* .dropdown { z-index: --z(1); }
|
|
478
|
+
* .header { z-index: --z(3); }
|
|
479
|
+
* .modal { z-index: --z(5); }
|
|
480
|
+
* .tooltip { z-index: --z(7); }
|
|
481
|
+
*/
|
|
482
|
+
|
|
483
|
+
@function --z(--layer <number>) returns <integer> {
|
|
484
|
+
result: calc(var(--layer) * 100);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* --neg() — Negative Value
|
|
489
|
+
*
|
|
490
|
+
* Simple negation — useful in calc-heavy layouts.
|
|
491
|
+
*
|
|
492
|
+
* @param {length} --value - Value to negate
|
|
493
|
+
* @returns {length} - Negative value
|
|
494
|
+
*
|
|
495
|
+
* @example
|
|
496
|
+
* .pull-up {
|
|
497
|
+
* margin-top: --neg(var(--header-height));
|
|
498
|
+
* }
|
|
499
|
+
* .bleed {
|
|
500
|
+
* margin-inline: --neg(var(--container-padding));
|
|
501
|
+
* }
|
|
502
|
+
*/
|
|
503
|
+
|
|
504
|
+
@function --neg(--value <length>) returns <length> {
|
|
505
|
+
result: calc(var(--value) * -1);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/* Math Utilities */
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* --lerp() — Linear Interpolation
|
|
512
|
+
*
|
|
513
|
+
* Interpolates between two values using a t parameter (0-1).
|
|
514
|
+
* When t=0, returns a; when t=1, returns b; when t=0.5, returns midpoint.
|
|
515
|
+
* Hides the complex calc expression: calc(a + (b - a) * t)
|
|
516
|
+
*
|
|
517
|
+
* @param {length-percentage} --a - Start value
|
|
518
|
+
* @param {length-percentage} --b - End value
|
|
519
|
+
* @param {number} --t - Interpolation factor (0-1), default: 0.5
|
|
520
|
+
* @returns {length-percentage} - Interpolated value
|
|
521
|
+
*
|
|
522
|
+
* @example
|
|
523
|
+
* .animated {
|
|
524
|
+
* width: --lerp(100px, 500px, 0.3); // 30% between 100px and 500px
|
|
525
|
+
* }
|
|
526
|
+
* .transition {
|
|
527
|
+
* width: --lerp(10%, 80%, 0.75); // 75% between 10% and 80%
|
|
528
|
+
* }
|
|
529
|
+
*/
|
|
530
|
+
|
|
531
|
+
@function --lerp(
|
|
532
|
+
--a <length-percentage>,
|
|
533
|
+
--b <length-percentage>,
|
|
534
|
+
--t <number>: 0.5
|
|
535
|
+
) returns <length-percentage> {
|
|
536
|
+
result: calc(var(--a) * (1 - var(--t)) + var(--b) * var(--t));
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/**
|
|
540
|
+
* --circle-x() — Circle X Position
|
|
541
|
+
*
|
|
542
|
+
* Calculate X coordinate on a circle using radius and angle.
|
|
543
|
+
* Uses cosine: r * cos(deg)
|
|
544
|
+
*
|
|
545
|
+
* @param {length} --radius - Circle radius
|
|
546
|
+
* @param {angle} --angle - Angle in degrees, default: 0deg
|
|
547
|
+
* @returns {length} - X coordinate offset from center
|
|
548
|
+
*
|
|
549
|
+
* @example
|
|
550
|
+
* .orbit {
|
|
551
|
+
* left: calc(50% + --circle-x(100px, 45deg)); // 45° position
|
|
552
|
+
* }
|
|
553
|
+
*/
|
|
554
|
+
|
|
555
|
+
@function --circle-x(
|
|
556
|
+
--radius <length>,
|
|
557
|
+
--angle <angle>: 0deg
|
|
558
|
+
) returns <length> {
|
|
559
|
+
result: calc(var(--radius) * cos(var(--angle)));
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* --circle-y() — Circle Y Position
|
|
564
|
+
*
|
|
565
|
+
* Calculate Y coordinate on a circle using radius and angle.
|
|
566
|
+
* Uses sine: r * sin(deg)
|
|
567
|
+
*
|
|
568
|
+
* @param {length} --radius - Circle radius
|
|
569
|
+
* @param {angle} --angle - Angle in degrees, default: 0deg
|
|
570
|
+
* @returns {length} - Y coordinate offset from center
|
|
571
|
+
*
|
|
572
|
+
* @example
|
|
573
|
+
* .orbit {
|
|
574
|
+
* top: calc(50% + --circle-y(100px, 45deg)); // 45° position
|
|
575
|
+
* }
|
|
576
|
+
*/
|
|
577
|
+
|
|
578
|
+
@function --circle-y(
|
|
579
|
+
--radius <length>,
|
|
580
|
+
--angle <angle>: 0deg
|
|
581
|
+
) returns <length> {
|
|
582
|
+
result: calc(var(--radius) * sin(var(--angle)));
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* --modular() — Modular Scale (Typographic Scale)
|
|
587
|
+
*
|
|
588
|
+
* Calculate values using a modular scale (typographic ratio).
|
|
589
|
+
* Hides the pow calculation: base * pow(ratio, step)
|
|
590
|
+
*
|
|
591
|
+
* @param {number} --step - Scale step (can be negative for smaller values)
|
|
592
|
+
* @param {length|number} --base - Base value, default: 1rem
|
|
593
|
+
* @param {number} --ratio - Scale ratio, default: 1.25 (major third)
|
|
594
|
+
* @returns {length|number} - Scaled value
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* :root {
|
|
598
|
+
* --type-base: 1rem;
|
|
599
|
+
* --type-ratio: 1.25;
|
|
600
|
+
* }
|
|
601
|
+
* h1 {
|
|
602
|
+
* font-size: --modular(4, var(--type-base), var(--type-ratio)); // Large scale
|
|
603
|
+
* }
|
|
604
|
+
* small {
|
|
605
|
+
* font-size: --modular(-1, var(--type-base), var(--type-ratio)); // Smaller
|
|
606
|
+
* }
|
|
607
|
+
*/
|
|
608
|
+
|
|
609
|
+
@function --modular(
|
|
610
|
+
--step <number>,
|
|
611
|
+
--base <length|number>: 1rem,
|
|
612
|
+
--ratio <number>: 1.25
|
|
613
|
+
) returns <length|number> {
|
|
614
|
+
result: calc(var(--base) * pow(var(--ratio), var(--step)));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
/**
|
|
618
|
+
* --poly-angle() — Polygon Vertex Angle
|
|
619
|
+
*
|
|
620
|
+
* Calculate the angle for a vertex in a regular polygon.
|
|
621
|
+
* Useful for creating polygon shapes with CSS transforms.
|
|
622
|
+
* Formula: (360deg / sides * index) - 90deg
|
|
623
|
+
*
|
|
624
|
+
* @param {number} --sides - Number of sides in polygon
|
|
625
|
+
* @param {number} --index - Vertex index (0-based), default: 0
|
|
626
|
+
* @returns {angle} - Angle in degrees
|
|
627
|
+
*
|
|
628
|
+
* @example
|
|
629
|
+
* .hexagon-vertex-0 {
|
|
630
|
+
* transform: rotate(--poly-angle(6, 0)); // First vertex of hexagon
|
|
631
|
+
* }
|
|
632
|
+
* .pentagon-vertex-2 {
|
|
633
|
+
* transform: rotate(--poly-angle(5, 2)); // Third vertex of pentagon
|
|
634
|
+
* }
|
|
635
|
+
*/
|
|
636
|
+
|
|
637
|
+
@function --poly-angle(
|
|
638
|
+
--sides <number>,
|
|
639
|
+
--index <number>: 0
|
|
640
|
+
) returns <angle> {
|
|
641
|
+
result: calc(360deg / var(--sides) * var(--index) - 90deg);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/* Unit Conversion */
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* --to-rem() — Pixel to REM Conversion
|
|
648
|
+
*
|
|
649
|
+
* Convert a pixel value to rem units. Base pixel size defaults to --rem-base (or 16px).
|
|
650
|
+
*
|
|
651
|
+
* @param {number} --px - Pixel value (unitless)
|
|
652
|
+
* @param {number} --base - Base pixel size for conversion, defaults to var(--rem-base, 16)
|
|
653
|
+
* @returns {length} - REM value
|
|
654
|
+
*
|
|
655
|
+
* @example
|
|
656
|
+
* .legacy-compat {
|
|
657
|
+
* font-size: --to-rem(18);
|
|
658
|
+
* padding: --to-rem(24);
|
|
659
|
+
* }
|
|
660
|
+
*
|
|
661
|
+
* .custom-base {
|
|
662
|
+
* font-size: --to-rem(18, 10);
|
|
663
|
+
* }
|
|
664
|
+
*
|
|
665
|
+
* :root {
|
|
666
|
+
* --rem-base: 20;
|
|
667
|
+
* }
|
|
668
|
+
*/
|
|
669
|
+
|
|
670
|
+
@function --to-rem(--px <number>, --base <number>: var(--rem-base, 16)) returns <length> {
|
|
671
|
+
result: calc(var(--px) * 1rem / var(--base));
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/**
|
|
675
|
+
* --to-px() — REM to Pixel Conversion
|
|
676
|
+
*
|
|
677
|
+
* Convert a rem value to pixels (assumes 16px base).
|
|
678
|
+
*
|
|
679
|
+
* @param {number} --rem - REM value (unitless)
|
|
680
|
+
* @returns {length} - Pixel value
|
|
681
|
+
*
|
|
682
|
+
* @example
|
|
683
|
+
* .legacy-system {
|
|
684
|
+
* width: --to-px(10);
|
|
685
|
+
* height: --to-px(5);
|
|
686
|
+
* }
|
|
687
|
+
*/
|
|
688
|
+
|
|
689
|
+
@function --to-px(--rem <number>) returns <length> {
|
|
690
|
+
result: calc(var(--rem) * 16 * 1px);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
/* Logic Operations */
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* --not() — Boolean Negation
|
|
697
|
+
*
|
|
698
|
+
* Inverts a boolean value (switch variable). Works with values 0 and 1.
|
|
699
|
+
* Returns 1 if input is 0, returns 0 if input is 1.
|
|
700
|
+
*
|
|
701
|
+
* @param {number} --value - Switch variable (0 or 1)
|
|
702
|
+
* @returns {number} - Inverted value (0 or 1)
|
|
703
|
+
*
|
|
704
|
+
* @example
|
|
705
|
+
* .toggle {
|
|
706
|
+
* --is-active: 1;
|
|
707
|
+
* --is-inactive: --not(var(--is-active)); // 0
|
|
708
|
+
* opacity: --not(var(--is-hidden));
|
|
709
|
+
* }
|
|
710
|
+
*
|
|
711
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
712
|
+
*/
|
|
713
|
+
|
|
714
|
+
@function --not(--value <number>) returns <number> {
|
|
715
|
+
result: calc(1 - var(--value));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
/**
|
|
719
|
+
* --and() — Logical AND Operation
|
|
720
|
+
*
|
|
721
|
+
* Returns 1 if both operands are 1, otherwise returns 0.
|
|
722
|
+
* Uses multiplication since any value multiplied by 0 equals 0.
|
|
723
|
+
*
|
|
724
|
+
* Truth table:
|
|
725
|
+
* - 0 AND 0 = 0
|
|
726
|
+
* - 0 AND 1 = 0
|
|
727
|
+
* - 1 AND 0 = 0
|
|
728
|
+
* - 1 AND 1 = 1
|
|
729
|
+
*
|
|
730
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
731
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
732
|
+
* @returns {number} - Result (0 or 1)
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* .visible-on-mobile-and-dark {
|
|
736
|
+
* --is-mobile: 1;
|
|
737
|
+
* --is-dark-mode: 1;
|
|
738
|
+
* display: --and(var(--is-mobile), var(--is-dark-mode));
|
|
739
|
+
* }
|
|
740
|
+
*
|
|
741
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
742
|
+
*/
|
|
743
|
+
|
|
744
|
+
@function --and(--a <number>, --b <number>) returns <number> {
|
|
745
|
+
result: calc(var(--a) * var(--b));
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* --or() — Logical OR Operation
|
|
750
|
+
*
|
|
751
|
+
* Returns 1 if at least one operand is 1, otherwise returns 0.
|
|
752
|
+
* Uses De Morgan's law: NOT (A OR B) = (NOT A) AND (NOT B)
|
|
753
|
+
*
|
|
754
|
+
* Truth table:
|
|
755
|
+
* - 0 OR 0 = 0
|
|
756
|
+
* - 0 OR 1 = 1
|
|
757
|
+
* - 1 OR 0 = 1
|
|
758
|
+
* - 1 OR 1 = 1
|
|
759
|
+
*
|
|
760
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
761
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
762
|
+
* @returns {number} - Result (0 or 1)
|
|
763
|
+
*
|
|
764
|
+
* @example
|
|
765
|
+
* .show-on-mobile-or-tablet {
|
|
766
|
+
* --is-mobile: 0;
|
|
767
|
+
* --is-tablet: 1;
|
|
768
|
+
* display: --or(var(--is-mobile), var(--is-tablet));
|
|
769
|
+
* }
|
|
770
|
+
*
|
|
771
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
772
|
+
*/
|
|
773
|
+
|
|
774
|
+
@function --or(--a <number>, --b <number>) returns <number> {
|
|
775
|
+
result: calc(1 - (1 - var(--a)) * (1 - var(--b)));
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* --xor() — Exclusive OR Operation
|
|
780
|
+
*
|
|
781
|
+
* Returns 1 if exactly one operand is 1, otherwise returns 0.
|
|
782
|
+
* Uses subtraction squared to get absolute value: (a - b)²
|
|
783
|
+
*
|
|
784
|
+
* Truth table:
|
|
785
|
+
* - 0 XOR 0 = 0 (both same)
|
|
786
|
+
* - 0 XOR 1 = 1 (different)
|
|
787
|
+
* - 1 XOR 0 = 1 (different)
|
|
788
|
+
* - 1 XOR 1 = 0 (both same)
|
|
789
|
+
*
|
|
790
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
791
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
792
|
+
* @returns {number} - Result (0 or 1)
|
|
793
|
+
*
|
|
794
|
+
* @example
|
|
795
|
+
* .highlight-when-different {
|
|
796
|
+
* --user-theme: 1;
|
|
797
|
+
* --system-theme: 0;
|
|
798
|
+
* opacity: --xor(var(--user-theme), var(--system-theme));
|
|
799
|
+
* }
|
|
800
|
+
*
|
|
801
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
802
|
+
*/
|
|
803
|
+
|
|
804
|
+
@function --xor(--a <number>, --b <number>) returns <number> {
|
|
805
|
+
result: calc((var(--a) - var(--b)) * (var(--a) - var(--b)));
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/**
|
|
809
|
+
* --nand() — Logical NAND Operation (NOT AND)
|
|
810
|
+
*
|
|
811
|
+
* Returns 0 if both operands are 1, otherwise returns 1.
|
|
812
|
+
* Combination of NOT and AND operations.
|
|
813
|
+
*
|
|
814
|
+
* Truth table:
|
|
815
|
+
* - 0 NAND 0 = 1
|
|
816
|
+
* - 0 NAND 1 = 1
|
|
817
|
+
* - 1 NAND 0 = 1
|
|
818
|
+
* - 1 NAND 1 = 0
|
|
819
|
+
*
|
|
820
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
821
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
822
|
+
* @returns {number} - Result (0 or 1)
|
|
823
|
+
*
|
|
824
|
+
* @example
|
|
825
|
+
* .hide-when-both-active {
|
|
826
|
+
* --feature-a: 1;
|
|
827
|
+
* --feature-b: 1;
|
|
828
|
+
* display: --nand(var(--feature-a), var(--feature-b));
|
|
829
|
+
* }
|
|
830
|
+
*
|
|
831
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
832
|
+
*/
|
|
833
|
+
|
|
834
|
+
@function --nand(--a <number>, --b <number>) returns <number> {
|
|
835
|
+
result: calc(1 - var(--a) * var(--b));
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
/**
|
|
839
|
+
* --nor() — Logical NOR Operation (NOT OR)
|
|
840
|
+
*
|
|
841
|
+
* Returns 1 if both operands are 0, otherwise returns 0.
|
|
842
|
+
* Combination of NOT and OR operations.
|
|
843
|
+
*
|
|
844
|
+
* Truth table:
|
|
845
|
+
* - 0 NOR 0 = 1
|
|
846
|
+
* - 0 NOR 1 = 0
|
|
847
|
+
* - 1 NOR 0 = 0
|
|
848
|
+
* - 1 NOR 1 = 0
|
|
849
|
+
*
|
|
850
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
851
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
852
|
+
* @returns {number} - Result (0 or 1)
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* .show-default-state {
|
|
856
|
+
* --has-custom-bg: 0;
|
|
857
|
+
* --has-custom-text: 0;
|
|
858
|
+
* opacity: --nor(var(--has-custom-bg), var(--has-custom-text));
|
|
859
|
+
* }
|
|
860
|
+
*
|
|
861
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
862
|
+
*/
|
|
863
|
+
|
|
864
|
+
@function --nor(--a <number>, --b <number>) returns <number> {
|
|
865
|
+
result: calc((1 - var(--a)) * (1 - var(--b)));
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* --xnor() — Exclusive NOR Operation (NOT XOR)
|
|
870
|
+
*
|
|
871
|
+
* Returns 1 if both operands are the same, otherwise returns 0.
|
|
872
|
+
* The opposite of XOR - checks for equality.
|
|
873
|
+
*
|
|
874
|
+
* Truth table:
|
|
875
|
+
* - 0 XNOR 0 = 1 (both same)
|
|
876
|
+
* - 0 XNOR 1 = 0 (different)
|
|
877
|
+
* - 1 XNOR 0 = 0 (different)
|
|
878
|
+
* - 1 XNOR 1 = 1 (both same)
|
|
879
|
+
*
|
|
880
|
+
* @param {number} --a - First switch variable (0 or 1)
|
|
881
|
+
* @param {number} --b - Second switch variable (0 or 1)
|
|
882
|
+
* @returns {number} - Result (0 or 1)
|
|
883
|
+
*
|
|
884
|
+
* @example
|
|
885
|
+
* .sync-indicator {
|
|
886
|
+
* --local-state: 1;
|
|
887
|
+
* --remote-state: 1;
|
|
888
|
+
* opacity: --xnor(var(--local-state), var(--remote-state));
|
|
889
|
+
* }
|
|
890
|
+
*
|
|
891
|
+
* @see https://css-tricks.com/logical-operations-with-css-variables/
|
|
892
|
+
*/
|
|
893
|
+
|
|
894
|
+
@function --xnor(--a <number>, --b <number>) returns <number> {
|
|
895
|
+
result: calc(1 - (var(--a) - var(--b)) * (var(--a) - var(--b)));
|
|
896
|
+
}
|
|
897
|
+
|