Appearance
CSS Layers
remCSS uses @layer to create a deterministic, predictable cascade — without !important.
The Layer Order
Declared once, at the top of src/remcss.css, never changed:
css
@layer base, components, utilities;Layers listed later win over layers listed earlier. The order means:
| Layer | Wins over | Loses to |
|---|---|---|
base | Browser defaults | components, utilities |
components | base | utilities |
utilities | base, components | — |
Why This Matters
Without layers, specificity wars force you to write !important or invent elaborate selectors. With layers, you always know who wins — it's the layer order, not specificity.
css
/* Without layers — this .button rule loses to a 3-part selector elsewhere */
.button {
color: red;
}
nav .site-header .button {
color: blue;
} /* wins */
/* With layers — utilities always win regardless of selector complexity */
@layer utilities {
.text-danger {
color: var(--color-danger);
} /* always wins over components */
}What Goes in Each Layer
@layer base
- CSS reset (box model, margin/padding reset, reduced motion)
- Root font-size calibration (
html { font-size: 62.5% }) - All
:rootcustom properties (tokens for scale, color, typography) - Font stack declarations
- Heading size defaults
No component-specific rules belong here.
@layer components
.button,.button-group.form,.field,.label,.input.table,.table-wrapper.grid,.stack,.cluster,.sidebar- Every rule is scoped with
@scope(progressive enhancement)
@layer utilities
.m-*,.p-*,.px-*,.py-*,.mt-*— spacing.flex,.flex-col,.items-center,.gap-*— flexbox.grid-auto,.grid-sidebar— grid helpers
Utilities are intentionally single-purpose and override everything else in the cascade.
@scope Inside Components
All component rules are wrapped in @scope for additional isolation:
css
/* Fallback for browsers without @scope */
.button {
padding-block: var(--step-n1);
padding-inline: var(--step-1);
}
/* Progressive enhancement */
@supports selector(:scope) {
@scope (.button) {
:scope {
padding-block: var(--step-n1);
padding-inline: var(--step-1);
}
}
}@scope prevents styles from leaking out of the component root. A .button inside a .card cannot accidentally affect a .button outside of it.
Unlayered Tokens
CSS custom properties (tokens) are declared on :root outside of any layer. This is intentional — custom properties must resolve before any layer rule references them. CSSOM processes unlayered rules first, making them always available.
css
/* Tokens — no @layer, always resolve first */
:root {
--step-1: calc(1rem * 1.618);
--color-accent: oklch(62% 0.22 27);
}
/* Components can safely reference them */
@layer components {
.button {
background: var(--color-accent); /* resolves correctly */
}
}