aegis-css
v1.0.0
Published
A future-proof, layered CSS framework built on native CSS primitives. Five progressive layers — classless defaults, design tokens, utility classes, semantic components, and ejectable source ownership — all orchestrated through cascade layers, container qu
Maintainers
Readme
⬡ AEGIS CSS Framework
A future-proof, layered CSS framework built entirely on native CSS primitives.
"The ultimate goal is to make itself unnecessary — teaching developers native CSS while providing the ergonomics they need today."
Overview
AEGIS (Adaptive Ergonomic Generation of Intelligent Styles) is a modern CSS framework designed around the blueprint for a future-proof framework. It combines the best ideas from Tailwind CSS, Bootstrap, Pico CSS, Open Props, DaisyUI, and shadcn/ui into a single, layered architecture.
Key Principles
- Native CSS first — Built on cascade layers, container queries, CSS nesting, OKLCH colors, and
:has(). - Zero JavaScript runtime — CSS-only by default; JS is opt-in for interactive components.
- Layered & modular — Use only what you need, from classless defaults to full component library.
- AI-friendly — Predictable, systematic naming for AI code generation tools.
- Design-system-first — All values are design tokens (CSS custom properties).
- Sub-10 KB target — Zero unused styles with on-demand architecture.
Architecture — Five Layers
AEGIS uses CSS @layer to establish a strict cascade order. Each layer is independently opt-in.
| Layer | Name | Description | Inspired By | |-------|------|-------------|-------------| | 0 | Base | Classless semantic defaults — just include the CSS and your HTML looks great | Pico CSS | | 1 | Tokens | Design tokens as CSS custom properties — spacing, colors, typography, shadows | Open Props | | 2 | Utilities | Atomic utility classes for layout, spacing, typography, colors, etc. | Tailwind CSS | | 3 | Components | Pre-built, semantic UI components — buttons, cards, modals, forms | DaisyUI, Bootstrap | | 4 | Eject | Copy-paste component ownership — eject any component into your codebase | shadcn/ui |
Cascade priority (lowest → highest):
aegis.tokens → aegis.reset → aegis.base → aegis.utilities → aegis.components → aegis.animations → aegis.overridesQuick Start
CDN (No Build Step)
<link rel="stylesheet" href="path/to/dist/aegis.min.css">
<script type="module" src="path/to/dist/aegis.min.js"></script>NPM
npm install aegis-css/* Import everything */
@import "aegis-css";
/* Or import selectively */
@import "aegis-css/css/core"; /* Layer 0 + 1 */
@import "aegis-css/css/utilities"; /* Layer 2 */
@import "aegis-css/css/components"; /* Layer 3 */Build from Source
npm install
npm run build # Full build (CSS + JS)
npm run build:css # CSS only
npm run build:js # JS only
npm run dev # Watch mode
npm run size # Bundle size report
npm run lint # Lint CSS for issuesDirectory Structure
aegis-css/
├── src/
│ ├── index.css ← Main entry point
│ ├── layers.css ← @layer cascade order
│ ├── core/
│ │ ├── index.css
│ │ ├── reset.css ← Modern CSS reset
│ │ ├── tokens.css ← Design tokens (Layer 1)
│ │ ├── base.css ← Classless defaults (Layer 0)
│ │ └── themes/
│ │ ├── light.css ← Light theme tokens
│ │ ├── dark.css ← Dark theme tokens
│ │ └── index.css
│ ├── utilities/
│ │ ├── index.css
│ │ ├── display.css
│ │ ├── layout.css
│ │ ├── flexbox.css
│ │ ├── grid.css
│ │ ├── spacing.css
│ │ ├── sizing.css
│ │ ├── typography.css
│ │ ├── colors.css
│ │ ├── borders.css
│ │ ├── effects.css
│ │ ├── position.css
│ │ ├── interactivity.css
│ │ ├── responsive.css
│ │ ├── container-queries.css
│ │ ├── accessibility.css
│ │ └── intent.css ← Intent-based utilities
│ ├── components/
│ │ ├── index.css
│ │ ├── button.css ← .btn, .btn-primary, etc.
│ │ ├── card.css ← .card, .card-hoverable
│ │ ├── modal.css ← .modal (native <dialog>)
│ │ ├── navbar.css ← .navbar
│ │ ├── form.css ← .input, .form-group
│ │ ├── table.css ← .table, .table-striped
│ │ ├── alert.css ← .alert, .alert-success
│ │ ├── badge.css ← .badge, .badge-dot
│ │ ├── tabs.css ← .tabs, .tab
│ │ ├── dropdown.css ← .dropdown
│ │ ├── tooltip.css ← .tooltip
│ │ ├── accordion.css ← .accordion
│ │ ├── breadcrumb.css ← .breadcrumb
│ │ ├── pagination.css ← .pagination
│ │ ├── avatar.css ← .avatar, .avatar-group
│ │ ├── progress.css ← .progress
│ │ ├── skeleton.css ← .skeleton
│ │ ├── dialog.css ← .dialog (confirms/alerts)
│ │ ├── toast.css ← .toast
│ │ ├── toggle.css ← .toggle (switch)
│ │ ├── chip.css ← .chip (tag)
│ │ ├── divider.css ← .divider
│ │ ├── drawer.css ← .drawer (off-canvas)
│ │ └── popover.css ← .popover
│ └── animations/
│ └── index.css ← Fade, slide, scale, spin, etc.
├── js/
│ ├── index.js ← Main JS entry (auto-init)
│ ├── core/
│ │ ├── dom.js ← $, $$, createElement
│ │ └── events.js ← delegate, emit, debounce
│ ├── components/
│ │ ├── modal.js ← initModals()
│ │ ├── dropdown.js ← initDropdowns()
│ │ ├── accordion.js ← initAccordions()
│ │ ├── tabs.js ← initTabs()
│ │ ├── toast.js ← showToast()
│ │ ├── tooltip.js ← initTooltips()
│ │ ├── dialog.js ← showAlert(), showConfirm()
│ │ └── drawer.js ← initDrawers()
│ └── utilities/
│ ├── theme-switcher.js ← toggleTheme(), setTheme()
│ ├── responsive.js ← matchBreakpoint()
│ └── accessibility.js ← trapFocus(), announce()
├── eject/
│ └── components/ ← Standalone component copies
├── dist/ ← Build output
├── examples/
│ └── index.html ← Kitchen sink demo
├── scripts/
│ ├── build.js ← Full build
│ ├── build-css.js ← Lightning CSS bundler
│ ├── build-js.js ← esbuild bundler
│ ├── dev.js ← Watch mode
│ ├── lint.js ← CSS linter
│ └── size-report.js ← Bundle size reporter
├── package.json
├── vite.config.js ← Vite integration
├── postcss.config.js ← PostCSS fallback
└── README.mdDesign Tokens
All design decisions are expressed as CSS custom properties, following the W3C Design Token Community Group conventions.
Spacing (4px grid)
| Token | Value | Pixels |
|-------|-------|--------|
| --space-1 | 0.25rem | 4px |
| --space-2 | 0.5rem | 8px |
| --space-3 | 0.75rem | 12px |
| --space-4 | 1rem | 16px |
| --space-6 | 1.5rem | 24px |
| --space-8 | 2rem | 32px |
| --space-12 | 3rem | 48px |
| --space-16 | 4rem | 64px |
Typography (Modular Scale, 1.25 ratio)
| Token | Range |
|-------|-------|
| --text-xs | 0.69–0.78rem |
| --text-sm | 0.83–0.98rem |
| --text-base | 1–1.22rem |
| --text-lg | 1.44–1.91rem |
| --text-2xl | 2.07–2.98rem |
| --text-4xl | 2.99–4.66rem |
All type sizes use clamp() for fluid scaling between viewports.
Colors (OKLCH)
All colors use OKLCH for perceptually uniform color spaces. Light and dark themes swap token values automatically via @media (prefers-color-scheme) or data-theme="dark".
Shadows (Elevation)
| Token | Use |
|-------|-----|
| --shadow-1 | Subtle lift |
| --shadow-2 | Cards |
| --shadow-3 | Dropdowns |
| --shadow-4 | Modals |
| --shadow-5 | Overlays |
Theming
Automatic (System Preference)
AEGIS respects prefers-color-scheme automatically. No configuration needed.
Manual Toggle
<button onclick="import('./js/utilities/theme-switcher.js').then(m => m.toggleTheme())">
Toggle Theme
</button>Custom Theme
Create a new theme by overriding tokens:
[data-theme="brand"] {
--color-primary-500: oklch(0.6 0.2 30); /* Warm orange */
--color-bg: oklch(0.99 0.005 30);
/* ... override any token ... */
}Utility Classes
Layout
container, container-sm…container-2xl, overflow-*, aspect-*, object-*
Flexbox
flex, flex-col, flex-wrap, items-center, justify-between, gap-*, flex-center, stack, cluster
Grid
grid, grid-cols-1…grid-cols-12, grid-auto-fit, grid-auto-fill, col-span-*, gap-*, subgrid-*
Spacing
m-*, mx-*, my-*, mt-*…me-*, p-*, px-*, py-*…pe-*, space-y-*, space-x-*
Typography
text-xs…text-4xl, font-sans/serif/mono, font-thin…font-black, leading-*, tracking-*, text-center, truncate, line-clamp-*, text-balance, text-pretty
Colors
text-default, text-primary, text-success…, bg-default, bg-primary, bg-surface-*…, opacity-*
Borders
border, border-*, rounded-*, divide-*, ring-*
Effects
shadow-1…shadow-5, backdrop-blur-*, transition-*, duration-*, ease-*, scale-*, rotate-*
Position
static, relative, absolute, fixed, sticky, z-*, inset-*, top-*, bottom-*, start-*, end-*
Responsive Prefixes
sm:, md:, lg:, xl: — Apply utilities at specific breakpoints.
<div class="flex-col md:flex-row gap-4 md:gap-8">Container Queries
cq-container, cq-name-*, cq-sm:*, cq-md:*, cq-lg:* — Apply styles based on parent container width.
<div class="cq-container">
<div class="flex-col cq-md:flex-row">Adapts to container, not viewport</div>
</div>Intent-Based Utilities
A novel feature: express intent instead of exact values.
<div data-spacing="comfortable">…</div>
<div data-density="compact">…</div>
<article data-reading="long-form">…</article>
<div data-elevation="floating">…</div>
<span data-weight="emphasis">…</span>Components
Button
<button class="btn">Default</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-outline">Outline</button>
<button class="btn btn-ghost">Ghost</button>
<button class="btn btn-danger">Danger</button>
<button class="btn btn-success">Success</button>
<button class="btn btn-lg btn-pill">Large Pill</button>
<button class="btn btn-icon" aria-label="Settings">⚙</button>Card
<div class="card card-hoverable">
<div class="card-media"><img src="…" alt="…"></div>
<div class="card-body">
<h3 class="card-title">Title</h3>
<p class="card-description">Description</p>
</div>
<div class="card-footer"><button class="btn btn-sm">Action</button></div>
</div>Modal (Native <dialog>)
<button class="btn" data-modal-open="#my-modal">Open Modal</button>
<dialog id="my-modal" class="modal">
<div class="modal-header">
<h3 class="modal-title">Modal Title</h3>
<button class="modal-close" data-modal-close aria-label="Close">✕</button>
</div>
<div class="modal-body">Content here</div>
<div class="modal-footer">
<button class="btn btn-outline" data-modal-close>Cancel</button>
<button class="btn">Save</button>
</div>
</dialog>Tabs
<div role="tablist" class="tabs">
<button class="tab" role="tab" aria-selected="true" aria-controls="p1">Tab 1</button>
<button class="tab" role="tab" aria-selected="false" aria-controls="p2">Tab 2</button>
</div>
<div id="p1" class="tab-panel" role="tabpanel">Panel 1</div>
<div id="p2" class="tab-panel" role="tabpanel" hidden>Panel 2</div>Toast (Programmatic)
import { showToast } from "aegis-css/js/components/toast.js";
showToast({
title: "Success!",
message: "File uploaded.",
variant: "success", // success | warning | danger | info
duration: 4000, // ms, 0 = persistent
position: "bottom-end"
});Dialog (Programmatic Confirm)
import { showConfirm } from "aegis-css/js/components/dialog.js";
const ok = await showConfirm({
title: "Delete item?",
message: "This cannot be undone.",
confirmText: "Delete",
cancelText: "Keep"
});All Components
Accordion, Alert, Avatar, Badge, Breadcrumb, Button, Card, Chip, Dialog, Divider, Drawer, Dropdown, Form (Input, Checkbox, Radio, Select, Textarea), Modal, Navbar, Pagination, Popover, Progress, Skeleton, Table, Tabs, Toast, Toggle, Tooltip.
JavaScript API
All JS uses ES6 arrow-function syntax with one exported function per file. Fully tree-shakeable.
Auto-Initialization
<script type="module" src="aegis-css/js/index.js"></script>
<!-- All interactive components auto-initialize on DOMContentLoaded -->Manual Initialization
import { initModals } from "aegis-css/js/components/modal.js";
import { initTabs } from "aegis-css/js/components/tabs.js";
initModals(document);
initTabs(document);Core Helpers
import { $, $$, createElement } from "aegis-css/js/core/dom.js";
import { delegate, emit, debounce, throttle } from "aegis-css/js/core/events.js";
import { trapFocus, announce } from "aegis-css/js/utilities/accessibility.js";Accessibility
AEGIS is built with accessibility as a structural requirement, not an afterthought:
- ARIA-driven styling — Components use
aria-selected,aria-expanded,aria-current,aria-invalid, andaria-disabledfor state management. - Skip link — Built-in
.skip-linkcomponent. - Focus management —
:focus-visiblestyling,trapFocus()utility. - Screen reader support —
.sr-only,announce()for live regions. - Reduced motion — Respects
prefers-reduced-motion: reduceglobally. - High contrast — Utility classes for
prefers-contrast: more. - Keyboard navigation — Full keyboard support for tabs, dropdowns, accordions.
Build Tool Integration
Lightning CSS (Recommended)
The default build uses Lightning CSS (Rust-based) for microsecond rebuilds:
npm run build:css # Uses scripts/build-css.jsVite
// vite.config.js — already configured
import { defineConfig } from "vite";
export default defineConfig({
css: { transformer: "lightningcss" }
});PostCSS (Fallback)
npx postcss src/index.css -o dist/aegis.min.cssPlain <link> (No Build)
<link rel="stylesheet" href="src/index.css">Works in modern browsers that support @import, CSS nesting, and @layer.
Ejectable Components (Layer 4)
Following the shadcn/ui model, any component can be "ejected" — copied as a standalone file you fully own:
cp eject/components/button.css ./my-project/styles/button.cssModify freely. Ejected components depend only on AEGIS core tokens.
Browser Support
| Feature | Chrome | Firefox | Safari |
|---------|--------|---------|--------|
| CSS Nesting | 120+ | 117+ | 17.2+ |
| Container Queries | 105+ | 110+ | 16+ |
| @layer | 99+ | 97+ | 15.4+ |
| :has() | 105+ | 121+ | 15.4+ |
| OKLCH Colors | 111+ | 113+ | 15.4+ |
| @property | 85+ | 128+ | 15.4+ |
Target: Chrome 120+, Firefox 117+, Safari 17.2+ (covers ~95% of global users).
Contributing
- Fork and clone
npm installnpm run dev(watch mode)- Open
examples/index.htmlin a browser - Make changes, verify visually
npm run lintandnpm run sizebefore committing
License
MIT © AEGIS CSS Framework
