Concepts
The ideas keel is built on. Everything else in these docs assumes them; nothing else re-explains them.
Five layers, one job each
keel is one stylesheet organized as five native cascade layers, declared once at the top of the file:
@layer tokens, base, layout, components, utilities;
Each layer has exactly one job. tokens is the only place visual decisions live. base styles semantic HTML so classless content already looks designed. layout arranges — full-bleed bands, containers, structural classes, never positional. components are thin classes that consume tokens. utilities is a small, token-bound escape hatch, deliberately last.
Because every keel rule is layered and your CSS is not,
your CSS always wins. Unlayered styles beat
layered ones regardless of specificity — no
!important, no selector arms races, structurally.
Overriding keel is just writing CSS.
Design-system-first
Most frameworks give you their look and a way to override it. keel inverts that: the tokens layer is the product, and the defaults you see are just its starting values. Seed a system from your brand on the design system page — a color, a mood, a font pairing — and every token derives from the seed by math: neutrals, surfaces, status colors, spacing density, corner radius.
The same seed → derive principle runs inside the stylesheet.
Shades are relationships, not swatches: strong, light,
soft, and the transparencies are all color-mix()
expressions over the seed, so re-theming is often two lines:
@layer tokens {
:root { --k-accent: hsl(160 84% 32%); }
}
Override --k-accent alone and every derived
variant follows. Only --k-on-accent stays explicit —
contrast is a judgment the math can't make safely. The full map
is on the tokens page.
Fluid by default
Type and section spacing are clamp() expressions
that breathe with the viewport — every text step and the larger
space steps interpolate smoothly between a phone floor and a
desktop ceiling, with no breakpoint declarations at all.
Where layout genuinely has to snap — columns collapsing,
a sidebar stacking — keel uses three fixed, documented
breakpoints: sm 640px, md 820px,
lg 1080px. They are not tokens because they cannot
be: media queries can't read custom properties, so pretending
otherwise would be a lie in the API. Three honest constants
instead.
Zero JavaScript
keel ships no scripts, because the platform already ships the
behavior: <dialog> for modals and drawers,
popover for overlays, <details>
for accordions and dropdowns. keel styles these natives; it does
not reinvent them.
When you need more, climb the ladder one rung at a time:
- Semantic HTML first. Links, forms,
details,dialog,popover— most interactivity is already in the parser. - Then CSS. States, tooltips, the scroll-snap gallery, scroll-driven reveals — presentation logic stays in the stylesheet.
- Then a few lines of your own JS. Tab panels, a live filter — small, owned by you, styled by keel.
- Then a framework, if the app earns it. keel still styles the output; the framework handles the runtime.
The design-system tool and the search on this site are site JavaScript, not framework JavaScript.
The grammar
Everything in keel is written in one grammar, and anything you
add should be too. Names are BEM with a prefix:
k-block__element--modifier. Values are tokens, never
raw numbers — if a value matters, it has a name in the tokens
layer. And every component reads local knobs
with token defaults, so a custom variant is plain CSS:
.btn-sale {
--k-btn-bg: var(--k-warn);
--k-btn-bg-hover: color-mix(in oklab, var(--k-warn), black 15%);
}
That is keel's mixin system — native custom properties, no build step, no plugin API. The components page ends with a worked recipe for building a new component in the same grammar.
Semantics & SEO
Stylesheets are invisible to search engines — but a CSS
framework decides what HTML people write, and that is
SEO. keel's base layer only rewards real elements: an
<h1>, a <p>, a
<table>, a <details> look
designed with zero classes, so semantic markup is the path of
least resistance instead of an afterthought. Semantic HTML is
keel's API.
The performance half is structural too: one small file, no
JavaScript runtime, no hydration shift, lazy self-hosted fonts
with font-display: swap — the things Core Web
Vitals measure. And clean, semantic, static HTML is what
generative engines read best, so the same choices serve GEO.
What a stylesheet honestly cannot do: meta and OG tags, sitemaps, structured data, content. keel owns semantics and performance; the rest of the SEO machinery belongs to the tool that builds the pages.
How keel compares
keel is plain to use — one file, no build — but
modern underneath. It leans on native platform features
(@layer, color-mix(), :has(),
the popover API, scroll-driven animation, field-sizing)
that the established frameworks were built before. "Plain"
describes how you ship it, not how old the CSS is.
| keel | Tailwind | Bootstrap | Bulma | |
|---|---|---|---|---|
| Build step to use | None | Required | Optional (Sass) | Optional (Sass) |
| Framework JavaScript | None | None | Ships JS | None |
| Theming | Native tokens, live | Config + rebuild | Sass rebuild | Sass rebuild |
| Styles semantic HTML | Yes — the base layer | No | Partly | Partly |
| Contrast enforced in code | Yes — WCAG AA | No | No | No |
| Design-system generator | Yes | No | No | No |
| Made for AI tools | MCP + llms.txt | No | No | No |
The honest trade: keel's floor is evergreen browsers from 2022
(it needs @layer, with no legacy fallback). Bootstrap
reaches further back. keel's bet is the opposite of legacy support
— use the platform as it is now.
And where each one wins, plainly: Tailwind for a utility-first workflow and a huge ecosystem; Bootstrap for broad legacy support and batteries-included JS components; keel for a real design system, accessible by default, with no toolchain — usable by a person or an AI.
Honest limits
- Not 1.0 yet. Class names and tokens may still tighten before 1.0; changes land in the changelog, not as surprises.
- Browser floor:
@layer. Every major browser since 2022. The layer model is the architecture, not an enhancement. - No tab-panel runtime.
.k-tabsis the visual bar; switching panels is separate pages, a details accordion, or three lines of your JS. - Refused on purpose: arbitrary utility values, responsive prefix systems, a JavaScript runtime, vendored icons-as-requests, and theming by override. Each one would trade the design system for convenience.