Start
Getting started
Link two files and you are done.
Install and link #
Two files and a fonts folder, no build step needed to use it
Build once with npm run build (or take the files from dist/), then link the stylesheet and the script. Keep the fonts/ folder next to the CSS: JetBrains Mono is self-hosted, so ldcss
never calls Google Fonts.
ldcss needs a current evergreen browser: it uses @layer, :has() and color-mix().
<link rel="stylesheet" href="dist/ldcss.css"> <script src="dist/ldcss-theme.js"></script> <!-- optional, tiny: no theme flash --> <script src="dist/ldcss.js"></script> <!-- end of <body> -->
| Class / attribute | What it does |
|---|---|
| dist/ldcss-theme.js | Optional, 0.3 KB, goes in <head> (blocking). Applies
the theme a visitor chose earlier before the first paint, so there is no flash of the wrong theme.
Without it everything still works; people who chose the opposite of their OS setting just see a
brief flash. |
| dist/ldcss.css, dist/ldcss.min.css | The stylesheet. The .min file is the same rules with
comments and whitespace removed. |
| dist/ldcss.js, dist/ldcss.min.js | Behaviour for every data-ld-* component. Safe to load at the
end of <body>; it also starts a mutation observer so
markup added later is initialised. |
| dist/fonts/ | JetBrains Mono (Latin subset, regular and bold, WOFF) with its OFL license. Must sit beside the CSS file. |
Naming conventions #
Classes for structure, attributes for state and variants
A class says what something is (ld-btn, ld-card). A data-ld-* attribute says
which variant or state it is in (data-ld-variant="primary", data-ld-active="true"). Utilities are single-purpose classes, and any of
them can be prefixed with a breakpoint, a theme or a state.
| Class / attribute | What it does |
|---|---|
| ld-* | Component and utility classes: ld-btn, ld-pad-a-3, ld-grid. |
| data-ld-* | Variants, sizes, state and behaviour: data-ld-variant, data-ld-size, data-ld-active,
data-ld-toggle.
|
| ld-{sm|md|lg|xl}:* | Responsive utilities, from min-width 640 / 960 / 1200 /
1440px. Example: ld-md:d-flex. |
| ld-dark:*, ld-light:* | A small set of theme-specific utilities for one-off flips. |
| ld-hover:*, ld-focus:*, ld-focus-visible:* | State variants of common utilities. Example: ld-hover:bg-raised. |
| --ld-* | Design tokens (custom properties). Override them on :root or
on any container. |
| ld:{component}:{event} | Bubbling CustomEvents. Listen with ldcss.on(); see the JavaScript page. |
Cascade layers #
Why your own CSS always wins
ldcss is split into six cascade layers, lowest priority first: ld.tokens, ld.base, ld.components, ld.utilities, ld.escape, ld.variants. A later
layer beats an earlier one no matter how specific the selectors are, so a utility class always beats a
component rule. CSS you write outside any layer beats all of ldcss, without !important.
One consequence: a shadow utility such as ld-shadow-soft also wins
over a button's :active shadow.
/* your own stylesheet, unlayered: wins over every ldcss layer */
.ld-btn { border-radius: 0; }
/* or put your code in a layer of your own, declared after ld */
@layer ld, app;
@layer app { .ld-card { padding: 2rem; } }
| Class / attribute | What it does |
|---|---|
| @layer ld.tokens, ld.base, ld.components, ld.utilities, ld.escape, ld.variants | Declared at the top of ldcss.css. Component rules live in
ld.components, single-class utilities in ld.utilities, the per-element escape hatches in ld.escape, hover/focus variants in ld.variants.
|
| @layer ld, app; | Put your layered CSS after ld to give it priority. |