@sparkstone/css

A lightweight SCSS framework in the spirit of Pico.css, rebuilt on oklch() relative color syntax. Give it one base color and it derives an entire light and dark palette that clears WCAG AA on every pairing the framework uses.

npm · GitHub

What you get

Install

# pnpm
pnpm add @sparkstone/css

# yarn
yarn add @sparkstone/css

# npm
npm install @sparkstone/css

Then import either the source or the precompiled stylesheet:

// SCSS, if you want the functions and mixins
@use "@sparkstone/css/src/theme.scss";

// or the precompiled CSS
import "@sparkstone/css/theme.css";

A complete page

This is the whole thing. No wrapper classes beyond .container.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="theme.css" />
    <style>
      :root {
        --color: teal;
      }
    </style>
  </head>
  <body>
    <main class="container">
      <h1>Hello</h1>
      <p>Body copy, and <a href="#">a link</a>.</p>

      <article class="card">
        <h2>A card</h2>
        <p>Cards are just articles.</p>
        <footer>
          <button class="secondary">Cancel</button>
          <button>Confirm</button>
        </footer>
      </article>
    </main>
  </body>
</html>

Theming

Three colors drive everything. Set them anywhere a CSS variable can be set.

:root {
  --color: rebeccapurple;
  --accent-color: oklch(from var(--color) l c calc(h + 180));
  --error-color: maroon;
}

Because they are plain CSS variables, you can rebind --color on a subtree and every descendant recolors itself. See Colors.

Light and dark

The scheme follows prefers-color-scheme by default. Force it with an attribute on any element, not just <html>:

<html data-color-scheme="light">
<html data-color-scheme="dark">

Live preview

Change these and every page on this site updates. Values persist for the session.

Browser support

The framework leans on relative color syntax, oklch(from ...). That means Chrome 119+, Safari 16.4+, and Firefox 128+. There is no fallback layer, by design.