strata-css 1.0.2 → 1.0.3

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.
Files changed (4) hide show
  1. package/README.md +730 -730
  2. package/bin/strata.js +276 -177
  3. package/package.json +68 -68
  4. package/src/index.js +171 -171
package/README.md CHANGED
@@ -1,730 +1,730 @@
1
- <div align="center">
2
-
3
- # Strata CSS
4
-
5
- **A modern CSS framework combining Bootstrap's component architecture with Tailwind's JIT processing.**
6
-
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
- [![Version](https://img.shields.io/badge/version-1.0.0-green.svg)]()
9
- [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)]()
10
- [![npm](https://img.shields.io/badge/npm-strata--css-red.svg)](https://www.npmjs.com/package/strata-css)
11
- [![css-framework](https://img.shields.io/badge/css--framework-%E2%9C%93-blue.svg)]()
12
- [![PostCSS plugin](https://img.shields.io/badge/postcss-plugin-orange.svg)]()
13
- [![JIT](https://img.shields.io/badge/JIT-enabled-green.svg)]()
14
- [![Themes](https://img.shields.io/badge/themes-light%20%7C%20dark%20%7C%20dim-purple.svg)]()
15
-
16
- `css-framework` · `tailwindcss` · `bootstrap` · `postcss` · `postcss-plugin` · `jit` · `component-library` · `theming` · `utility-first`
17
-
18
- [Getting Started](#getting-started) · [Live Demo](#live-demo) · [Components](#components) · [Utilities](#utilities) · [Theming](#theming) · [Configuration](#configuration)
19
-
20
- </div>
21
-
22
- ---
23
-
24
- ## What is Strata?
25
-
26
- Strata is an open source CSS framework that takes the best from Bootstrap and Tailwind while fixing their biggest pain points.
27
-
28
- **From Bootstrap** — component-first classes (`btn-primary`, `card`, `navbar`) that work out of the box with zero configuration.
29
-
30
- **From Tailwind** — JIT post-processing that generates only the CSS you actually use, keeping output lean.
31
-
32
- **Strata's own contributions:**
33
- - No `!important` anywhere in framework CSS — `@layer` handles all specificity
34
- - Custom CSS is fully compatible and always wins automatically
35
- - Three built-in themes: light, dark, and dim — plus unlimited custom themes
36
- - Buttery smooth transitions built in by default on all interactive elements
37
- - State management via `data-st-*` attributes — no class toggling in JavaScript
38
- - Arbitrary value utilities — `mt-[24px]`, `bg-[#ff0000]`, `w-[347px]`
39
-
40
- ---
41
-
42
- ## Benchmarks
43
-
44
- Strata outperforms Tailwind on every metric in watch mode — the speed developers actually feel on every file save.
45
-
46
- | Metric | Strata | Tailwind |
47
- |---|---|---|
48
- | Cold build average | 1.89ms | 7.21ms |
49
- | Cold build median | 0.15ms | 4.55ms |
50
- | Warm rebuild average | 0.14ms | 2.70ms |
51
- | Warm rebuild p95 | 0.23ms | 6.12ms |
52
-
53
- Results generated via `npm run benchmark`. See [`benchmark/`](./benchmark/) for the reproducible script.
54
-
55
- ---
56
-
57
- ## Live Demo
58
-
59
- View the interactive component showcase: [aftabibrahimkazi.github.io/strata](https://aftabibrahimkazi.github.io/strata)
60
-
61
- To view locally: open `docs/index.html` directly in a browser — no build step required.
62
-
63
- ---
64
-
65
- ## Getting Started
66
-
67
- ### Installation
68
-
69
- ```bash
70
- npm install strata-css
71
- ```
72
-
73
- > **Publishing:** Run `npm publish --dry-run` to verify the package contents, then `npm publish` to release.
74
-
75
- ### Scaffold a new project
76
-
77
- ```bash
78
- npx strata init
79
- ```
80
-
81
- This creates:
82
- ```
83
- strata.config.js ← configuration
84
- strata.css ← entry point with @strata directives
85
- postcss.config.js ← PostCSS setup
86
- dist/ ← generated CSS output
87
- ```
88
-
89
- ### Link the output CSS in your HTML
90
-
91
- ```html
92
- <link rel="stylesheet" href="dist/strata.output.css">
93
- ```
94
-
95
- ### Set a theme on your HTML element
96
-
97
- ```html
98
- <html data-st-theme="light">
99
- ```
100
-
101
- ### Run in development
102
-
103
- ```bash
104
- npm run dev
105
- ```
106
-
107
- ### Build for production
108
-
109
- ```bash
110
- npm run build
111
- ```
112
-
113
- ---
114
-
115
- ## How It Works
116
-
117
- Strata is a PostCSS plugin. It scans your source files for class names and generates only the CSS those classes need — nothing more.
118
-
119
- ```
120
- Source files (HTML/JSX/Vue/Astro)
121
-
122
- Scanner (extracts class names)
123
-
124
- Registry (O(1) Map lookup)
125
-
126
- Generator (builds CSS)
127
-
128
- @layer st-base, st-components, st-utilities
129
-
130
- Output CSS
131
- ```
132
-
133
- Your custom CSS lives outside any layer and automatically wins over Strata styles — no `!important` needed.
134
-
135
- ---
136
-
137
- ## Components
138
-
139
- Components are full Bootstrap-style classes with states baked in. They live in `@layer st-components` so your custom CSS always overrides them.
140
-
141
- ### Buttons
142
-
143
- ```html
144
- <button class="btn-primary">Primary</button>
145
- <button class="btn-secondary">Secondary</button>
146
- <button class="btn-success">Success</button>
147
- <button class="btn-danger">Danger</button>
148
- <button class="btn-warning">Warning</button>
149
- <button class="btn-info">Info</button>
150
- <button class="btn-light">Light</button>
151
- <button class="btn-dark">Dark</button>
152
- ```
153
-
154
- ### Layout
155
-
156
- ```html
157
- <div class="container">
158
- <div class="row">
159
- <div class="col-md-6 col-lg-4">Column</div>
160
- <div class="col-md-6 col-lg-8">Column</div>
161
- </div>
162
- </div>
163
- ```
164
-
165
- ### Cards
166
-
167
- ```html
168
- <div class="card">
169
- <div class="card-header">Header</div>
170
- <div class="card-body">Body</div>
171
- <div class="card-footer">Footer</div>
172
- </div>
173
- ```
174
-
175
- ---
176
-
177
- ## Utilities
178
-
179
- Utilities follow Bootstrap's naming convention and support arbitrary values via Tailwind-style syntax.
180
-
181
- ### Spacing
182
-
183
- ```html
184
- <!-- Scale values (0-5) -->
185
- <div class="mt-3 mb-2 px-4 py-1">
186
- <div class="mx-auto my-3">
187
-
188
- <!-- Arbitrary values -->
189
- <div class="mt-[24px] px-[1.5rem]">
190
-
191
- <!-- Important variants -->
192
- <div class="!mt-0 !mb-0">
193
- ```
194
-
195
- ### Display
196
-
197
- ```html
198
- <div class="d-flex">
199
- <div class="d-none">
200
- <div class="d-block">
201
- <div class="d-grid">
202
-
203
- <!-- Responsive -->
204
- <div class="d-none d-md-flex">
205
- ```
206
-
207
- ### Colours
208
-
209
- ```html
210
- <!-- Text -->
211
- <p class="text-primary">
212
- <p class="text-[#ff0000]">
213
-
214
- <!-- Background -->
215
- <div class="bg-success">
216
- <div class="bg-[rgba(0,0,0,0.5)]">
217
- ```
218
-
219
- ---
220
-
221
- ## Theming
222
-
223
- ### Built-in themes
224
-
225
- ```html
226
- <html data-st-theme="light"> <!-- default -->
227
- <html data-st-theme="dark"> <!-- dark mode -->
228
- <html data-st-theme="dim"> <!-- intermediate -->
229
- ```
230
-
231
- ### System preference
232
-
233
- If no `data-st-theme` is set, Strata automatically follows the user's system preference via `prefers-color-scheme`.
234
-
235
- ### Custom theme
236
-
237
- ```css
238
- [data-st-theme="brand"] {
239
- --st-primary: #7c3aed;
240
- --st-bg: #0f0f0f;
241
- --st-text: #fafafa;
242
- }
243
- ```
244
-
245
- ```html
246
- <html data-st-theme="brand">
247
- ```
248
-
249
- ### Switch theme with JavaScript
250
-
251
- ```js
252
- document.documentElement.setAttribute('data-st-theme', 'dark')
253
- ```
254
-
255
- ### Theme Toggle
256
-
257
- Cycle through all built-in themes with a single button — no framework needed.
258
-
259
- ```html
260
- <button id="theme-toggle">Toggle Theme</button>
261
-
262
- <script>
263
- const themes = ['light', 'dark', 'dim']
264
- let current = 0
265
-
266
- document.getElementById('theme-toggle').addEventListener('click', () => {
267
- current = (current + 1) % themes.length
268
- document.documentElement.setAttribute('data-st-theme', themes[current])
269
- })
270
- </script>
271
- ```
272
-
273
- To start from the user's current theme rather than always resetting to `light`, read the attribute first:
274
-
275
- ```js
276
- const themes = ['light', 'dark', 'dim']
277
- const initial = document.documentElement.getAttribute('data-st-theme') || 'light'
278
- let current = themes.indexOf(initial)
279
- if (current === -1) current = 0
280
- ```
281
-
282
- To include your own custom themes in the cycle, add them to the array:
283
-
284
- ```js
285
- const themes = ['light', 'dark', 'dim', 'brand']
286
- ```
287
-
288
- Any theme in the array must have its CSS variables defined before it can be toggled to:
289
-
290
- ```css
291
- [data-st-theme="brand"] {
292
- --st-primary: #7c3aed;
293
- --st-bg: #0f0f0f;
294
- --st-text: #fafafa;
295
- }
296
- ```
297
-
298
- ### Override CSS variables
299
-
300
- ```css
301
- :root {
302
- --st-primary: #7c3aed;
303
- --st-border-radius: 8px;
304
- --st-duration: 300ms;
305
- }
306
- ```
307
-
308
- ---
309
-
310
- ## Transitions
311
-
312
- Strata builds smooth transitions into every interactive element by default.
313
-
314
- ### Control globally
315
-
316
- ```css
317
- /* Slow all transitions */
318
- :root { --st-duration: 400ms; }
319
-
320
- /* Kill all transitions */
321
- :root { --st-duration: 0ms; }
322
- ```
323
-
324
- ### Control per component
325
-
326
- ```css
327
- .btn-primary { --st-duration: 80ms; }
328
- ```
329
-
330
- ### Transition utilities
331
-
332
- ```html
333
- <div class="transition">
334
- <div class="transition-fast">
335
- <div class="transition-slow">
336
- <div class="transition-none">
337
- <div class="transition-[background-color_0.3s_ease]">
338
- <div class="duration-[400ms]">
339
- <div class="ease-in">
340
- <div class="ease-out">
341
- ```
342
-
343
- ### Reduced motion
344
-
345
- Strata automatically respects `prefers-reduced-motion` — no configuration needed.
346
-
347
- ---
348
-
349
- ## State Management
350
-
351
- States are managed via `data-st-*` attributes. JavaScript sets the attribute, CSS handles the visual change.
352
-
353
- ```html
354
- <!-- Visibility with fade transition -->
355
- <div data-st-visible="true">Visible</div>
356
- <div data-st-visible="false">Hidden (faded out)</div>
357
-
358
- <!-- Collapse with smooth height transition -->
359
- <div data-st-collapsed="false">Expanded</div>
360
- <div data-st-collapsed="true">Collapsed</div>
361
-
362
- <!-- Loading state -->
363
- <button data-st-loading="true">Loading...</button>
364
-
365
- <!-- Disabled state -->
366
- <button data-st-disabled="true">Disabled</button>
367
- ```
368
-
369
- ```js
370
- // Toggle visibility
371
- element.setAttribute('data-st-visible', 'false')
372
-
373
- // Collapse/expand
374
- element.setAttribute('data-st-collapsed', 'true')
375
- ```
376
-
377
- ---
378
-
379
- ## Skeleton Loader
380
-
381
- Skeleton loading shows animated shimmer placeholders while content is fetching — preventing layout shift and giving users instant visual feedback that something is coming.
382
-
383
- Strata's skeleton system is entirely attribute-driven. There are no class names to add. Instead, set `data-st-skeleton` on your elements and use the `Strata.skeleton` JS utility to manage the lifecycle.
384
-
385
- ### Attribute states
386
-
387
- | Value | Meaning |
388
- |---|---|
389
- | `"true"` | Element shimmers (CSS applies animated `::before` overlay) |
390
- | `"false"` | Element revealed (shimmer removed, content shows) |
391
- | `"null"` | JS-managed parent — no overlay on the parent itself, children shimmer individually |
392
-
393
- ### Basic usage
394
-
395
- Mark a container and call `Strata.skeleton.init()` — Strata auto-detects the leaf nodes inside and shimmers them individually.
396
-
397
- ```html
398
- <div class="card" data-st-skeleton="true">
399
- <div class="card-header">
400
- <h3>Card Title</h3>
401
- </div>
402
- <div class="card-body">
403
- <p>Some body text that will load soon.</p>
404
- <button class="btn-primary">Action</button>
405
- </div>
406
- </div>
407
- ```
408
-
409
- ```js
410
- // Initialise — auto-detects leaf nodes inside all [data-st-skeleton="true"] parents
411
- Strata.skeleton.init()
412
-
413
- // Simulate data loading, then reveal
414
- fetchData().then(() => {
415
- Strata.skeleton.reveal()
416
- })
417
- ```
418
-
419
- ### JS API
420
-
421
- ```js
422
- Strata.skeleton.init() // auto-discover all skeleton parents on page
423
- Strata.skeleton.init('.card') // manage specific elements
424
- Strata.skeleton.show('.card') // re-enter skeleton state
425
- Strata.skeleton.reveal('.card') // reveal content (removes shimmer)
426
- Strata.skeleton.toggle('.card') // toggle between skeleton and revealed
427
- Strata.skeleton.revealAt('.card', 0) // reveal one element by index
428
- Strata.skeleton.isSkeleton(el) // returns true if element is currently shimmering
429
- ```
430
-
431
- ### Staggered reveal
432
-
433
- Reveal a list of cards one by one with a delay between each:
434
-
435
- ```js
436
- Strata.skeleton.reveal('.card', { stagger: 150 })
437
- ```
438
-
439
- ### Opt out a child element
440
-
441
- Set `data-st-skeleton="false"` on any child to exclude it from shimmering entirely:
442
-
443
- ```html
444
- <div class="card" data-st-skeleton="true">
445
- <div class="card-header">
446
- <h3>Title</h3>
447
- <span data-st-skeleton="false">Always visible badge</span>
448
- </div>
449
- </div>
450
- ```
451
-
452
- ### Customise the shimmer
453
-
454
- Control the shimmer appearance via CSS variables:
455
-
456
- ```css
457
- :root {
458
- --st-skeleton-base: #e2e8f0; /* bar background colour */
459
- --st-skeleton-shine: #f8fafc; /* highlight colour */
460
- --st-skeleton-duration: 1.5s; /* animation speed */
461
- --st-skeleton-radius: 4px; /* corner rounding on bars */
462
- }
463
- ```
464
-
465
- ### Realistic card example
466
-
467
- A card that shimmers while data loads, then transitions to real content:
468
-
469
- ```html
470
- <div class="card" id="profile-card" data-st-skeleton="true">
471
- <div class="card-header">
472
- <div class="img-wrap">
473
- <img src="" alt="Avatar" id="avatar">
474
- </div>
475
- <h3 id="name"></h3>
476
- </div>
477
- <div class="card-body">
478
- <p id="bio"></p>
479
- <a href="#" id="profile-link" class="btn-primary">View Profile</a>
480
- </div>
481
- </div>
482
-
483
- <script>
484
- Strata.skeleton.init('#profile-card')
485
-
486
- loadUser(42).then(user => {
487
- document.getElementById('avatar').src = user.avatarUrl
488
- document.getElementById('name').textContent = user.name
489
- document.getElementById('bio').textContent = user.bio
490
- document.getElementById('profile-link').href = user.profileUrl
491
-
492
- Strata.skeleton.reveal('#profile-card')
493
- })
494
- </script>
495
- ```
496
-
497
- > **Note on images:** Browsers do not support `::before` on replaced elements (`img`, `video`, `iframe`). Wrap media in a `div` — Strata will shimmer the wrapper instead.
498
-
499
- ---
500
-
501
- ## Custom CSS
502
-
503
- Strata uses CSS `@layer` internally. Any CSS you write outside a layer automatically wins over Strata styles.
504
-
505
- ```css
506
- /* This overrides Strata's .btn-primary — no !important needed */
507
- .btn-primary {
508
- background-color: purple;
509
- border-radius: 0;
510
- }
511
-
512
- /* Only overrides what you specify — other properties stay from Strata */
513
- .card {
514
- border-radius: 16px; /* changed */
515
- /* padding, shadow etc. stay as Strata defined */
516
- }
517
- ```
518
-
519
- ---
520
-
521
- ## JavaScript Integration
522
-
523
- ### Class naming convention
524
-
525
- Classes used in JavaScript carry a `-js` suffix. Classes used in TypeScript carry a `-ts` suffix. This signals to any developer reading the code that the element is touched by a script.
526
-
527
- ```html
528
- <div class="modal-js" id="main-modal-js">
529
- <div class="modal-ts" id="main-modal-ts">
530
- ```
531
-
532
- ### Never toggle classes for state
533
-
534
- ```js
535
- // Wrong — don't do this
536
- element.classList.add('hidden')
537
- element.classList.toggle('active')
538
-
539
- // Right — use data attributes
540
- element.setAttribute('data-st-visible', 'false')
541
- element.setAttribute('data-st-active', 'true')
542
- ```
543
-
544
- ---
545
-
546
- ## Configuration
547
-
548
- ```js
549
- // strata.config.js
550
- module.exports = {
551
- // Files to scan for class names
552
- content: [
553
- './src/**/*.{html,jsx,tsx,vue,astro,svelte}'
554
- ],
555
-
556
- // Input and output paths
557
- input: './strata.css',
558
- output: './dist/strata.output.css',
559
-
560
- // Theme overrides
561
- theme: {
562
- breakpoints: {
563
- '3xl': '1600px' // add custom breakpoints
564
- },
565
- colors: {
566
- primary: '#7c3aed' // override default colors
567
- }
568
- },
569
-
570
- // Include or exclude specific components
571
- components: {
572
- exclude: ['carousel']
573
- }
574
- }
575
- ```
576
-
577
- ---
578
-
579
- ## Breakpoints
580
-
581
- Bootstrap-style — breakpoint embedded inside the class name.
582
-
583
- | Breakpoint | Prefix | Min-width |
584
- |---|---|---|
585
- | Extra small | `xs` | 0px |
586
- | Small | `sm` | 576px |
587
- | Medium | `md` | 768px |
588
- | Large | `lg` | 992px |
589
- | Extra large | `xl` | 1200px |
590
- | Extra extra large | `xxl` | 1400px |
591
-
592
- ```html
593
- <div class="col-12 col-md-6 col-lg-4">
594
- <div class="d-none d-md-block">
595
- <div class="mt-2 mt-md-4 mt-lg-5">
596
- ```
597
-
598
- ---
599
-
600
- ## CSS Variables Reference
601
-
602
- | Variable | Default | Purpose |
603
- |---|---|---|
604
- | `--st-primary` | `#0d6efd` | Primary brand colour |
605
- | `--st-secondary` | `#6c757d` | Secondary colour |
606
- | `--st-success` | `#198754` | Success colour |
607
- | `--st-danger` | `#dc3545` | Danger colour |
608
- | `--st-warning` | `#ffc107` | Warning colour |
609
- | `--st-info` | `#0dcaf0` | Info colour |
610
- | `--st-bg` | `#ffffff` | Page background |
611
- | `--st-text` | `#212529` | Body text |
612
- | `--st-border` | `#dee2e6` | Border colour |
613
- | `--st-border-radius` | `0.375rem` | Default radius |
614
- | `--st-duration` | `200ms` | Transition duration |
615
- | `--st-easing` | `cubic-bezier(0.4,0,0.2,1)` | Transition easing |
616
- | `--st-shadow` | `0 0.5rem 1rem rgba(0,0,0,0.15)` | Default shadow |
617
- | `--st-font-family` | System font stack | Body font |
618
-
619
- ---
620
-
621
- ## Framework Compatibility
622
-
623
- Strata works with any project that can consume a CSS file.
624
-
625
- | Framework | Supported |
626
- |---|---|
627
- | Plain HTML | ✓ |
628
- | React / Next.js | ✓ |
629
- | Vue / Nuxt | ✓ |
630
- | Astro | ✓ |
631
- | Svelte / SvelteKit | ✓ |
632
- | Angular | ✓ |
633
- | PHP / Laravel | ✓ |
634
- | Django / Rails | ✓ |
635
-
636
- ---
637
-
638
- ## Build Tool Integration
639
-
640
- ### Vite
641
-
642
- ```js
643
- // vite.config.js
644
- import { defineConfig } from 'vite'
645
-
646
- export default defineConfig({
647
- css: {
648
- postcss: {
649
- plugins: [require('strata-css')]
650
- }
651
- }
652
- })
653
- ```
654
-
655
- ### Webpack
656
-
657
- ```js
658
- // webpack.config.js
659
- module.exports = {
660
- module: {
661
- rules: [{
662
- test: /\.css$/,
663
- use: ['style-loader', 'css-loader', 'postcss-loader']
664
- }]
665
- }
666
- }
667
- ```
668
-
669
- ### PostCSS
670
-
671
- ```js
672
- // postcss.config.js
673
- module.exports = {
674
- plugins: [
675
- require('strata-css'),
676
- require('autoprefixer')
677
- ]
678
- }
679
- ```
680
-
681
- ---
682
-
683
- ## Roadmap
684
-
685
- ### v1.0 — Current
686
- Full component library, utility system, JIT processing, three-theme system, transition system.
687
-
688
- ### v2.0 — Planned
689
- - Formal plugin API
690
- - VSCode IntelliSense extension
691
- - Strata DevTools browser extension
692
- - Design token pipeline (Figma support)
693
- - Storybook integration
694
-
695
- ---
696
-
697
- ## Acknowledgements
698
-
699
- Strata builds on the shoulders of excellent prior work:
700
-
701
- - **[Bootstrap](https://getbootstrap.com/)** (MIT) — component class naming conventions, breakpoint scale, color palette, and form patterns that Strata's API is compatible with
702
- - **[Tailwind CSS](https://tailwindcss.com/)** (MIT) — the JIT processing concept and arbitrary value syntax (`mt-[24px]`, `bg-[#ff0000]`)
703
- - **[PostCSS](https://postcss.org/)** (MIT) — the build pipeline that powers Strata's `@strata` directive processing
704
-
705
- Strata's component architecture, cascade layer system, `data-st-*` state model, theming engine, and JIT registry are original work.
706
-
707
- ---
708
-
709
- ## Creating a GitHub Release
710
-
711
- The v1.0.0 tag already exists. To publish the GitHub Release from it:
712
-
713
- ```bash
714
- gh release create v1.0.0 \
715
- --title "Strata CSS v1.0.0" \
716
- --notes-file CHANGELOG.md \
717
- --verify-tag
718
- ```
719
-
720
- ---
721
-
722
- ## Contributing
723
-
724
- Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a pull request.
725
-
726
- ---
727
-
728
- ## License
729
-
730
- [MIT](LICENSE) © 2026 Aftab Ibrahim Kazi
1
+ <div align="center">
2
+
3
+ # Strata CSS
4
+
5
+ **A modern CSS framework combining Bootstrap's component architecture with Tailwind's JIT processing.**
6
+
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
8
+ [![Version](https://img.shields.io/badge/version-1.0.0-green.svg)]()
9
+ [![Node](https://img.shields.io/badge/node-%3E%3D18.0.0-brightgreen.svg)]()
10
+ [![npm](https://img.shields.io/badge/npm-strata--css-red.svg)](https://www.npmjs.com/package/strata-css)
11
+ [![css-framework](https://img.shields.io/badge/css--framework-%E2%9C%93-blue.svg)]()
12
+ [![PostCSS plugin](https://img.shields.io/badge/postcss-plugin-orange.svg)]()
13
+ [![JIT](https://img.shields.io/badge/JIT-enabled-green.svg)]()
14
+ [![Themes](https://img.shields.io/badge/themes-light%20%7C%20dark%20%7C%20dim-purple.svg)]()
15
+
16
+ `css-framework` · `tailwindcss` · `bootstrap` · `postcss` · `postcss-plugin` · `jit` · `component-library` · `theming` · `utility-first`
17
+
18
+ [Getting Started](#getting-started) · [Live Demo](#live-demo) · [Components](#components) · [Utilities](#utilities) · [Theming](#theming) · [Configuration](#configuration)
19
+
20
+ </div>
21
+
22
+ ---
23
+
24
+ ## What is Strata?
25
+
26
+ Strata is an open source CSS framework that takes the best from Bootstrap and Tailwind while fixing their biggest pain points.
27
+
28
+ **From Bootstrap** — component-first classes (`btn-primary`, `card`, `navbar`) that work out of the box with zero configuration.
29
+
30
+ **From Tailwind** — JIT post-processing that generates only the CSS you actually use, keeping output lean.
31
+
32
+ **Strata's own contributions:**
33
+ - No `!important` anywhere in framework CSS — `@layer` handles all specificity
34
+ - Custom CSS is fully compatible and always wins automatically
35
+ - Three built-in themes: light, dark, and dim — plus unlimited custom themes
36
+ - Buttery smooth transitions built in by default on all interactive elements
37
+ - State management via `data-st-*` attributes — no class toggling in JavaScript
38
+ - Arbitrary value utilities — `mt-[24px]`, `bg-[#ff0000]`, `w-[347px]`
39
+
40
+ ---
41
+
42
+ ## Benchmarks
43
+
44
+ Strata outperforms Tailwind on every metric in watch mode — the speed developers actually feel on every file save.
45
+
46
+ | Metric | Strata | Tailwind |
47
+ |---|---|---|
48
+ | Cold build average | 1.89ms | 7.21ms |
49
+ | Cold build median | 0.15ms | 4.55ms |
50
+ | Warm rebuild average | 0.14ms | 2.70ms |
51
+ | Warm rebuild p95 | 0.23ms | 6.12ms |
52
+
53
+ Results generated via `npm run benchmark`. See [`benchmark/`](./benchmark/) for the reproducible script.
54
+
55
+ ---
56
+
57
+ ## Live Demo
58
+
59
+ View the interactive component showcase: [aftabibrahimkazi.github.io/strata](https://aftabibrahimkazi.github.io/strata)
60
+
61
+ To view locally: open `docs/index.html` directly in a browser — no build step required.
62
+
63
+ ---
64
+
65
+ ## Getting Started
66
+
67
+ ### Installation
68
+
69
+ ```bash
70
+ npm install strata-css
71
+ ```
72
+
73
+ > **Publishing:** Run `npm publish --dry-run` to verify the package contents, then `npm publish` to release.
74
+
75
+ ### Scaffold a new project
76
+
77
+ ```bash
78
+ npx strata init
79
+ ```
80
+
81
+ This creates:
82
+ ```
83
+ strata.config.js ← configuration
84
+ strata.css ← entry point with @strata directives
85
+ postcss.config.js ← PostCSS setup
86
+ dist/ ← generated CSS output
87
+ ```
88
+
89
+ ### Link the output CSS in your HTML
90
+
91
+ ```html
92
+ <link rel="stylesheet" href="dist/strata.output.css">
93
+ ```
94
+
95
+ ### Set a theme on your HTML element
96
+
97
+ ```html
98
+ <html data-st-theme="light">
99
+ ```
100
+
101
+ ### Run in development
102
+
103
+ ```bash
104
+ npm run dev
105
+ ```
106
+
107
+ ### Build for production
108
+
109
+ ```bash
110
+ npm run build
111
+ ```
112
+
113
+ ---
114
+
115
+ ## How It Works
116
+
117
+ Strata is a PostCSS plugin. It scans your source files for class names and generates only the CSS those classes need — nothing more.
118
+
119
+ ```
120
+ Source files (HTML/JSX/Vue/Astro)
121
+
122
+ Scanner (extracts class names)
123
+
124
+ Registry (O(1) Map lookup)
125
+
126
+ Generator (builds CSS)
127
+
128
+ @layer st-base, st-components, st-utilities
129
+
130
+ Output CSS
131
+ ```
132
+
133
+ Your custom CSS lives outside any layer and automatically wins over Strata styles — no `!important` needed.
134
+
135
+ ---
136
+
137
+ ## Components
138
+
139
+ Components are full Bootstrap-style classes with states baked in. They live in `@layer st-components` so your custom CSS always overrides them.
140
+
141
+ ### Buttons
142
+
143
+ ```html
144
+ <button class="btn-primary">Primary</button>
145
+ <button class="btn-secondary">Secondary</button>
146
+ <button class="btn-success">Success</button>
147
+ <button class="btn-danger">Danger</button>
148
+ <button class="btn-warning">Warning</button>
149
+ <button class="btn-info">Info</button>
150
+ <button class="btn-light">Light</button>
151
+ <button class="btn-dark">Dark</button>
152
+ ```
153
+
154
+ ### Layout
155
+
156
+ ```html
157
+ <div class="container">
158
+ <div class="row">
159
+ <div class="col-md-6 col-lg-4">Column</div>
160
+ <div class="col-md-6 col-lg-8">Column</div>
161
+ </div>
162
+ </div>
163
+ ```
164
+
165
+ ### Cards
166
+
167
+ ```html
168
+ <div class="card">
169
+ <div class="card-header">Header</div>
170
+ <div class="card-body">Body</div>
171
+ <div class="card-footer">Footer</div>
172
+ </div>
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Utilities
178
+
179
+ Utilities follow Bootstrap's naming convention and support arbitrary values via Tailwind-style syntax.
180
+
181
+ ### Spacing
182
+
183
+ ```html
184
+ <!-- Scale values (0-5) -->
185
+ <div class="mt-3 mb-2 px-4 py-1">
186
+ <div class="mx-auto my-3">
187
+
188
+ <!-- Arbitrary values -->
189
+ <div class="mt-[24px] px-[1.5rem]">
190
+
191
+ <!-- Important variants -->
192
+ <div class="!mt-0 !mb-0">
193
+ ```
194
+
195
+ ### Display
196
+
197
+ ```html
198
+ <div class="d-flex">
199
+ <div class="d-none">
200
+ <div class="d-block">
201
+ <div class="d-grid">
202
+
203
+ <!-- Responsive -->
204
+ <div class="d-none d-md-flex">
205
+ ```
206
+
207
+ ### Colours
208
+
209
+ ```html
210
+ <!-- Text -->
211
+ <p class="text-primary">
212
+ <p class="text-[#ff0000]">
213
+
214
+ <!-- Background -->
215
+ <div class="bg-success">
216
+ <div class="bg-[rgba(0,0,0,0.5)]">
217
+ ```
218
+
219
+ ---
220
+
221
+ ## Theming
222
+
223
+ ### Built-in themes
224
+
225
+ ```html
226
+ <html data-st-theme="light"> <!-- default -->
227
+ <html data-st-theme="dark"> <!-- dark mode -->
228
+ <html data-st-theme="dim"> <!-- intermediate -->
229
+ ```
230
+
231
+ ### System preference
232
+
233
+ If no `data-st-theme` is set, Strata automatically follows the user's system preference via `prefers-color-scheme`.
234
+
235
+ ### Custom theme
236
+
237
+ ```css
238
+ [data-st-theme="brand"] {
239
+ --st-primary: #7c3aed;
240
+ --st-bg: #0f0f0f;
241
+ --st-text: #fafafa;
242
+ }
243
+ ```
244
+
245
+ ```html
246
+ <html data-st-theme="brand">
247
+ ```
248
+
249
+ ### Switch theme with JavaScript
250
+
251
+ ```js
252
+ document.documentElement.setAttribute('data-st-theme', 'dark')
253
+ ```
254
+
255
+ ### Theme Toggle
256
+
257
+ Cycle through all built-in themes with a single button — no framework needed.
258
+
259
+ ```html
260
+ <button id="theme-toggle">Toggle Theme</button>
261
+
262
+ <script>
263
+ const themes = ['light', 'dark', 'dim']
264
+ let current = 0
265
+
266
+ document.getElementById('theme-toggle').addEventListener('click', () => {
267
+ current = (current + 1) % themes.length
268
+ document.documentElement.setAttribute('data-st-theme', themes[current])
269
+ })
270
+ </script>
271
+ ```
272
+
273
+ To start from the user's current theme rather than always resetting to `light`, read the attribute first:
274
+
275
+ ```js
276
+ const themes = ['light', 'dark', 'dim']
277
+ const initial = document.documentElement.getAttribute('data-st-theme') || 'light'
278
+ let current = themes.indexOf(initial)
279
+ if (current === -1) current = 0
280
+ ```
281
+
282
+ To include your own custom themes in the cycle, add them to the array:
283
+
284
+ ```js
285
+ const themes = ['light', 'dark', 'dim', 'brand']
286
+ ```
287
+
288
+ Any theme in the array must have its CSS variables defined before it can be toggled to:
289
+
290
+ ```css
291
+ [data-st-theme="brand"] {
292
+ --st-primary: #7c3aed;
293
+ --st-bg: #0f0f0f;
294
+ --st-text: #fafafa;
295
+ }
296
+ ```
297
+
298
+ ### Override CSS variables
299
+
300
+ ```css
301
+ :root {
302
+ --st-primary: #7c3aed;
303
+ --st-border-radius: 8px;
304
+ --st-duration: 300ms;
305
+ }
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Transitions
311
+
312
+ Strata builds smooth transitions into every interactive element by default.
313
+
314
+ ### Control globally
315
+
316
+ ```css
317
+ /* Slow all transitions */
318
+ :root { --st-duration: 400ms; }
319
+
320
+ /* Kill all transitions */
321
+ :root { --st-duration: 0ms; }
322
+ ```
323
+
324
+ ### Control per component
325
+
326
+ ```css
327
+ .btn-primary { --st-duration: 80ms; }
328
+ ```
329
+
330
+ ### Transition utilities
331
+
332
+ ```html
333
+ <div class="transition">
334
+ <div class="transition-fast">
335
+ <div class="transition-slow">
336
+ <div class="transition-none">
337
+ <div class="transition-[background-color_0.3s_ease]">
338
+ <div class="duration-[400ms]">
339
+ <div class="ease-in">
340
+ <div class="ease-out">
341
+ ```
342
+
343
+ ### Reduced motion
344
+
345
+ Strata automatically respects `prefers-reduced-motion` — no configuration needed.
346
+
347
+ ---
348
+
349
+ ## State Management
350
+
351
+ States are managed via `data-st-*` attributes. JavaScript sets the attribute, CSS handles the visual change.
352
+
353
+ ```html
354
+ <!-- Visibility with fade transition -->
355
+ <div data-st-visible="true">Visible</div>
356
+ <div data-st-visible="false">Hidden (faded out)</div>
357
+
358
+ <!-- Collapse with smooth height transition -->
359
+ <div data-st-collapsed="false">Expanded</div>
360
+ <div data-st-collapsed="true">Collapsed</div>
361
+
362
+ <!-- Loading state -->
363
+ <button data-st-loading="true">Loading...</button>
364
+
365
+ <!-- Disabled state -->
366
+ <button data-st-disabled="true">Disabled</button>
367
+ ```
368
+
369
+ ```js
370
+ // Toggle visibility
371
+ element.setAttribute('data-st-visible', 'false')
372
+
373
+ // Collapse/expand
374
+ element.setAttribute('data-st-collapsed', 'true')
375
+ ```
376
+
377
+ ---
378
+
379
+ ## Skeleton Loader
380
+
381
+ Skeleton loading shows animated shimmer placeholders while content is fetching — preventing layout shift and giving users instant visual feedback that something is coming.
382
+
383
+ Strata's skeleton system is entirely attribute-driven. There are no class names to add. Instead, set `data-st-skeleton` on your elements and use the `Strata.skeleton` JS utility to manage the lifecycle.
384
+
385
+ ### Attribute states
386
+
387
+ | Value | Meaning |
388
+ |---|---|
389
+ | `"true"` | Element shimmers (CSS applies animated `::before` overlay) |
390
+ | `"false"` | Element revealed (shimmer removed, content shows) |
391
+ | `"null"` | JS-managed parent — no overlay on the parent itself, children shimmer individually |
392
+
393
+ ### Basic usage
394
+
395
+ Mark a container and call `Strata.skeleton.init()` — Strata auto-detects the leaf nodes inside and shimmers them individually.
396
+
397
+ ```html
398
+ <div class="card" data-st-skeleton="true">
399
+ <div class="card-header">
400
+ <h3>Card Title</h3>
401
+ </div>
402
+ <div class="card-body">
403
+ <p>Some body text that will load soon.</p>
404
+ <button class="btn-primary">Action</button>
405
+ </div>
406
+ </div>
407
+ ```
408
+
409
+ ```js
410
+ // Initialise — auto-detects leaf nodes inside all [data-st-skeleton="true"] parents
411
+ Strata.skeleton.init()
412
+
413
+ // Simulate data loading, then reveal
414
+ fetchData().then(() => {
415
+ Strata.skeleton.reveal()
416
+ })
417
+ ```
418
+
419
+ ### JS API
420
+
421
+ ```js
422
+ Strata.skeleton.init() // auto-discover all skeleton parents on page
423
+ Strata.skeleton.init('.card') // manage specific elements
424
+ Strata.skeleton.show('.card') // re-enter skeleton state
425
+ Strata.skeleton.reveal('.card') // reveal content (removes shimmer)
426
+ Strata.skeleton.toggle('.card') // toggle between skeleton and revealed
427
+ Strata.skeleton.revealAt('.card', 0) // reveal one element by index
428
+ Strata.skeleton.isSkeleton(el) // returns true if element is currently shimmering
429
+ ```
430
+
431
+ ### Staggered reveal
432
+
433
+ Reveal a list of cards one by one with a delay between each:
434
+
435
+ ```js
436
+ Strata.skeleton.reveal('.card', { stagger: 150 })
437
+ ```
438
+
439
+ ### Opt out a child element
440
+
441
+ Set `data-st-skeleton="false"` on any child to exclude it from shimmering entirely:
442
+
443
+ ```html
444
+ <div class="card" data-st-skeleton="true">
445
+ <div class="card-header">
446
+ <h3>Title</h3>
447
+ <span data-st-skeleton="false">Always visible badge</span>
448
+ </div>
449
+ </div>
450
+ ```
451
+
452
+ ### Customise the shimmer
453
+
454
+ Control the shimmer appearance via CSS variables:
455
+
456
+ ```css
457
+ :root {
458
+ --st-skeleton-base: #e2e8f0; /* bar background colour */
459
+ --st-skeleton-shine: #f8fafc; /* highlight colour */
460
+ --st-skeleton-duration: 1.5s; /* animation speed */
461
+ --st-skeleton-radius: 4px; /* corner rounding on bars */
462
+ }
463
+ ```
464
+
465
+ ### Realistic card example
466
+
467
+ A card that shimmers while data loads, then transitions to real content:
468
+
469
+ ```html
470
+ <div class="card" id="profile-card" data-st-skeleton="true">
471
+ <div class="card-header">
472
+ <div class="img-wrap">
473
+ <img src="" alt="Avatar" id="avatar">
474
+ </div>
475
+ <h3 id="name"></h3>
476
+ </div>
477
+ <div class="card-body">
478
+ <p id="bio"></p>
479
+ <a href="#" id="profile-link" class="btn-primary">View Profile</a>
480
+ </div>
481
+ </div>
482
+
483
+ <script>
484
+ Strata.skeleton.init('#profile-card')
485
+
486
+ loadUser(42).then(user => {
487
+ document.getElementById('avatar').src = user.avatarUrl
488
+ document.getElementById('name').textContent = user.name
489
+ document.getElementById('bio').textContent = user.bio
490
+ document.getElementById('profile-link').href = user.profileUrl
491
+
492
+ Strata.skeleton.reveal('#profile-card')
493
+ })
494
+ </script>
495
+ ```
496
+
497
+ > **Note on images:** Browsers do not support `::before` on replaced elements (`img`, `video`, `iframe`). Wrap media in a `div` — Strata will shimmer the wrapper instead.
498
+
499
+ ---
500
+
501
+ ## Custom CSS
502
+
503
+ Strata uses CSS `@layer` internally. Any CSS you write outside a layer automatically wins over Strata styles.
504
+
505
+ ```css
506
+ /* This overrides Strata's .btn-primary — no !important needed */
507
+ .btn-primary {
508
+ background-color: purple;
509
+ border-radius: 0;
510
+ }
511
+
512
+ /* Only overrides what you specify — other properties stay from Strata */
513
+ .card {
514
+ border-radius: 16px; /* changed */
515
+ /* padding, shadow etc. stay as Strata defined */
516
+ }
517
+ ```
518
+
519
+ ---
520
+
521
+ ## JavaScript Integration
522
+
523
+ ### Class naming convention
524
+
525
+ Classes used in JavaScript carry a `-js` suffix. Classes used in TypeScript carry a `-ts` suffix. This signals to any developer reading the code that the element is touched by a script.
526
+
527
+ ```html
528
+ <div class="modal-js" id="main-modal-js">
529
+ <div class="modal-ts" id="main-modal-ts">
530
+ ```
531
+
532
+ ### Never toggle classes for state
533
+
534
+ ```js
535
+ // Wrong — don't do this
536
+ element.classList.add('hidden')
537
+ element.classList.toggle('active')
538
+
539
+ // Right — use data attributes
540
+ element.setAttribute('data-st-visible', 'false')
541
+ element.setAttribute('data-st-active', 'true')
542
+ ```
543
+
544
+ ---
545
+
546
+ ## Configuration
547
+
548
+ ```js
549
+ // strata.config.js
550
+ module.exports = {
551
+ // Files to scan for class names
552
+ content: [
553
+ './src/**/*.{html,jsx,tsx,vue,astro,svelte}'
554
+ ],
555
+
556
+ // Input and output paths
557
+ input: './strata.css',
558
+ output: './dist/strata.output.css',
559
+
560
+ // Theme overrides
561
+ theme: {
562
+ breakpoints: {
563
+ '3xl': '1600px' // add custom breakpoints
564
+ },
565
+ colors: {
566
+ primary: '#7c3aed' // override default colors
567
+ }
568
+ },
569
+
570
+ // Include or exclude specific components
571
+ components: {
572
+ exclude: ['carousel']
573
+ }
574
+ }
575
+ ```
576
+
577
+ ---
578
+
579
+ ## Breakpoints
580
+
581
+ Bootstrap-style — breakpoint embedded inside the class name.
582
+
583
+ | Breakpoint | Prefix | Min-width |
584
+ |---|---|---|
585
+ | Extra small | `xs` | 0px |
586
+ | Small | `sm` | 576px |
587
+ | Medium | `md` | 768px |
588
+ | Large | `lg` | 992px |
589
+ | Extra large | `xl` | 1200px |
590
+ | Extra extra large | `xxl` | 1400px |
591
+
592
+ ```html
593
+ <div class="col-12 col-md-6 col-lg-4">
594
+ <div class="d-none d-md-block">
595
+ <div class="mt-2 mt-md-4 mt-lg-5">
596
+ ```
597
+
598
+ ---
599
+
600
+ ## CSS Variables Reference
601
+
602
+ | Variable | Default | Purpose |
603
+ |---|---|---|
604
+ | `--st-primary` | `#0d6efd` | Primary brand colour |
605
+ | `--st-secondary` | `#6c757d` | Secondary colour |
606
+ | `--st-success` | `#198754` | Success colour |
607
+ | `--st-danger` | `#dc3545` | Danger colour |
608
+ | `--st-warning` | `#ffc107` | Warning colour |
609
+ | `--st-info` | `#0dcaf0` | Info colour |
610
+ | `--st-bg` | `#ffffff` | Page background |
611
+ | `--st-text` | `#212529` | Body text |
612
+ | `--st-border` | `#dee2e6` | Border colour |
613
+ | `--st-border-radius` | `0.375rem` | Default radius |
614
+ | `--st-duration` | `200ms` | Transition duration |
615
+ | `--st-easing` | `cubic-bezier(0.4,0,0.2,1)` | Transition easing |
616
+ | `--st-shadow` | `0 0.5rem 1rem rgba(0,0,0,0.15)` | Default shadow |
617
+ | `--st-font-family` | System font stack | Body font |
618
+
619
+ ---
620
+
621
+ ## Framework Compatibility
622
+
623
+ Strata works with any project that can consume a CSS file.
624
+
625
+ | Framework | Supported |
626
+ |---|---|
627
+ | Plain HTML | ✓ |
628
+ | React / Next.js | ✓ |
629
+ | Vue / Nuxt | ✓ |
630
+ | Astro | ✓ |
631
+ | Svelte / SvelteKit | ✓ |
632
+ | Angular | ✓ |
633
+ | PHP / Laravel | ✓ |
634
+ | Django / Rails | ✓ |
635
+
636
+ ---
637
+
638
+ ## Build Tool Integration
639
+
640
+ ### Vite
641
+
642
+ ```js
643
+ // vite.config.js
644
+ import { defineConfig } from 'vite'
645
+
646
+ export default defineConfig({
647
+ css: {
648
+ postcss: {
649
+ plugins: [require('strata-css')]
650
+ }
651
+ }
652
+ })
653
+ ```
654
+
655
+ ### Webpack
656
+
657
+ ```js
658
+ // webpack.config.js
659
+ module.exports = {
660
+ module: {
661
+ rules: [{
662
+ test: /\.css$/,
663
+ use: ['style-loader', 'css-loader', 'postcss-loader']
664
+ }]
665
+ }
666
+ }
667
+ ```
668
+
669
+ ### PostCSS
670
+
671
+ ```js
672
+ // postcss.config.js
673
+ module.exports = {
674
+ plugins: [
675
+ require('strata-css'),
676
+ require('autoprefixer')
677
+ ]
678
+ }
679
+ ```
680
+
681
+ ---
682
+
683
+ ## Roadmap
684
+
685
+ ### v1.0 — Current
686
+ Full component library, utility system, JIT processing, three-theme system, transition system.
687
+
688
+ ### v2.0 — Planned
689
+ - Formal plugin API
690
+ - VSCode IntelliSense extension
691
+ - Strata DevTools browser extension
692
+ - Design token pipeline (Figma support)
693
+ - Storybook integration
694
+
695
+ ---
696
+
697
+ ## Acknowledgements
698
+
699
+ Strata builds on the shoulders of excellent prior work:
700
+
701
+ - **[Bootstrap](https://getbootstrap.com/)** (MIT) — component class naming conventions, breakpoint scale, color palette, and form patterns that Strata's API is compatible with
702
+ - **[Tailwind CSS](https://tailwindcss.com/)** (MIT) — the JIT processing concept and arbitrary value syntax (`mt-[24px]`, `bg-[#ff0000]`)
703
+ - **[PostCSS](https://postcss.org/)** (MIT) — the build pipeline that powers Strata's `@strata` directive processing
704
+
705
+ Strata's component architecture, cascade layer system, `data-st-*` state model, theming engine, and JIT registry are original work.
706
+
707
+ ---
708
+
709
+ ## Creating a GitHub Release
710
+
711
+ The v1.0.0 tag already exists. To publish the GitHub Release from it:
712
+
713
+ ```bash
714
+ gh release create v1.0.0 \
715
+ --title "Strata CSS v1.0.0" \
716
+ --notes-file CHANGELOG.md \
717
+ --verify-tag
718
+ ```
719
+
720
+ ---
721
+
722
+ ## Contributing
723
+
724
+ Contributions are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) before submitting a pull request.
725
+
726
+ ---
727
+
728
+ ## License
729
+
730
+ [MIT](LICENSE) © 2026 Aftab Ibrahim Kazi